Pratap2002 commited on
Commit
cdec450
·
verified ·
1 Parent(s): d8a9fb0

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +633 -96
app.py CHANGED
@@ -1,50 +1,102 @@
1
  import streamlit as st
2
- from PIL import Image, ImageDraw, ImageFont
3
  import io
4
- import cv2
5
- import numpy as np
6
- import easyocr
7
  import os
8
- from dotenv import load_dotenv
9
  import requests
 
 
 
 
 
 
 
 
 
10
  import logging
11
 
12
  # Load environment variables
 
13
  load_dotenv()
14
 
15
- # Set up logging
16
- logging.basicConfig(level=logging.DEBUG)
17
- logger = logging.getLogger(__name__)
18
 
19
- # Hugging Face API setup
20
- API_URL = "https://api-inference.huggingface.co/models/black-forest-labs/FLUX.1-schnell"
21
- HF_TOKEN = os.getenv("HF_TOKEN")
22
- headers = {"Authorization": f"Bearer {HF_TOKEN}"}
 
 
23
 
24
- def load_image(image_file):
25
- img = Image.open(image_file)
26
- return img
 
27
 
28
- def detect_text(image):
29
- reader = easyocr.Reader(['en'])
30
- img_array = np.array(image)
31
- results = reader.readtext(img_array)
32
- return [(text, box) for (box, text, _) in results]
33
 
34
- def replace_text_in_image(image, text_to_replace, new_text):
35
- img_array = np.array(image)
36
- for (text, box) in detect_text(image):
37
- if text == text_to_replace:
38
- x, y, w, h = int(box[0][0]), int(box[0][1]), int(box[2][0] - box[0][0]), int(box[2][1] - box[0][1])
39
- mask = np.zeros(img_array.shape[:2], dtype=np.uint8)
40
- cv2.rectangle(mask, (x, y), (x+w, y+h), 255, -1)
41
- img_array = cv2.inpaint(img_array, mask, 3, cv2.INPAINT_TELEA)
42
- image = Image.fromarray(img_array)
43
- draw = ImageDraw.Draw(image)
44
- font = ImageFont.truetype("arial.ttf", 40)
45
- draw.text((x, y), new_text, font=font, fill="#000000")
46
- return image
47
- return Image.fromarray(img_array)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
48
 
49
  def query(payload):
50
  try:
@@ -54,15 +106,7 @@ def query(payload):
54
  logger.debug(f"API response status code: {response.status_code}")
55
  logger.debug(f"API response headers: {response.headers}")
56
 
57
- content_type = response.headers.get('Content-Type', '')
58
- if 'application/json' in content_type:
59
- return response.json()
60
- elif 'image' in content_type:
61
- return response.content
62
- else:
63
- logger.error(f"Unexpected content type: {content_type}")
64
- st.error(f"Unexpected content type: {content_type}")
65
- return None
66
  except requests.exceptions.RequestException as e:
67
  logger.error(f"Request failed: {str(e)}")
68
  st.error(f"Request failed: {str(e)}")
@@ -73,64 +117,106 @@ def increase_image_quality(image, scale_factor):
73
  new_size = (width * scale_factor, height * scale_factor)
74
  return image.resize(new_size, Image.LANCZOS)
75
 
76
- def image_text_replacer():
77
- st.header("Image Text Replacer")
78
-
79
- uploaded_file = st.file_uploader("Choose an image...", type=["jpg", "jpeg", "png"])
80
- if uploaded_file is not None:
81
- image = load_image(uploaded_file)
82
- st.image(image, caption='Uploaded Image', use_column_width=True)
83
-
84
- text_results = detect_text(image)
85
-
86
- st.subheader("Detected Text:")
87
-
88
- edited_image = image.copy()
89
-
90
- for i, (text, box) in enumerate(text_results):
91
- if text.strip(): # Only process non-empty text
92
- st.text(f"{i+1}. {text}")
93
-
94
- new_text = st.text_input(f"Enter new text for '{text}':", value=text, key=f"new_text_{i}")
95
-
96
- if st.button(f"Replace '{text}'", key=f"replace_{i}"):
97
- edited_image = replace_text_in_image(edited_image, text, new_text)
98
- st.image(edited_image, caption='Edited Image', use_column_width=True)
99
-
100
- # Provide download option for the edited image
101
- buf = io.BytesIO()
102
- edited_image.save(buf, format="PNG")
103
- byte_im = buf.getvalue()
104
- st.download_button(
105
- label="Download edited image",
106
- data=byte_im,
107
- file_name="edited_image.png",
108
- mime="image/png"
109
- )
110
-
111
- def poster_generator():
112
- st.header("Generate Poster")
113
- poster_type = st.selectbox("Poster Type", ["Fashion", "Movie", "Event", "Advertisement", "Other"])
114
- prompt = st.text_area("Prompt")
115
- num_images = st.number_input("Number of Images", min_value=1, max_value=5, value=1)
116
  quality_factor = st.number_input("Quality Factor", min_value=1, max_value=4, value=1)
117
 
118
  if st.button("Generate Images"):
119
- if poster_type == "Other":
120
- full_prompt = f"A colorful poster with the following elements: {prompt}"
121
  else:
122
- full_prompt = f"A colorful {poster_type.lower()} poster with the following elements: {prompt}"
123
 
124
  generated_images = []
125
  for i in range(num_images):
126
  with st.spinner(f"Generating image {i+1}..."):
127
  logger.info(f"Generating image {i+1} with prompt: {full_prompt}")
128
- response = query({"inputs": full_prompt})
 
 
129
 
130
- if isinstance(response, bytes):
131
- image = Image.open(io.BytesIO(response))
132
  if quality_factor > 1:
133
  image = increase_image_quality(image, quality_factor)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
134
  generated_images.append(image)
135
  else:
136
  st.error("Failed to generate image")
@@ -150,16 +236,467 @@ def poster_generator():
150
  mime="image/png"
151
  )
152
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
153
  def main():
154
- st.title("Image Processing App")
155
 
156
- app_mode = st.sidebar.selectbox("Choose the app mode",
157
- ["Image Text Replacer", "Poster Generator"])
158
 
159
- if app_mode == "Image Text Replacer":
160
- image_text_replacer()
161
- elif app_mode == "Poster Generator":
162
- poster_generator()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
163
 
164
  if __name__ == "__main__":
165
  main()
 
1
  import streamlit as st
2
+ from PIL import Image
3
  import io
4
+ import base64
5
+ import google.generativeai as genai
 
6
  import os
 
7
  import requests
8
+ import random
9
+ import numpy as np
10
+ import cv2
11
+ from rembg import remove
12
+ import textwrap
13
+ import easyocr
14
+ import pytesseract
15
+ from fontTools.ttLib import TTFont
16
+ from langchain_groq import ChatGroq
17
  import logging
18
 
19
  # Load environment variables
20
+ from dotenv import load_dotenv
21
  load_dotenv()
22
 
23
+ # Configure the generative AI model
24
+ genai.configure(api_key=os.getenv("GOOGLE_API_KEY"))
 
25
 
26
+ generation_config = {
27
+ "temperature": 0,
28
+ "top_p": 1,
29
+ "top_k": 1,
30
+ "max_output_tokens": 2048,
31
+ }
32
 
33
+ model = genai.GenerativeModel(
34
+ model_name="gemini-1.5-pro",
35
+ generation_config=generation_config,
36
+ )
37
 
38
+ API_URL = "https://api-inference.huggingface.co/models/black-forest-labs/FLUX.1-dev"
39
+ headers = {"Authorization": f"Bearer {os.getenv('HF_TOKEN')}"}
 
 
 
40
 
41
+ # Set up Tesseract path
42
+ pytesseract.pytesseract.tesseract_cmd = r'C:\Program Files\Tesseract-OCR\tesseract.exe' # Adjust this path as needed
43
+
44
+ # Set up Groq LLM
45
+ llm = ChatGroq(
46
+ temperature=0.7,
47
+ groq_api_key=os.getenv('GROQ_API_KEY'),
48
+ model_name="llama-3.1-70b-versatile"
49
+ )
50
+
51
+ # Content from agent.py
52
+ def generate_advertisement_prompt(description):
53
+ prompt = f"""
54
+ Based on the following detailed description for an advertisement post, image prompt:
55
+
56
+ Description: "{description}"
57
+
58
+ Generate a detailed image prompt for an AI image generation model, incorporating these elements:
59
+
60
+ 1. Subject: Describe the main subject or product in the advertisement, including its key features and visual characteristics.
61
+
62
+ 2. Composition: Explain how the subject should be positioned within the frame, any specific angles or perspectives to highlight its best features.
63
+
64
+ 3. Background: Detail the setting or environment that complements the subject and reinforces the advertisement's message.
65
+
66
+ 4. Text Elements: text elemeny should be adverticement purpose like based on the description generate adverticement text.
67
+
68
+ 5. Style: Describe the overall visual style, color scheme, and mood that best represents the brand and appeals to the target audience.
69
+
70
+ 6. Additional Elements: List any supporting visual elements, such as logos, icons, or graphics that should be included to enhance the advertisement's impact.
71
+
72
+ 7. Target Audience: Briefly mention the intended audience to ensure the image resonates with them.
73
+
74
+ 8. Think in the basis of adverticment designer and combined all 7 points and make a final prompt.
75
+
76
+ Please provide a cohesive image prompt that incorporates all these elements into a striking, attention-grabbing advertisement poster, based on the given description. The prompt should be detailed enough to generate a compelling and effective advertisement image.
77
+ """
78
+
79
+ response = llm.invoke(prompt)
80
+ return response.content
81
+
82
+ def advertisement_generator():
83
+ st.title("Advertisement Post Generator")
84
+
85
+ post_description = st.text_input("Enter a brief description for your advertisement post:")
86
+
87
+ if st.button("Generate Advertisement Elements"):
88
+ if post_description:
89
+ with st.spinner("Generating advertisement elements..."):
90
+ final_prompt = generate_advertisement_prompt(post_description)
91
+ st.subheader("Generated Advertisement Prompt:")
92
+
93
+ st.text_area(label="Final Prompt", value=final_prompt.strip(), height=200)
94
+ else:
95
+ st.warning("Please enter a description for your advertisement post.")
96
+
97
+ # Content from image_generation.py
98
+ logging.basicConfig(level=logging.DEBUG)
99
+ logger = logging.getLogger(__name__)
100
 
101
  def query(payload):
102
  try:
 
106
  logger.debug(f"API response status code: {response.status_code}")
107
  logger.debug(f"API response headers: {response.headers}")
108
 
109
+ return response.content
 
 
 
 
 
 
 
 
110
  except requests.exceptions.RequestException as e:
111
  logger.error(f"Request failed: {str(e)}")
112
  st.error(f"Request failed: {str(e)}")
 
117
  new_size = (width * scale_factor, height * scale_factor)
118
  return image.resize(new_size, Image.LANCZOS)
119
 
120
+ def generate_poster():
121
+ st.header("Generate Social Media Post")
122
+ post_type = st.selectbox("Select Post Type", ["Instagram advertisement post", "Facebook advertisement post", "Twitter advertisement post", "Other"])
123
+ aspect_ratio = st.selectbox("Select Image Aspect Ratio", ["1:1", "16:9", "4:5", "9:16"])
124
+
125
+ # Add dimension selection based on aspect ratio
126
+ if aspect_ratio == "1:1":
127
+ dimensions = st.selectbox("Select Image Dimensions", ["1080x1080", "1200x1200", "1500x1500"])
128
+ elif aspect_ratio == "16:9":
129
+ dimensions = st.selectbox("Select Image Dimensions", ["1920x1080", "1280x720", "2560x1440"])
130
+ elif aspect_ratio == "4:5":
131
+ dimensions = st.selectbox("Select Image Dimensions", ["1080x1350", "1200x1500", "1600x2000"])
132
+ elif aspect_ratio == "9:16":
133
+ dimensions = st.selectbox("Select Image Dimensions", ["1080x1920", "1350x2400", "1600x2844"])
134
+
135
+ # Extract width and height from the selected dimensions
136
+ width, height = map(int, dimensions.split('x'))
137
+
138
+ design_style = st.selectbox("Select Design Style", [
139
+ "Minimalistic", "Bold/Graphic", "Elegant", "Playful/Fun",
140
+ "Corporate/Professional", "Retro/Vintage", "Modern/Contemporary", "Illustrative/Artistic"
141
+ ])
142
+
143
+ header = st.text_input("Enter Header for Advertisement:")
144
+ placeholder_text = st.text_input("Enter placeholder text:")
145
+ description = st.text_area("Enter Description for Advertisement:")
146
+ logo = st.file_uploader("Upload Logo (optional)", type=['png', 'jpg', 'jpeg'])
147
+
148
+ # Add logo position selection
149
+ logo_position = st.selectbox("Select Logo Position", [
150
+ "Top Left", "Top Middle", "Top Right",
151
+ "Left Middle", "Right Middle",
152
+ "Bottom Left", "Bottom Middle", "Bottom Right"
153
+ ])
154
+
155
+ # Add padding slider
156
+ padding_percent = st.slider("Logo Padding (%)", 1, 10, 2)
157
+
158
+ num_images = st.number_input("Number of Images", min_value=4, max_value=8, value=4)
 
159
  quality_factor = st.number_input("Quality Factor", min_value=1, max_value=4, value=1)
160
 
161
  if st.button("Generate Images"):
162
+ if post_type == "Other":
163
+ full_prompt = f"{header}. A {design_style.lower()} style post with the following elements: {description}, aspect ratio: {aspect_ratio}, dimensions: {width}x{height}, 4k high resolution. Placeholder: {placeholder_text}"
164
  else:
165
+ full_prompt = f"{header}. A {design_style.lower()} style {post_type.lower()} with the following elements: {description}, aspect ratio: {aspect_ratio}, dimensions: {width}x{height}, 4k high resolution. Placeholder: {placeholder_text}"
166
 
167
  generated_images = []
168
  for i in range(num_images):
169
  with st.spinner(f"Generating image {i+1}..."):
170
  logger.info(f"Generating image {i+1} with prompt: {full_prompt}")
171
+ # Add a random seed to ensure different images
172
+ seed = random.randint(1, 1000000)
173
+ image_bytes = query({"inputs": full_prompt, "parameters": {"seed": seed, "width": width, "height": height}})
174
 
175
+ if image_bytes:
176
+ image = Image.open(io.BytesIO(image_bytes))
177
  if quality_factor > 1:
178
  image = increase_image_quality(image, quality_factor)
179
+
180
+ # Add logo to the selected position if provided
181
+ if logo:
182
+ logo_image = Image.open(logo)
183
+ logo_width = int(image.width * 0.15) # 15% of the image width
184
+ logo_height = int(logo_image.height * (logo_width / logo_image.width))
185
+ logo_image = logo_image.resize((logo_width, logo_height), Image.LANCZOS)
186
+
187
+ padding = int(image.width * (padding_percent / 100)) # Convert percentage to pixels
188
+
189
+ # Calculate logo position based on user selection
190
+ if logo_position == "Top Left":
191
+ position = (padding, padding)
192
+ elif logo_position == "Top Middle":
193
+ position = ((image.width - logo_width) // 2, padding)
194
+ elif logo_position == "Top Right":
195
+ position = (image.width - logo_width - padding, padding)
196
+ elif logo_position == "Left Middle":
197
+ position = (padding, (image.height - logo_height) // 2)
198
+ elif logo_position == "Right Middle":
199
+ position = (image.width - logo_width - padding, (image.height - logo_height) // 2)
200
+ elif logo_position == "Bottom Left":
201
+ position = (padding, image.height - logo_height - padding)
202
+ elif logo_position == "Bottom Middle":
203
+ position = ((image.width - logo_width) // 2, image.height - logo_height - padding)
204
+ else: # Bottom Right
205
+ position = (image.width - logo_width - padding, image.height - logo_height - padding)
206
+
207
+ # Create a new image with an alpha channel
208
+ combined_image = Image.new('RGBA', image.size, (0, 0, 0, 0))
209
+ combined_image.paste(image, (0, 0))
210
+
211
+ # Convert logo to RGBA if it's not already
212
+ if logo_image.mode != 'RGBA':
213
+ logo_image = logo_image.convert('RGBA')
214
+
215
+ combined_image.paste(logo_image, position, logo_image)
216
+
217
+ # Convert back to RGB for compatibility
218
+ image = combined_image.convert('RGB')
219
+
220
  generated_images.append(image)
221
  else:
222
  st.error("Failed to generate image")
 
236
  mime="image/png"
237
  )
238
 
239
+ # Content from image_to_image.py
240
+ def encode_image(image):
241
+ buffered = io.BytesIO()
242
+ image.save(buffered, format="PNG")
243
+ return base64.b64encode(buffered.getvalue()).decode('utf-8')
244
+
245
+ def generate_image_prompt(image):
246
+ encoded_image = encode_image(image)
247
+
248
+ prompt_parts = [
249
+ {"mime_type": "image/png", "data": base64.b64decode(encoded_image)},
250
+ "Analyze this image and generate a detailed prompt that could be used to recreate this image using an AI image generation model. Include key visual elements, style, composition, and any other relevant details but do not include any kind of text elements."
251
+ ]
252
+
253
+ response = model.generate_content(prompt_parts)
254
+ return response.text
255
+
256
+ def generate_new_image(prompt):
257
+ # Add a random seed to ensure different images
258
+ seed = random.randint(1, 1000000)
259
+ payload = {
260
+ "inputs": prompt,
261
+ "parameters": {"seed": seed}
262
+ }
263
+ response = requests.post(API_URL, headers=headers, json=payload)
264
+ return Image.open(io.BytesIO(response.content))
265
+
266
+ # Part 2: Image Editing
267
+
268
+ # Content from image_assembled.py
269
+ def load_image(image_file):
270
+ img = Image.open(image_file)
271
+ return img
272
+
273
+ def crop_image(img, left, top, right, bottom):
274
+ return img.crop((left, top, right, bottom))
275
+
276
+ def resize_image(img, max_size):
277
+ width, height = img.size
278
+ if width > height:
279
+ if width > max_size:
280
+ ratio = max_size / width
281
+ new_size = (max_size, int(height * ratio))
282
+ else:
283
+ if height > max_size:
284
+ ratio = max_size / height
285
+ new_size = (int(width * ratio), max_size)
286
+ return img.resize(new_size, Image.LANCZOS)
287
+
288
+ def assemble_images(background, images, positions, sizes):
289
+ canvas = background.copy()
290
+ for img, pos, size in zip(images, positions, sizes):
291
+ resized_img = img.resize(size, Image.LANCZOS)
292
+ canvas.paste(resized_img, pos, resized_img if resized_img.mode == 'RGBA' else None)
293
+ return canvas
294
+
295
+ def drag_and_resize_images(background, images, positions, sizes):
296
+ def on_mouse(event, x, y, flags, param):
297
+ nonlocal dragging, resizing, active_image, offset_x, offset_y, start_size, resize_corner
298
+
299
+ if event == cv2.EVENT_LBUTTONDOWN:
300
+ for i, (image, pos, size) in enumerate(zip(images, positions, sizes)):
301
+ ix, iy = pos
302
+ if ix <= x <= ix + size[0] and iy <= y <= iy + size[1]:
303
+ active_image = i
304
+ offset_x = x - ix
305
+ offset_y = y - iy
306
+ start_size = size
307
+
308
+ # Check if click is near a corner (within 10 pixels)
309
+ corner_size = 10
310
+ if (x - ix < corner_size and y - iy < corner_size) or \
311
+ (ix + size[0] - x < corner_size and y - iy < corner_size) or \
312
+ (x - ix < corner_size and iy + size[1] - y < corner_size) or \
313
+ (ix + size[0] - x < corner_size and iy + size[1] - y < corner_size):
314
+ resizing = True
315
+ resize_corner = (x - ix, y - iy)
316
+ else:
317
+ dragging = True
318
+ break
319
+
320
+ elif event == cv2.EVENT_MOUSEMOVE:
321
+ if dragging:
322
+ positions[active_image] = (x - offset_x, y - offset_y)
323
+ elif resizing:
324
+ dx = x - (positions[active_image][0] + resize_corner[0])
325
+ dy = y - (positions[active_image][1] + resize_corner[1])
326
+
327
+ if resize_corner[0] < start_size[0] / 2:
328
+ dx = -dx
329
+ if resize_corner[1] < start_size[1] / 2:
330
+ dy = -dy
331
+
332
+ new_width = max(10, start_size[0] + dx)
333
+ new_height = max(10, start_size[1] + dy)
334
+ sizes[active_image] = (int(new_width), int(new_height))
335
+
336
+ elif event == cv2.EVENT_LBUTTONUP:
337
+ dragging = False
338
+ resizing = False
339
+
340
+ dragging = False
341
+ resizing = False
342
+ active_image = -1
343
+ offset_x, offset_y = 0, 0
344
+ start_size = (0, 0)
345
+ resize_corner = (0, 0)
346
+
347
+ window_name = "Drag and Resize Images"
348
+ cv2.namedWindow(window_name)
349
+ cv2.setMouseCallback(window_name, on_mouse)
350
+
351
+ while True:
352
+ img_copy = assemble_images(background, images, positions, sizes)
353
+ cv2.imshow(window_name, cv2.cvtColor(np.array(img_copy), cv2.COLOR_RGB2BGR))
354
+ key = cv2.waitKey(1) & 0xFF
355
+ if key == 27: # ESC key
356
+ break
357
+
358
+ cv2.destroyAllWindows()
359
+ return positions, sizes, img_copy
360
+
361
+ # Content from text_replacer.py
362
+ def detect_text(image):
363
+ reader = easyocr.Reader(['en'])
364
+ img_array = np.array(image)
365
+ results = reader.readtext(img_array)
366
+ return [(text, box) for (box, text, _) in results]
367
+
368
+ def get_text_color(image, box):
369
+ x, y = int(box[0][0]), int(box[0][1])
370
+ rgb_image = image.convert('RGB')
371
+ color = rgb_image.getpixel((x, y))
372
+ return color
373
+
374
+ def detect_font(image, box):
375
+ x, y, w, h = int(box[0][0]), int(box[0][1]), int(box[2][0] - box[0][0]), int(box[2][1] - box[0][1])
376
+ cropped = image.crop((x, y, x+w, y+h))
377
+
378
+ # Use Tesseract to detect font
379
+ custom_config = r'--oem 3 --psm 6 -c tessedit_char_whitelist=ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'
380
+ font_info = pytesseract.image_to_data(cropped, config=custom_config, output_type=pytesseract.Output.DICT)
381
+
382
+ # Check if 'font' key exists in font_info
383
+ if 'font' in font_info:
384
+ # Get the most common font
385
+ fonts = [f for f in font_info['font'] if f != '']
386
+ if fonts:
387
+ most_common_font = max(set(fonts), key=fonts.count)
388
+ return most_common_font
389
+
390
+ return "arialbd" # Default to Bold Arial if no font detected or 'font' key not present
391
+
392
+ def replace_text_in_image(image, text_to_replace, new_text, new_color):
393
+ img_array = np.array(image)
394
+ for (text, box) in detect_text(image):
395
+ if text == text_to_replace:
396
+ x, y, w, h = int(box[0][0]), int(box[0][1]), int(box[2][0] - box[0][0]), int(box[2][1] - box[0][1])
397
+
398
+ # Detect the font of the original text
399
+ detected_font = detect_font(image, box)
400
+
401
+ # Create a mask for the text area
402
+ mask = np.zeros(img_array.shape[:2], dtype=np.uint8)
403
+ cv2.rectangle(mask, (x, y), (x+w, y+h), 255, -1)
404
+
405
+ # Inpaint the text area
406
+ img_array = cv2.inpaint(img_array, mask, 3, cv2.INPAINT_TELEA)
407
+
408
+ image = Image.fromarray(img_array)
409
+ draw = ImageDraw.Draw(image)
410
+ font_size = int(h * 0.8)
411
+
412
+ supported_extensions = ['.ttf', '.otf', '.woff', '.woff2']
413
+ font_path = None
414
+ for ext in supported_extensions:
415
+ if os.path.exists(f"{detected_font}{ext}"):
416
+ font_path = f"{detected_font}{ext}"
417
+ break
418
+ if not font_path:
419
+ font_path = "arialbd.ttf" # Default to Bold Arial if no supported font found
420
+
421
+ font = ImageFont.truetype(font_path, font_size)
422
+
423
+ draw.text((x, y), new_text, font=font, fill=new_color)
424
+ return image
425
+
426
+ return Image.fromarray(img_array)
427
+
428
+ # Content from text.py
429
+ def put_text(img, text, x_value, y_value, color):
430
+ if img is None:
431
+ raise ValueError("Image not found or could not be loaded.")
432
+
433
+ font = cv2.FONT_HERSHEY_DUPLEX
434
+ wrapped_text = textwrap.wrap(text, width=30)
435
+ font_size = 1
436
+ font_thickness = 2
437
+
438
+ for i, line in enumerate(wrapped_text):
439
+ textsize = cv2.getTextSize(line, font, font_size, font_thickness)[0]
440
+
441
+ gap = textsize[1] + 10
442
+ y = y_value + i * gap
443
+ x = x_value
444
+ cv2.putText(img, line, (x, y), font,
445
+ font_size,
446
+ color,
447
+ font_thickness,
448
+ lineType = cv2.LINE_AA)
449
+
450
+ def drag_text(img, texts):
451
+ def on_mouse(event, x, y, flags, param):
452
+ nonlocal dragging, active_text, offset_x, offset_y
453
+
454
+ if event == cv2.EVENT_LBUTTONDOWN:
455
+ for i, (text, pos, color) in enumerate(texts):
456
+ tx, ty = pos
457
+ wrapped_text = textwrap.wrap(text, width=30)
458
+ text_height = len(wrapped_text) * 30 # Approximate text height
459
+ text_width = max(cv2.getTextSize(line, cv2.FONT_HERSHEY_DUPLEX, 1, 2)[0][0] for line in wrapped_text)
460
+ if tx <= x <= tx + text_width and ty - 30 <= y <= ty + text_height: # Expanded clickable area
461
+ dragging = True
462
+ active_text = i
463
+ offset_x = x - tx
464
+ offset_y = y - ty
465
+ break
466
+
467
+ elif event == cv2.EVENT_MOUSEMOVE:
468
+ if dragging:
469
+ texts[active_text] = (texts[active_text][0], (x - offset_x, y - offset_y), texts[active_text][2])
470
+
471
+ elif event == cv2.EVENT_LBUTTONUP:
472
+ dragging = False
473
+
474
+ dragging = False
475
+ active_text = -1
476
+ offset_x, offset_y = 0, 0
477
+
478
+ window_name = "Drag Text"
479
+ cv2.namedWindow(window_name)
480
+ cv2.setMouseCallback(window_name, on_mouse)
481
+
482
+ while True:
483
+ img_copy = img.copy()
484
+ for text, (x, y), color in texts:
485
+ put_text(img_copy, text, x, y, color)
486
+
487
+ cv2.imshow(window_name, img_copy)
488
+ key = cv2.waitKey(1) & 0xFF
489
+ if key == 27: # ESC key
490
+ break
491
+
492
+ cv2.destroyAllWindows()
493
+ return texts, img_copy
494
+
495
+ # Content from background_remove.py
496
+ def remove_background(image):
497
+ # Convert PIL Image to numpy array
498
+ img_array = np.array(image)
499
+
500
+ # Remove background
501
+ result = remove(img_array)
502
+
503
+ # Convert back to PIL Image
504
+ return Image.fromarray(result)
505
+
506
+ # Main Streamlit App
507
  def main():
508
+ st.title("Image Generation and Editing App")
509
 
510
+ # Sidebar for navigation
511
+ page = st.sidebar.selectbox("Choose a function", ["Text to Image Generation", "Image Editing", "Poster Generation", "Advertisement Generator"])
512
 
513
+ if page == "Text to Image Generation":
514
+ text_to_image_generation()
515
+ elif page == "Image Editing":
516
+ image_editing()
517
+ elif page == "Poster Generation":
518
+ generate_poster()
519
+ elif page == "Advertisement Generator":
520
+ advertisement_generator()
521
+
522
+ def text_to_image_generation():
523
+ st.header("Text to Image Generation")
524
+
525
+ # Image to Image Generation
526
+ st.subheader("Image to Image Generation")
527
+ uploaded_file = st.file_uploader("Choose an image:", type=["png", "jpg", "jpeg"])
528
+ if uploaded_file is not None:
529
+ image = Image.open(uploaded_file)
530
+ st.image(image, caption="Uploaded Image", use_column_width=True)
531
+
532
+ if st.button("Generate Image Prompt"):
533
+ with st.spinner("Analyzing image and generating prompt..."):
534
+ generated_prompt = generate_image_prompt(image)
535
+ st.subheader("Generated Image Prompt:")
536
+ st.text_area(label="", value=generated_prompt.strip(), height=200, key="generated_prompt", disabled=True)
537
+ st.session_state['saved_prompt'] = generated_prompt.strip()
538
+
539
+ # Add multiple text elements
540
+ st.subheader("Add Text Elements")
541
+ num_text_elements = st.number_input("Number of text elements to add:", min_value=1, max_value=5, value=1)
542
+ text_elements = []
543
+ for i in range(num_text_elements):
544
+ text_element = st.text_input(f"Enter text {i+1} to add to the image:")
545
+ if text_element:
546
+ text_elements.append(f'text on image: "{text_element}"')
547
+ text_element_prompt = ", ".join(text_elements)
548
+
549
+ # User input prompt
550
+ st.subheader("Additional Prompt")
551
+ user_prompt = st.text_input("Enter additional prompt details:")
552
+
553
+ # Combine prompts
554
+ saved_prompt = st.session_state.get('saved_prompt', '')
555
+ final_prompt = f"{saved_prompt}, {text_element_prompt}, {user_prompt}".strip()
556
+
557
+ st.subheader("Final Prompt")
558
+ final_prompt_area = st.text_area("Final prompt for image generation:", value=final_prompt, height=150, key="final_prompt")
559
+
560
+ if st.button("Generate New Images"):
561
+ with st.spinner("Generating new images..."):
562
+ col1, col2 = st.columns(2)
563
+ for i in range(4):
564
+ new_image = generate_new_image(final_prompt_area)
565
+ if i % 2 == 0:
566
+ with col1:
567
+ st.image(new_image, caption=f"Generated Image {i+1}", use_column_width=True)
568
+ else:
569
+ with col2:
570
+ st.image(new_image, caption=f"Generated Image {i+1}", use_column_width=True)
571
+
572
+ def image_editing():
573
+ st.header("Image Editing")
574
+
575
+ # Background Removal
576
+ st.subheader("Background Removal")
577
+ bg_remove_file = st.file_uploader("Choose an image for background removal", type=["jpg", "jpeg", "png"])
578
+ if bg_remove_file is not None:
579
+ image = Image.open(bg_remove_file)
580
+ st.image(image, caption="Original Image", use_column_width=True)
581
+ if st.button("Remove Background"):
582
+ result = remove_background(image)
583
+ st.image(result, caption="Image with Background Removed", use_column_width=True)
584
+ buf = io.BytesIO()
585
+ result.save(buf, format="PNG")
586
+ byte_im = buf.getvalue()
587
+ st.download_button(label="Download Result", data=byte_im, file_name="result.png", mime="image/png")
588
+
589
+ # Image Assembly
590
+ st.subheader("Image Assembly")
591
+ background_file = st.file_uploader("Choose a background image", type=['png', 'jpg', 'jpeg'])
592
+ if background_file:
593
+ background = load_image(background_file)
594
+ background = resize_image(background, 800)
595
+ st.image(background, caption="Background Image", use_column_width=True)
596
+
597
+ uploaded_files = st.file_uploader("Choose foreground images", accept_multiple_files=True, type=['png', 'jpg', 'jpeg'])
598
+ if uploaded_files:
599
+ images = [load_image(file) for file in uploaded_files]
600
+ cropped_images = []
601
+ for i, img in enumerate(images):
602
+ st.subheader(f"Image {i+1}")
603
+ st.image(img, use_column_width=True)
604
+
605
+ st.write(f"Crop image {i+1}")
606
+ col1, col2 = st.columns(2)
607
+ with col1:
608
+ left = st.slider(f"Left crop for image {i+1}", 0, img.width, 0)
609
+ right = st.slider(f"Right crop for image {i+1}", 0, img.width, img.width)
610
+ with col2:
611
+ top = st.slider(f"Top crop for image {i+1}", 0, img.height, 0)
612
+ bottom = st.slider(f"Bottom crop for image {i+1}", 0, img.height, img.height)
613
+
614
+ cropped_img = crop_image(img, left, top, right, bottom)
615
+ resized_img = resize_image(cropped_img, 200)
616
+ cropped_images.append(resized_img)
617
+ st.image(resized_img, caption=f"Cropped and Resized Image {i+1}", use_column_width=True)
618
+
619
+ if 'positions' not in st.session_state:
620
+ st.session_state.positions = [(0, 0) for _ in cropped_images]
621
+ if 'sizes' not in st.session_state:
622
+ st.session_state.sizes = [img.size for img in cropped_images]
623
+
624
+ if st.button("Drag, Resize, and Assemble Images"):
625
+ positions, sizes, assembled_image = drag_and_resize_images(background, cropped_images, st.session_state.positions, st.session_state.sizes)
626
+ st.session_state.positions = positions
627
+ st.session_state.sizes = sizes
628
+ st.image(assembled_image, caption="Assembled Image", use_column_width=True)
629
+
630
+ if st.button("Finalize Assembly"):
631
+ assembled_image = assemble_images(background, cropped_images, st.session_state.positions, st.session_state.sizes)
632
+ st.image(assembled_image, caption="Final Assembled Image", use_column_width=True)
633
+
634
+ buf = io.BytesIO()
635
+ assembled_image.save(buf, format="PNG")
636
+ byte_im = buf.getvalue()
637
+ st.download_button(label="Download Assembled Image", data=byte_im, file_name="assembled_image.png", mime="image/png")
638
+
639
+ # Text Overlay
640
+ st.subheader("Text Overlay")
641
+ text_overlay_file = st.file_uploader("Choose an image for text overlay", type=["jpg", "jpeg", "png"])
642
+ if text_overlay_file is not None:
643
+ image = Image.open(text_overlay_file)
644
+ img_array = np.array(image)
645
+
646
+ st.image(image, caption='Uploaded Image', use_column_width=True)
647
+
648
+ texts = []
649
+ num_texts = st.number_input("Number of text overlays", min_value=1, value=1)
650
+
651
+ for i in range(num_texts):
652
+ text = st.text_area(f"Enter text to overlay #{i+1} (multiple lines supported):")
653
+ x_value = st.slider(f"X position for text #{i+1}", 0, img_array.shape[1], 50)
654
+ y_value = st.slider(f"Y position for text #{i+1}", 0, img_array.shape[0], 50 + i*50)
655
+ color = st.color_picker(f"Choose color for text #{i+1}", '#000000')
656
+ color = tuple(int(color.lstrip('#')[i:i+2], 16) for i in (0, 2, 4))
657
+ texts.append((text, (x_value, y_value), color))
658
+
659
+ if st.button("Add Text and Drag"):
660
+ img_with_text = img_array.copy()
661
+ updated_texts, updated_img = drag_text(img_with_text, texts)
662
+ result_image = Image.fromarray(updated_img)
663
+ st.image(result_image, caption='Image with Dragged Text Overlay', use_column_width=True)
664
+
665
+ buf = io.BytesIO()
666
+ result_image.save(buf, format="PNG")
667
+ st.download_button(label="Download Updated Image", data=buf.getvalue(), file_name="image_with_dragged_text.png", mime="image/png")
668
+
669
+ # Text Replacement
670
+ st.subheader("Text Replacement")
671
+ text_replace_file = st.file_uploader("Choose an image for text replacement", type=["jpg", "jpeg", "png"])
672
+ if text_replace_file is not None:
673
+ image = Image.open(text_replace_file)
674
+ st.image(image, caption='Current Image', use_column_width=True)
675
+
676
+ text_results = detect_text(image)
677
+
678
+ st.subheader("Detected Text:")
679
+
680
+ for i, (text, box) in enumerate(text_results):
681
+ if text.strip() and text not in st.session_state.get('replaced_texts', []):
682
+ st.text(f"{i+1}. {text}")
683
+
684
+ new_text = st.text_input(f"Enter new text for '{text}':", value=text, key=f"new_text_{i}")
685
+ new_color = st.color_picker(f"Choose color for new text '{new_text}':", '#000000', key=f"color_{i}")
686
+
687
+ if st.button(f"Replace '{text}'", key=f"replace_{i}"):
688
+ st.session_state.edited_image = replace_text_in_image(image, text, new_text, new_color)
689
+ if 'replaced_texts' not in st.session_state:
690
+ st.session_state.replaced_texts = []
691
+ st.session_state.replaced_texts.append(text)
692
+ st.image(st.session_state.edited_image, caption='Edited Image', use_column_width=True)
693
+ text_results[i] = (new_text, box)
694
+
695
+ if hasattr(st.session_state, 'edited_image') and st.session_state.edited_image is not None:
696
+ buf = io.BytesIO()
697
+ st.session_state.edited_image.save(buf, format="PNG")
698
+ byte_im = buf.getvalue()
699
+ st.download_button(label="Download edited image", data=byte_im, file_name="edited_image.png", mime="image/png")
700
 
701
  if __name__ == "__main__":
702
  main()