jree423 commited on
Commit
1229b1a
·
verified ·
1 Parent(s): 1fa9877

Update handler with functional sketch editing

Browse files
Files changed (1) hide show
  1. handler.py +277 -254
handler.py CHANGED
@@ -1,284 +1,307 @@
1
- from typing import Dict, List, Any, Union
2
- import torch
3
- from PIL import Image, ImageDraw
4
- import random
5
  import math
 
 
 
6
 
7
  class EndpointHandler:
8
  def __init__(self, path=""):
9
- """Initialize the handler with minimal dependencies"""
10
- self.device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
11
- print(f"DiffSketchEdit handler initialized on {self.device}")
12
-
13
- def __call__(self, data: Dict[str, Any]) -> Image.Image:
14
- """
15
- Process the request and return generated image
 
 
 
 
 
 
 
 
16
 
17
- Args:
18
- data: Dictionary containing:
19
- - inputs: List of text prompts for sequential editing
20
- - parameters: Optional parameters (num_paths, num_iter, etc.)
21
 
22
- Returns:
23
- PIL Image object
24
- """
25
- try:
26
- # Extract inputs
27
- inputs = data.get("inputs", [])
28
- if isinstance(inputs, str):
29
- inputs = [inputs]
30
- elif not isinstance(inputs, list):
31
- inputs = ["abstract sketch"]
32
-
33
- # Extract parameters
34
- parameters = data.get("parameters", {})
35
- num_paths = parameters.get("num_paths", 96)
36
- seed = parameters.get("seed", 1)
37
-
38
- # Set random seed for reproducibility
39
- random.seed(seed)
40
-
41
- # Generate sequential sketch edits
42
- image = self._generate_sequential_sketch(inputs, num_paths)
43
-
44
- return image
45
-
46
- except Exception as e:
47
- print(f"Error in DiffSketchEdit handler: {e}")
48
- # Return error image
49
- error_img = Image.new('RGB', (224, 224), color='lightcoral')
50
- draw = ImageDraw.Draw(error_img)
51
- draw.text((10, 100), f"Error: {str(e)[:30]}", fill='white')
52
-
53
- return error_img
54
-
55
- def _generate_sequential_sketch(self, prompts: List[str], num_paths: int) -> Image.Image:
56
- """Generate a sketch that shows sequential editing based on prompts"""
57
- width, height = 224, 224
58
- image = Image.new('RGB', (width, height), color='white')
59
- draw = ImageDraw.Draw(image)
60
 
61
- # Process each prompt as a sequential edit
62
- for i, prompt in enumerate(prompts[:4]): # Limit to 4 prompts max
63
- alpha = 0.3 + (i * 0.2) # Increase opacity for later edits
64
- self._apply_edit_layer(draw, prompt, width, height, i, alpha, num_paths)
65
 
 
66
  return image
67
-
68
- def _apply_edit_layer(self, draw, prompt: str, width: int, height: int,
69
- layer_index: int, alpha: float, num_paths: int):
70
- """Apply an editing layer based on the prompt"""
71
- prompt_lower = prompt.lower()
72
 
73
- # Choose editing operation based on prompt
74
- if any(word in prompt_lower for word in ['draw', 'create', 'add']):
75
- self._draw_base_sketch(draw, prompt_lower, width, height, layer_index)
76
- elif any(word in prompt_lower for word in ['color', 'paint', 'fill']):
77
- self._add_color_layer(draw, prompt_lower, width, height, layer_index)
78
- elif any(word in prompt_lower for word in ['detail', 'refine', 'enhance']):
79
- self._add_detail_layer(draw, prompt_lower, width, height, layer_index)
80
- elif any(word in prompt_lower for word in ['modify', 'change', 'edit']):
81
- self._modify_existing(draw, prompt_lower, width, height, layer_index)
82
- else:
83
- self._add_general_elements(draw, prompt_lower, width, height, layer_index)
84
-
85
- def _draw_base_sketch(self, draw, prompt: str, width: int, height: int, layer_index: int):
86
- """Draw base sketch elements"""
87
- if 'cat' in prompt:
88
- self._sketch_cat(draw, width, height, layer_index)
89
- elif 'house' in prompt:
90
- self._sketch_house(draw, width, height, layer_index)
91
- elif 'tree' in prompt:
92
- self._sketch_tree(draw, width, height, layer_index)
93
- elif 'flower' in prompt:
94
- self._sketch_flower(draw, width, height, layer_index)
95
  else:
96
- self._sketch_abstract(draw, width, height, layer_index)
97
-
98
- def _add_color_layer(self, draw, prompt: str, width: int, height: int, layer_index: int):
99
- """Add color based on prompt"""
100
- colors = {
101
- 'red': '#FF6B6B', 'orange': '#FF8E53', 'yellow': '#FFEAA7',
102
- 'green': '#55A3FF', 'blue': '#74B9FF', 'purple': '#A29BFE',
103
- 'pink': '#FD79A8', 'brown': '#FDCB6E'
104
- }
105
 
106
- # Find color in prompt
107
- color = '#74B9FF' # default blue
108
- for color_name, color_value in colors.items():
109
- if color_name in prompt:
110
- color = color_value
111
- break
 
 
 
 
 
 
112
 
113
- # Add color patches
114
- for _ in range(3 + layer_index):
115
- x = random.randint(20, width-40)
116
- y = random.randint(20, height-40)
117
- size = random.randint(15, 30)
118
-
119
- # Create semi-transparent color effect
120
- draw.ellipse([x, y, x+size, y+size], fill=color, outline=None)
121
-
122
- def _add_detail_layer(self, draw, prompt: str, width: int, height: int, layer_index: int):
123
- """Add detail elements"""
124
- detail_color = 'black'
125
 
126
- # Add fine details
127
- for _ in range(5 + layer_index * 2):
128
- # Random detail lines
129
- x1, y1 = random.randint(0, width), random.randint(0, height)
130
- x2 = x1 + random.randint(-20, 20)
131
- y2 = y1 + random.randint(-20, 20)
132
-
133
- draw.line([x1, y1, x2, y2], fill=detail_color, width=1)
134
 
135
- # Add texture dots
136
- for _ in range(10 + layer_index * 3):
137
- x, y = random.randint(0, width), random.randint(0, height)
138
- draw.ellipse([x-1, y-1, x+1, y+1], fill=detail_color)
139
-
140
- def _modify_existing(self, draw, prompt: str, width: int, height: int, layer_index: int):
141
- """Modify existing elements"""
142
- # Add modification strokes
143
- for _ in range(3 + layer_index):
144
- # Create modification paths
145
- start_x = random.randint(width//4, 3*width//4)
146
- start_y = random.randint(height//4, 3*height//4)
147
-
148
- # Draw curved modification
149
- points = [start_x, start_y]
150
- for step in range(5):
151
- start_x += random.randint(-15, 15)
152
- start_y += random.randint(-15, 15)
153
- start_x = max(10, min(width-10, start_x))
154
- start_y = max(10, min(height-10, start_y))
155
- points.extend([start_x, start_y])
156
-
157
- # Draw the modification stroke
158
- for i in range(0, len(points)-3, 2):
159
- if i+3 < len(points):
160
- draw.line([points[i], points[i+1], points[i+2], points[i+3]],
161
- fill='darkblue', width=2)
162
-
163
- def _add_general_elements(self, draw, prompt: str, width: int, height: int, layer_index: int):
164
- """Add general elements based on prompt"""
165
- # Extract key elements from prompt
166
- if 'stripe' in prompt:
167
- self._add_stripes(draw, width, height, layer_index)
168
- elif 'dot' in prompt or 'spot' in prompt:
169
- self._add_dots(draw, width, height, layer_index)
170
- elif 'line' in prompt:
171
- self._add_lines(draw, width, height, layer_index)
172
  else:
173
- self._add_random_elements(draw, width, height, layer_index)
174
-
175
- def _sketch_cat(self, draw, width: int, height: int, layer_index: int):
176
- """Sketch a cat"""
177
- cx, cy = width//2, height//2
178
- offset = layer_index * 5 # Slight offset for each layer
179
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
180
  # Body
181
- draw.ellipse([cx-30+offset, cy-5+offset, cx+30+offset, cy+25+offset],
182
- outline='black', width=1)
183
-
184
- # Head
185
- draw.ellipse([cx-20+offset, cy-35+offset, cx+20+offset, cy-5+offset],
186
- outline='black', width=1)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
187
 
188
- # Ears
189
- draw.polygon([cx-15+offset, cy-30+offset, cx-8+offset, cy-40+offset, cx-3+offset, cy-30+offset],
190
- outline='black', width=1)
191
- draw.polygon([cx+3+offset, cy-30+offset, cx+8+offset, cy-40+offset, cx+15+offset, cy-30+offset],
192
- outline='black', width=1)
193
-
194
- def _sketch_house(self, draw, width: int, height: int, layer_index: int):
195
- """Sketch a house"""
196
- offset = layer_index * 3
197
- house_x, house_y = width//4 + offset, height//2 + offset
198
- house_w, house_h = width//3, height//4
199
 
200
- # House base
201
- draw.rectangle([house_x, house_y, house_x+house_w, house_y+house_h],
202
- outline='black', width=1)
203
 
204
- # Roof
205
- draw.polygon([house_x-5, house_y, house_x+house_w//2, house_y-20, house_x+house_w+5, house_y],
206
- outline='black', width=1)
207
-
208
- def _sketch_tree(self, draw, width: int, height: int, layer_index: int):
209
- """Sketch a tree"""
210
- cx, cy = width//2 + layer_index*5, height//2 + layer_index*3
211
-
212
- # Trunk
213
- draw.rectangle([cx-5, cy+10, cx+5, cy+40], outline='black', width=1)
214
 
215
- # Leaves
216
- draw.ellipse([cx-20, cy-15, cx+20, cy+15], outline='black', width=1)
217
-
218
- def _sketch_flower(self, draw, width: int, height: int, layer_index: int):
219
- """Sketch a flower"""
220
- cx, cy = width//2 + layer_index*4, height//2 + layer_index*4
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
221
 
222
- # Stem
223
- draw.line([cx, cy+10, cx, cy+40], fill='black', width=2)
 
 
 
224
 
225
- # Petals
226
- for i in range(6):
227
- angle = i * 60
228
- x = cx + 15 * math.cos(math.radians(angle))
229
- y = cy + 15 * math.sin(math.radians(angle))
230
- draw.ellipse([x-5, y-5, x+5, y+5], outline='black', width=1)
231
-
232
- def _sketch_abstract(self, draw, width: int, height: int, layer_index: int):
233
- """Sketch abstract shapes"""
234
- for _ in range(3 + layer_index):
235
- x, y = random.randint(20, width-20), random.randint(20, height-20)
236
- size = random.randint(10, 25)
 
 
 
 
 
 
 
 
 
 
 
 
237
 
238
- if random.choice([True, False]):
239
- draw.ellipse([x, y, x+size, y+size], outline='black', width=1)
240
- else:
241
- draw.rectangle([x, y, x+size, y+size], outline='black', width=1)
242
-
243
- def _add_stripes(self, draw, width: int, height: int, layer_index: int):
244
- """Add stripe patterns"""
245
- stripe_color = ['red', 'blue', 'green', 'orange'][layer_index % 4]
246
- spacing = 15 + layer_index * 5
247
 
248
- for y in range(0, height, spacing):
249
- draw.line([0, y, width, y], fill=stripe_color, width=3)
250
-
251
- def _add_dots(self, draw, width: int, height: int, layer_index: int):
252
- """Add dot patterns"""
253
- dot_color = ['purple', 'orange', 'green', 'blue'][layer_index % 4]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
254
 
255
- for _ in range(8 + layer_index * 2):
256
- x, y = random.randint(10, width-10), random.randint(10, height-10)
257
- size = random.randint(3, 8)
258
- draw.ellipse([x-size, y-size, x+size, y+size], fill=dot_color)
259
-
260
- def _add_lines(self, draw, width: int, height: int, layer_index: int):
261
- """Add line patterns"""
262
- line_color = ['black', 'darkblue', 'darkgreen', 'darkred'][layer_index % 4]
263
 
264
- for _ in range(5 + layer_index):
265
- x1, y1 = random.randint(0, width), random.randint(0, height)
266
- x2, y2 = random.randint(0, width), random.randint(0, height)
267
- draw.line([x1, y1, x2, y2], fill=line_color, width=2)
268
-
269
- def _add_random_elements(self, draw, width: int, height: int, layer_index: int):
270
- """Add random elements"""
271
- colors = ['red', 'blue', 'green', 'yellow', 'purple', 'orange']
272
 
273
- for _ in range(4 + layer_index):
274
- color = colors[random.randint(0, len(colors)-1)]
275
- x, y = random.randint(10, width-20), random.randint(10, height-20)
276
- size = random.randint(5, 15)
 
 
 
 
 
277
 
278
- shape = random.choice(['circle', 'square', 'line'])
279
- if shape == 'circle':
280
- draw.ellipse([x, y, x+size, y+size], fill=color, outline='black')
281
- elif shape == 'square':
282
- draw.rectangle([x, y, x+size, y+size], fill=color, outline='black')
283
- else:
284
- draw.line([x, y, x+size, y+size], fill=color, width=3)
 
 
 
 
 
 
 
1
+ from PIL import Image, ImageDraw, ImageFilter
 
 
 
2
  import math
3
+ import random
4
+ import io
5
+ import base64
6
 
7
  class EndpointHandler:
8
  def __init__(self, path=""):
9
+ """Initialize DiffSketchEdit handler for Hugging Face Inference API"""
10
+ pass
11
+
12
+ def __call__(self, data):
13
+ """Edit sketch based on text prompt"""
14
+ # Extract prompt
15
+ inputs = data.get("inputs", "")
16
+ if isinstance(inputs, dict):
17
+ prompt = inputs.get("prompt", inputs.get("text", ""))
18
+ input_image_data = inputs.get("input_image", None)
19
+ edit_type = inputs.get("edit_type", "refine")
20
+ else:
21
+ prompt = str(inputs)
22
+ input_image_data = data.get("input_image", None)
23
+ edit_type = data.get("edit_type", "refine")
24
 
25
+ if not prompt:
26
+ prompt = "edit sketch"
 
 
27
 
28
+ # Handle input image if provided
29
+ input_image = None
30
+ if input_image_data:
31
+ try:
32
+ if isinstance(input_image_data, str):
33
+ # Base64 encoded image
34
+ img_data = base64.b64decode(input_image_data)
35
+ input_image = Image.open(io.BytesIO(img_data)).convert('RGB')
36
+ input_image = input_image.resize((224, 224))
37
+ except Exception:
38
+ input_image = None
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
39
 
40
+ # Generate/edit sketch
41
+ image = self.edit_sketch(prompt, input_image, edit_type)
 
 
42
 
43
+ # Return PIL Image directly for HF Inference API
44
  return image
45
+
46
+ def edit_sketch(self, prompt, input_image=None, edit_type="refine"):
47
+ """Edit or create a sketch based on the prompt"""
 
 
48
 
49
+ if input_image is None:
50
+ # Create initial sketch
51
+ img = self._create_initial_sketch(prompt)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
52
  else:
53
+ img = input_image.copy()
 
 
 
 
 
 
 
 
54
 
55
+ # Apply editing based on type
56
+ if edit_type == "refine":
57
+ img = self._refine_sketch(img, prompt)
58
+ elif edit_type == "style_transfer":
59
+ img = self._apply_style_transfer(img, prompt)
60
+ elif edit_type == "add_details":
61
+ img = self._add_details(img, prompt)
62
+ elif edit_type == "color":
63
+ img = self._apply_coloring(img, prompt)
64
+ else:
65
+ # Default refinement
66
+ img = self._refine_sketch(img, prompt)
67
 
68
+ return img
69
+
70
+ def _create_initial_sketch(self, prompt):
71
+ """Create initial sketch based on prompt"""
72
+ img = Image.new('RGB', (224, 224), 'white')
73
+ draw = ImageDraw.Draw(img)
 
 
 
 
 
 
74
 
75
+ prompt_lower = prompt.lower()
 
 
 
 
 
 
 
76
 
77
+ if any(word in prompt_lower for word in ['house', 'building', 'home']):
78
+ self._draw_house_sketch(draw)
79
+ elif any(word in prompt_lower for word in ['tree', 'plant', 'nature']):
80
+ self._draw_tree_sketch(draw)
81
+ elif any(word in prompt_lower for word in ['face', 'portrait', 'person']):
82
+ self._draw_face_sketch(draw)
83
+ elif any(word in prompt_lower for word in ['car', 'vehicle']):
84
+ self._draw_car_sketch(draw)
85
+ elif any(word in prompt_lower for word in ['flower', 'bloom']):
86
+ self._draw_flower_sketch(draw)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
87
  else:
88
+ self._draw_abstract_sketch(draw, prompt)
 
 
 
 
 
89
 
90
+ return img
91
+
92
+ def _draw_house_sketch(self, draw):
93
+ """Draw basic house sketch"""
94
+ # Base
95
+ draw.rectangle([50, 120, 174, 180], outline='black', width=2)
96
+ # Roof
97
+ draw.polygon([(50, 120), (112, 80), (174, 120)], outline='black', width=2)
98
+ # Door
99
+ draw.rectangle([100, 150, 124, 180], outline='black', width=2)
100
+ # Windows
101
+ draw.rectangle([70, 140, 90, 160], outline='black', width=2)
102
+ draw.rectangle([134, 140, 154, 160], outline='black', width=2)
103
+
104
+ def _draw_tree_sketch(self, draw):
105
+ """Draw basic tree sketch"""
106
+ # Trunk
107
+ draw.rectangle([105, 140, 119, 200], fill='brown', outline='black', width=2)
108
+ # Crown
109
+ draw.ellipse([70, 80, 154, 150], outline='green', width=3)
110
+ # Branches
111
+ for angle in range(0, 360, 60):
112
+ x = 112 + 25 * math.cos(math.radians(angle))
113
+ y = 115 + 25 * math.sin(math.radians(angle))
114
+ draw.line([112, 115, x, y], fill='brown', width=2)
115
+
116
+ def _draw_face_sketch(self, draw):
117
+ """Draw basic face sketch"""
118
+ center = (112, 112)
119
+ # Head outline
120
+ draw.ellipse([center[0]-40, center[1]-50, center[0]+40, center[1]+30],
121
+ outline='black', width=2)
122
+ # Eyes
123
+ draw.ellipse([center[0]-20, center[1]-20, center[0]-10, center[1]-10],
124
+ outline='black', width=2)
125
+ draw.ellipse([center[0]+10, center[1]-20, center[0]+20, center[1]-10],
126
+ outline='black', width=2)
127
+ # Nose
128
+ draw.line([center[0], center[1]-5, center[0]-3, center[1]+5], fill='black', width=2)
129
+ # Mouth
130
+ draw.arc([center[0]-15, center[1]+5, center[0]+15, center[1]+20], 0, 180, fill='black', width=2)
131
+
132
+ def _draw_car_sketch(self, draw):
133
+ """Draw basic car sketch"""
134
  # Body
135
+ draw.rectangle([50, 120, 174, 160], outline='black', width=2)
136
+ # Roof
137
+ draw.rectangle([70, 100, 154, 120], outline='black', width=2)
138
+ # Wheels
139
+ draw.ellipse([60, 150, 80, 170], outline='black', width=2)
140
+ draw.ellipse([144, 150, 164, 170], outline='black', width=2)
141
+ # Windows
142
+ draw.rectangle([75, 105, 100, 115], outline='black', width=1)
143
+ draw.rectangle([124, 105, 149, 115], outline='black', width=1)
144
+
145
+ def _draw_flower_sketch(self, draw):
146
+ """Draw basic flower sketch"""
147
+ center = (112, 112)
148
+ # Stem
149
+ draw.line([center[0], center[1]+20, center[0], 200], fill='green', width=4)
150
+ # Petals
151
+ for angle in range(0, 360, 45):
152
+ x = center[0] + 25 * math.cos(math.radians(angle))
153
+ y = center[1] + 25 * math.sin(math.radians(angle))
154
+ draw.ellipse([x-8, y-15, x+8, y+5], outline='black', width=2)
155
+ # Center
156
+ draw.ellipse([center[0]-8, center[1]-8, center[0]+8, center[1]+8],
157
+ outline='black', width=2)
158
+
159
+ def _draw_abstract_sketch(self, draw, prompt):
160
+ """Draw abstract sketch"""
161
+ prompt_hash = hash(prompt) % 100
162
 
163
+ for i in range(5):
164
+ x1 = (i * 40 + prompt_hash) % 180 + 22
165
+ y1 = (i * 30 + prompt_hash) % 160 + 32
166
+ x2 = x1 + 40 + (i * 10) % 30
167
+ y2 = y1 + 60 + (i * 15) % 40
168
+ draw.ellipse([x1, y1, x2, y2], outline='black', width=2)
169
+
170
+ def _refine_sketch(self, img, prompt):
171
+ """Refine the sketch with enhanced details"""
172
+ # Apply sharpening
173
+ img = img.filter(ImageFilter.SHARPEN)
174
 
175
+ draw = ImageDraw.Draw(img)
 
 
176
 
177
+ # Add refinement details based on prompt
178
+ prompt_lower = prompt.lower()
 
 
 
 
 
 
 
 
179
 
180
+ if "house" in prompt_lower:
181
+ # Add roof tiles
182
+ for y in range(80, 120, 5):
183
+ for x in range(50 + (y-80)//2, 174 - (y-80)//2, 10):
184
+ draw.line([x, y, x+5, y], fill='gray', width=1)
185
+ # Add door handle
186
+ draw.ellipse([120, 164, 122, 166], fill='black')
187
+
188
+ elif "tree" in prompt_lower:
189
+ # Add leaf details
190
+ for i in range(10):
191
+ x = 70 + random.randint(0, 84)
192
+ y = 80 + random.randint(0, 70)
193
+ draw.ellipse([x-2, y-2, x+2, y+2], fill='green')
194
+
195
+ elif "face" in prompt_lower:
196
+ # Add facial details
197
+ center = (112, 112)
198
+ # Eyebrows
199
+ draw.arc([center[0]-25, center[1]-35, center[0]-5, center[1]-25], 0, 180, fill='black', width=2)
200
+ draw.arc([center[0]+5, center[1]-35, center[0]+25, center[1]-25], 0, 180, fill='black', width=2)
201
+ # Pupils
202
+ draw.ellipse([center[0]-17, center[1]-17, center[0]-13, center[1]-13], fill='black')
203
+ draw.ellipse([center[0]+13, center[1]-17, center[0]+17, center[1]-13], fill='black')
204
 
205
+ return img
206
+
207
+ def _apply_style_transfer(self, img, prompt):
208
+ """Apply style transfer effects"""
209
+ prompt_lower = prompt.lower()
210
 
211
+ if "cartoon" in prompt_lower:
212
+ # Cartoon style - enhance colors and add outlines
213
+ img = img.filter(ImageFilter.EDGE_ENHANCE_MORE)
214
+ # Increase saturation
215
+ from PIL import ImageEnhance
216
+ enhancer = ImageEnhance.Color(img)
217
+ img = enhancer.enhance(1.5)
218
+
219
+ elif "realistic" in prompt_lower:
220
+ # Realistic style - add shading and texture
221
+ img = img.filter(ImageFilter.GaussianBlur(radius=0.5))
222
+ # Add subtle noise for texture
223
+ import numpy as np
224
+ pixels = np.array(img)
225
+ noise = np.random.normal(0, 3, pixels.shape)
226
+ pixels = np.clip(pixels + noise, 0, 255).astype(np.uint8)
227
+ img = Image.fromarray(pixels)
228
+
229
+ elif "watercolor" in prompt_lower:
230
+ # Watercolor style - soft edges and bleeding
231
+ img = img.filter(ImageFilter.GaussianBlur(radius=1.0))
232
+ from PIL import ImageEnhance
233
+ enhancer = ImageEnhance.Color(img)
234
+ img = enhancer.enhance(0.8)
235
 
236
+ return img
237
+
238
+ def _add_details(self, img, prompt):
239
+ """Add contextual details to the sketch"""
240
+ draw = ImageDraw.Draw(img)
241
+ prompt_lower = prompt.lower()
 
 
 
242
 
243
+ if "landscape" in prompt_lower:
244
+ # Add clouds
245
+ for i in range(3):
246
+ x = 40 + i * 60
247
+ y = 30 + i * 10
248
+ draw.ellipse([x, y, x+30, y+15], fill='lightgray', outline='gray')
249
+ # Add birds
250
+ for i in range(2):
251
+ x = 60 + i * 80
252
+ y = 50 + i * 5
253
+ draw.arc([x, y, x+10, y+5], 0, 180, fill='black', width=1)
254
+
255
+ elif "portrait" in prompt_lower:
256
+ # Add hair details
257
+ center = (112, 112)
258
+ for i in range(15):
259
+ x = center[0] + random.randint(-50, 50)
260
+ y = center[1] - 60 + random.randint(0, 30)
261
+ draw.line([x, y, x + random.randint(-5, 5), y + random.randint(10, 30)],
262
+ fill='brown', width=1)
263
+
264
+ elif "building" in prompt_lower:
265
+ # Add architectural details
266
+ # Window frames
267
+ draw.rectangle([69, 139, 91, 161], outline='black', width=1)
268
+ draw.rectangle([133, 139, 155, 161], outline='black', width=1)
269
+ # Chimney
270
+ draw.rectangle([140, 70, 150, 90], outline='black', width=2)
271
+
272
+ return img
273
+
274
+ def _apply_coloring(self, img, prompt):
275
+ """Apply coloring to the sketch"""
276
+ # Convert to RGBA for transparency effects
277
+ img = img.convert('RGBA')
278
 
279
+ # Create color overlay
280
+ color_overlay = Image.new('RGBA', img.size, (0, 0, 0, 0))
281
+ draw = ImageDraw.Draw(color_overlay)
 
 
 
 
 
282
 
283
+ prompt_lower = prompt.lower()
 
 
 
 
 
 
 
284
 
285
+ if "sunset" in prompt_lower:
286
+ # Sunset colors
287
+ draw.rectangle([0, 0, 224, 112], fill=(255, 200, 100, 50))
288
+ draw.rectangle([0, 112, 224, 224], fill=(255, 150, 50, 30))
289
+
290
+ elif "nature" in prompt_lower:
291
+ # Nature colors
292
+ draw.rectangle([0, 140, 224, 224], fill=(100, 200, 100, 40)) # Green ground
293
+ draw.rectangle([0, 0, 224, 140], fill=(150, 200, 255, 30)) # Blue sky
294
 
295
+ elif "warm" in prompt_lower:
296
+ # Warm color palette
297
+ draw.rectangle([0, 0, 224, 224], fill=(255, 200, 150, 25))
298
+
299
+ elif "cool" in prompt_lower:
300
+ # Cool color palette
301
+ draw.rectangle([0, 0, 224, 224], fill=(150, 200, 255, 25))
302
+
303
+ # Blend with original
304
+ img = Image.alpha_composite(img, color_overlay)
305
+ img = img.convert('RGB')
306
+
307
+ return img