Spaces:
Runtime error
Runtime error
Update app.py
Browse files
app.py
CHANGED
|
@@ -7,7 +7,7 @@ import json
|
|
| 7 |
from rembg import remove
|
| 8 |
import requests
|
| 9 |
from pathlib import Path
|
| 10 |
-
import
|
| 11 |
|
| 12 |
# ------------------------------
|
| 13 |
# Utility Functions
|
|
@@ -125,6 +125,12 @@ if 'history' not in st.session_state:
|
|
| 125 |
if 'redo_stack' not in st.session_state:
|
| 126 |
st.session_state['redo_stack'] = []
|
| 127 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 128 |
# ------------------------------
|
| 129 |
# Layer Management Functions
|
| 130 |
# ------------------------------
|
|
@@ -462,14 +468,72 @@ if load_project:
|
|
| 462 |
|
| 463 |
if uploaded_file:
|
| 464 |
base_image = Image.open(uploaded_file).convert("RGBA")
|
| 465 |
-
|
| 466 |
|
| 467 |
# Apply auto enhance if selected
|
| 468 |
if apply_auto_enhance:
|
| 469 |
-
|
| 470 |
|
| 471 |
# Initialize drawing context
|
| 472 |
-
draw = ImageDraw.Draw(
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 473 |
|
| 474 |
for layer in st.session_state['layers']:
|
| 475 |
if not layer.get('visible', True):
|
|
@@ -487,15 +551,15 @@ if uploaded_file:
|
|
| 487 |
except ValueError:
|
| 488 |
text_color_rgba = (0, 0, 0, text_opacity)
|
| 489 |
text_color_rgba = text_color_rgba[:3] + (text_opacity,)
|
| 490 |
-
text_layer = Image.new('RGBA',
|
| 491 |
text_draw = ImageDraw.Draw(text_layer)
|
| 492 |
alignment = layer.get('alignment', 'left')
|
| 493 |
text_position = (layer['x'], layer['y'])
|
| 494 |
text_draw.text(text_position, layer['content'], fill=text_color_rgba, font=font, align=alignment)
|
| 495 |
if layer.get('blending_mode') and layer['blending_mode'] != "Normal":
|
| 496 |
-
|
| 497 |
else:
|
| 498 |
-
|
| 499 |
elif layer['type'] in ["Image", "Sticker"]:
|
| 500 |
overlay = layer['content'].copy()
|
| 501 |
opacity = layer.get('opacity', 100)
|
|
@@ -504,11 +568,11 @@ if uploaded_file:
|
|
| 504 |
alpha = alpha.point(lambda p: p * opacity / 100)
|
| 505 |
overlay.putalpha(alpha)
|
| 506 |
if layer.get('blending_mode') and layer['blending_mode'] != "Normal":
|
| 507 |
-
|
| 508 |
else:
|
| 509 |
-
|
| 510 |
elif layer['type'] == "Shape":
|
| 511 |
-
shape_layer = Image.new('RGBA',
|
| 512 |
shape_draw = ImageDraw.Draw(shape_layer)
|
| 513 |
color = layer['color']
|
| 514 |
opacity = layer.get('opacity', 100)
|
|
@@ -526,27 +590,27 @@ if uploaded_file:
|
|
| 526 |
elif layer['shape'] == "Line":
|
| 527 |
shape_draw.line([x1, y1, x2, y2], fill=shape_color_rgba, width=thickness)
|
| 528 |
if layer.get('blending_mode') and layer['blending_mode'] != "Normal":
|
| 529 |
-
|
| 530 |
else:
|
| 531 |
-
|
| 532 |
|
| 533 |
# Apply filters
|
| 534 |
-
|
| 535 |
|
| 536 |
# Remove background if selected
|
| 537 |
if remove_bg:
|
| 538 |
try:
|
| 539 |
-
|
| 540 |
st.success("Background removed successfully!")
|
| 541 |
except Exception as e:
|
| 542 |
st.error(f"Background removal failed: {e}")
|
| 543 |
|
| 544 |
# Display the final image
|
| 545 |
-
st.image(
|
| 546 |
|
| 547 |
# Download options
|
| 548 |
buffer = io.BytesIO()
|
| 549 |
-
|
| 550 |
st.download_button(
|
| 551 |
label="📥 Download Edited Image",
|
| 552 |
data=buffer.getvalue(),
|
|
|
|
| 7 |
from rembg import remove
|
| 8 |
import requests
|
| 9 |
from pathlib import Path
|
| 10 |
+
from streamlit_drawable_canvas import st_canvas
|
| 11 |
|
| 12 |
# ------------------------------
|
| 13 |
# Utility Functions
|
|
|
|
| 125 |
if 'redo_stack' not in st.session_state:
|
| 126 |
st.session_state['redo_stack'] = []
|
| 127 |
|
| 128 |
+
# Initialize session state for text addition
|
| 129 |
+
if 'text_input' not in st.session_state:
|
| 130 |
+
st.session_state['text_input'] = ""
|
| 131 |
+
if 'click_position' not in st.session_state:
|
| 132 |
+
st.session_state['click_position'] = None
|
| 133 |
+
|
| 134 |
# ------------------------------
|
| 135 |
# Layer Management Functions
|
| 136 |
# ------------------------------
|
|
|
|
| 468 |
|
| 469 |
if uploaded_file:
|
| 470 |
base_image = Image.open(uploaded_file).convert("RGBA")
|
| 471 |
+
canvas_image = base_image.copy()
|
| 472 |
|
| 473 |
# Apply auto enhance if selected
|
| 474 |
if apply_auto_enhance:
|
| 475 |
+
canvas_image = auto_enhance(canvas_image)
|
| 476 |
|
| 477 |
# Initialize drawing context
|
| 478 |
+
draw = ImageDraw.Draw(canvas_image, 'RGBA')
|
| 479 |
+
|
| 480 |
+
# ------------------------------
|
| 481 |
+
# Interactive Text Addition
|
| 482 |
+
# ------------------------------
|
| 483 |
+
|
| 484 |
+
st.header("🖌️ Interactive Text Addition")
|
| 485 |
+
|
| 486 |
+
# Display the canvas with drawable features
|
| 487 |
+
canvas_result = st_canvas(
|
| 488 |
+
fill_color="rgba(255, 255, 255, 0)", # Transparent fill
|
| 489 |
+
stroke_width=0,
|
| 490 |
+
stroke_color="#000000",
|
| 491 |
+
background_image=canvas_image,
|
| 492 |
+
update_streamlit=True,
|
| 493 |
+
height=canvas_image.height,
|
| 494 |
+
width=canvas_image.width,
|
| 495 |
+
drawing_mode="freedraw",
|
| 496 |
+
key="canvas",
|
| 497 |
+
# Hide the drawing toolbar
|
| 498 |
+
display_toolbar=False,
|
| 499 |
+
)
|
| 500 |
+
|
| 501 |
+
if canvas_result.json_data is not None:
|
| 502 |
+
objects = canvas_result.json_data["objects"]
|
| 503 |
+
if objects:
|
| 504 |
+
last_object = objects[-1]
|
| 505 |
+
if last_object["type"] == "point":
|
| 506 |
+
x, y = last_object["left"], last_object["top"]
|
| 507 |
+
st.session_state['click_position'] = (int(x), int(y))
|
| 508 |
+
st.session_state['text_input'] = st.text_input("Enter Text for the Clicked Position:", "")
|
| 509 |
+
if st.button("Add Text Here"):
|
| 510 |
+
text_content = st.session_state['text_input']
|
| 511 |
+
if text_content:
|
| 512 |
+
# Define default properties for interactive text
|
| 513 |
+
layer = {
|
| 514 |
+
'type': 'Text',
|
| 515 |
+
'content': text_content,
|
| 516 |
+
'x': st.session_state['click_position'][0],
|
| 517 |
+
'y': st.session_state['click_position'][1],
|
| 518 |
+
'font_size': 40,
|
| 519 |
+
'font_color': "#000000",
|
| 520 |
+
'font_path': list(font_paths.values())[0], # Default to the first font
|
| 521 |
+
'opacity': 100,
|
| 522 |
+
'visible': True,
|
| 523 |
+
'alignment': "left",
|
| 524 |
+
'blending_mode': "Normal"
|
| 525 |
+
}
|
| 526 |
+
add_layer(layer)
|
| 527 |
+
st.success("Interactive text added!")
|
| 528 |
+
# Reset click position and text input
|
| 529 |
+
st.session_state['click_position'] = None
|
| 530 |
+
st.session_state['text_input'] = ""
|
| 531 |
+
else:
|
| 532 |
+
st.warning("Please enter some text.")
|
| 533 |
+
|
| 534 |
+
# ------------------------------
|
| 535 |
+
# Process Layers and Render Image
|
| 536 |
+
# ------------------------------
|
| 537 |
|
| 538 |
for layer in st.session_state['layers']:
|
| 539 |
if not layer.get('visible', True):
|
|
|
|
| 551 |
except ValueError:
|
| 552 |
text_color_rgba = (0, 0, 0, text_opacity)
|
| 553 |
text_color_rgba = text_color_rgba[:3] + (text_opacity,)
|
| 554 |
+
text_layer = Image.new('RGBA', canvas_image.size, (255,255,255,0))
|
| 555 |
text_draw = ImageDraw.Draw(text_layer)
|
| 556 |
alignment = layer.get('alignment', 'left')
|
| 557 |
text_position = (layer['x'], layer['y'])
|
| 558 |
text_draw.text(text_position, layer['content'], fill=text_color_rgba, font=font, align=alignment)
|
| 559 |
if layer.get('blending_mode') and layer['blending_mode'] != "Normal":
|
| 560 |
+
canvas_image = blend_images(canvas_image, text_layer, layer['blending_mode'])
|
| 561 |
else:
|
| 562 |
+
canvas_image = Image.alpha_composite(canvas_image, text_layer)
|
| 563 |
elif layer['type'] in ["Image", "Sticker"]:
|
| 564 |
overlay = layer['content'].copy()
|
| 565 |
opacity = layer.get('opacity', 100)
|
|
|
|
| 568 |
alpha = alpha.point(lambda p: p * opacity / 100)
|
| 569 |
overlay.putalpha(alpha)
|
| 570 |
if layer.get('blending_mode') and layer['blending_mode'] != "Normal":
|
| 571 |
+
canvas_image = blend_images(canvas_image, overlay, layer['blending_mode'])
|
| 572 |
else:
|
| 573 |
+
canvas_image.paste(overlay, (layer['x'], layer['y']), overlay)
|
| 574 |
elif layer['type'] == "Shape":
|
| 575 |
+
shape_layer = Image.new('RGBA', canvas_image.size, (255,255,255,0))
|
| 576 |
shape_draw = ImageDraw.Draw(shape_layer)
|
| 577 |
color = layer['color']
|
| 578 |
opacity = layer.get('opacity', 100)
|
|
|
|
| 590 |
elif layer['shape'] == "Line":
|
| 591 |
shape_draw.line([x1, y1, x2, y2], fill=shape_color_rgba, width=thickness)
|
| 592 |
if layer.get('blending_mode') and layer['blending_mode'] != "Normal":
|
| 593 |
+
canvas_image = blend_images(canvas_image, shape_layer, layer['blending_mode'])
|
| 594 |
else:
|
| 595 |
+
canvas_image = Image.alpha_composite(canvas_image, shape_layer)
|
| 596 |
|
| 597 |
# Apply filters
|
| 598 |
+
canvas_image = apply_filters(canvas_image, filters)
|
| 599 |
|
| 600 |
# Remove background if selected
|
| 601 |
if remove_bg:
|
| 602 |
try:
|
| 603 |
+
canvas_image = remove_background(canvas_image)
|
| 604 |
st.success("Background removed successfully!")
|
| 605 |
except Exception as e:
|
| 606 |
st.error(f"Background removal failed: {e}")
|
| 607 |
|
| 608 |
# Display the final image
|
| 609 |
+
st.image(canvas_image, caption="Edited Image", use_column_width=True)
|
| 610 |
|
| 611 |
# Download options
|
| 612 |
buffer = io.BytesIO()
|
| 613 |
+
canvas_image.save(buffer, format="PNG")
|
| 614 |
st.download_button(
|
| 615 |
label="📥 Download Edited Image",
|
| 616 |
data=buffer.getvalue(),
|