import streamlit as st from PIL import Image, ImageColor from io import BytesIO from rembg import remove import os from typing import Tuple from PIL.Image import Image as PILImage from copy import deepcopy class ImageProcessor: def __init__(self, image): self.image = image def remove_background(self): return remove(self.image) @staticmethod def change_background(image, background_alpha: float = 1.0, background_hex: str = "#000000"): """ image: PIL Image (RGBA) matte: PIL Image (grayscale, if 255 it is foreground) background_alpha: float background_hex: string """ img = deepcopy(image) if image.mode != "RGBA": img = img.convert("RGBA") background_color = ImageColor.getrgb(background_hex) background_alpha = int(255 * background_alpha) background = Image.new( "RGBA", img.size, color=background_color + (background_alpha,)) background.paste(img, mask=ImageProcessor.matte) return background @staticmethod def matte(img_input): # Implement matte logic pass class ImageDownloader: @staticmethod def download_button(pil_image, filename: str, fmt: str, label="Download"): if fmt not in ["jpg", "png"]: raise ValueError( "Unknown image format (Available: jpg, png - case sensitive)") pil_format = "JPEG" if fmt == "jpg" else "PNG" file_format = "jpg" if fmt == "jpg" else "png" mime = "image/jpeg" if fmt == "jpg" else "image/png" buf = BytesIO() pil_image.save(buf, format=pil_format) return st.download_button( label=label, data=buf.getvalue(), file_name=f'{filename}.{file_format}', mime=mime, ) class ImageUploader: @staticmethod def upload_image(): return st.file_uploader( label="Upload your photo here", accept_multiple_files=False, type=["png", "jpg", "jpeg"], ) class BackgroundColorSelector: @staticmethod def select_background_color(): return st.selectbox("Choose background color", [ "Transparent (PNG)", "White", "Black", "Green", "Red", "Blue" ]) class App: def __init__(self): self.image_processor = None self.image_uploader = ImageUploader() self.background_selector = BackgroundColorSelector() self.image_downloader = ImageDownloader() self.hexmap = { "Transparent (PNG)": "#000000", "Black": "#000000", "White": "#FFFFFF", "Green": "#22EE22", "Red": "#EE2222", "Blue": "#2222EE", } def run(self): st.title("Simple image editor") st.write( "Simply remove the background of your picture and fill it with a plain color") uploaded_file = self.image_uploader.upload_image() if uploaded_file: self.display_original_photo(uploaded_file) in_mode = self.background_selector.select_background_color() in_submit = st.button("Submit") if in_submit: self.process_and_display_image(uploaded_file, in_mode) def display_original_photo(self, uploaded_file): with st.expander("Original photo", expanded=True): st.image(uploaded_file) def process_and_display_image(self, uploaded_file, in_mode): img_input = Image.open(uploaded_file) self.image_processor = ImageProcessor(img_input) with st.spinner("Magic happening behind the scenes. Please wait..."): alpha = 0.0 if in_mode == "Transparent (PNG)" else 1.0 img_output = self.image_processor.remove_background() # img_output = self.image_processor.change_background( # img_without_bg, alpha, in_mode) with st.expander("Success!", expanded=True): st.image(img_output) uploaded_name = os.path.splitext(uploaded_file.name)[0] self.image_downloader.download_button( pil_image=img_output, filename=uploaded_name, fmt="png" ) if __name__ == "__main__": app = App() app.run()