Spaces:
Running
Running
File size: 7,822 Bytes
724aa84 5f6ef81 724aa84 5f6ef81 724aa84 5f6ef81 59cbef2 5f6ef81 59cbef2 5f6ef81 59cbef2 5f6ef81 ecfbfd1 59cbef2 5f6ef81 59cbef2 5f6ef81 59cbef2 ecfbfd1 59cbef2 ecfbfd1 5f6ef81 724aa84 5f6ef81 724aa84 5f6ef81 ecfbfd1 5f6ef81 724aa84 ecfbfd1 724aa84 5f6ef81 ecfbfd1 724aa84 5f6ef81 724aa84 5f6ef81 724aa84 5f6ef81 ecfbfd1 5f6ef81 d935ae6 5f6ef81 ecfbfd1 5f6ef81 724aa84 5f6ef81 ecfbfd1 724aa84 5f6ef81 ecfbfd1 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 |
import gradio as gr
import numpy as np
from PIL import Image
import io
import tempfile
import os
def resize_images_to_match(images, resize_mode="height"):
if not images or len(images) == 0:
return []
valid_images = [img for img in images if img is not None]
if not valid_images:
return []
if resize_mode == "height":
target_height = min(img.size[1] for img in valid_images)
resized_images = []
for img in valid_images:
aspect_ratio = img.size[0] / img.size[1]
new_width = int(target_height * aspect_ratio)
resized_img = img.resize((new_width, target_height), Image.Resampling.LANCZOS)
resized_images.append(resized_img)
else:
target_width = min(img.size[0] for img in valid_images)
resized_images = []
for img in valid_images:
aspect_ratio = img.size[1] / img.size[0]
new_height = int(target_width * aspect_ratio)
resized_img = img.resize((target_width, new_height), Image.Resampling.LANCZOS)
resized_images.append(resized_img)
return resized_images
def concatenate_images(images, direction="horizontal", spacing=0, background_color="white"):
if not images or len(images) == 0:
return None
valid_images = [img for img in images if img is not None]
if not valid_images:
return None
rgb_images = []
for img in valid_images:
if img.mode != 'RGB':
if img.mode in ('RGBA', 'LA'):
background = Image.new('RGB', img.size, 'white')
background.paste(img, mask=img.split()[-1] if img.mode == 'RGBA' else None)
rgb_images.append(background)
else:
rgb_images.append(img.convert('RGB'))
else:
rgb_images.append(img)
if len(rgb_images) == 1:
return rgb_images[0]
if direction == "horizontal":
total_width = sum(img.size[0] for img in rgb_images) + spacing * (len(rgb_images) - 1)
max_height = max(img.size[1] for img in rgb_images)
result = Image.new('RGB', (total_width, max_height), background_color)
x_offset = 0
for img in rgb_images:
y_offset = (max_height - img.size[1]) // 2
result.paste(img, (x_offset, y_offset))
x_offset += img.size[0] + spacing
else:
max_width = max(img.size[0] for img in rgb_images)
total_height = sum(img.size[1] for img in rgb_images) + spacing * (len(rgb_images) - 1)
result = Image.new('RGB', (max_width, total_height), background_color)
y_offset = 0
for img in rgb_images:
x_offset = (max_width - img.size[0]) // 2
result.paste(img, (x_offset, y_offset))
y_offset += img.size[1] + spacing
return result
def save_as_jpg(image, quality=95):
if image is None:
return None
if image.mode != 'RGB':
if image.mode in ('RGBA', 'LA'):
background = Image.new('RGB', image.size, 'white')
background.paste(image, mask=image.split()[-1])
image = background
else:
image = image.convert('RGB')
buffer = io.BytesIO()
image.save(buffer, format='JPEG', quality=quality, optimize=True)
buffer.seek(0)
return Image.open(buffer)
def process_images(
image1, image2, image3, image4, image5, image6,
resize_mode, concat_direction, spacing, bg_color, jpg_quality
):
uploaded_images = [image1, image2, image3, image4, image5, image6]
valid_images = [img for img in uploaded_images if img is not None]
if len(valid_images) == 0:
return None, "❌ 請至少上傳一張圖片", None
if len(valid_images) == 1:
return valid_images[0], f"✅ 只有一張圖片,無需拼接", None
try:
if resize_mode == "等高度 (水平拼接)":
resized_images = resize_images_to_match(valid_images, "height")
direction = "horizontal"
else:
resized_images = resize_images_to_match(valid_images, "width")
direction = "vertical"
if concat_direction != "自動 (根據調整模式)":
direction = "horizontal" if concat_direction == "水平拼接" else "vertical"
result = concatenate_images(resized_images, direction, spacing, bg_color)
if result is None:
return None, "❌ 拼接失敗", None
result = save_as_jpg(result, quality=jpg_quality)
temp_path = os.path.join(tempfile.gettempdir(), "result.jpg")
result.save(temp_path, format="JPEG", quality=jpg_quality)
info = f"✅ 成功拼接 {len(valid_images)} 張圖片\n"
info += f"📐 最終尺寸: {result.size[0]} x {result.size[1]} 像素\n"
info += f"🔄 調整模式: {resize_mode}\n"
info += f"➡️ 拼接方向: {'水平' if direction == 'horizontal' else '垂直'}\n"
info += f"📏 間距: {spacing} 像素\n"
info += f"💾 輸出品質: {jpg_quality}%"
return result, info, temp_path
except Exception as e:
return None, f"❌ 處理過程中出現錯誤: {str(e)}", None
def create_interface():
with gr.Blocks(title="圖片拼接比較工具", theme=gr.themes.Soft()) as iface:
gr.Markdown("# 🖼️ 圖片拼接比較工具")
with gr.Row():
with gr.Column(scale=2):
gr.Markdown("### 📁 上傳圖片")
with gr.Row():
image1 = gr.Image(type="pil", label="圖片 1")
image2 = gr.Image(type="pil", label="圖片 2")
image3 = gr.Image(type="pil", label="圖片 3")
with gr.Row():
image4 = gr.Image(type="pil", label="圖片 4")
image5 = gr.Image(type="pil", label="圖片 5")
image6 = gr.Image(type="pil", label="圖片 6")
gr.Markdown("### ⚙️ 處理設定")
with gr.Row():
resize_mode = gr.Dropdown(
choices=["等高度 (水平拼接)", "等寬度 (垂直拼接)"],
value="等高度 (水平拼接)",
label="尺寸調整模式"
)
concat_direction = gr.Dropdown(
choices=["自動 (根據調整模式)", "水平拼接", "垂直拼接"],
value="自動 (根據調整模式)",
label="拼接方向"
)
with gr.Row():
spacing = gr.Slider(0, 50, value=2, step=1, label="圖片間距 (像素)")
bg_color = gr.Dropdown(
choices=["white", "black", "gray"],
value="white",
label="背景顏色"
)
jpg_quality = gr.Slider(60, 100, value=95, step=5, label="JPG 輸出品質 (%)")
process_btn = gr.Button("🚀 開始處理", variant="primary", size="lg")
with gr.Column(scale=2):
gr.Markdown("### 🎯 處理結果")
result_image = gr.Image(type="pil", label="拼接結果")
result_info = gr.Textbox(label="處理信息", lines=6, max_lines=10)
result_file = gr.File(label="下載 JPG 檔案")
process_btn.click(
fn=process_images,
inputs=[image1, image2, image3, image4, image5, image6,
resize_mode, concat_direction, spacing, bg_color, jpg_quality],
outputs=[result_image, result_info, result_file]
)
return iface
if __name__ == "__main__":
app = create_interface()
app.launch(server_name="0.0.0.0", server_port=7860, share=True)
|