Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 3f720f02d2 |
10
app.py
10
app.py
@@ -1,7 +1,7 @@
|
|||||||
"""
|
"""
|
||||||
图片编辑器 - Image Editor v1.2.6
|
图片编辑器 - Image Editor v1.2.7
|
||||||
前端图片处理工具:合并、分割、挖孔填充、圆形切图、文字图片等
|
前端图片处理工具:合并、分割、挖孔填充、圆形切图、文字图片等
|
||||||
v1.2.6: 操作后显示预览效果,保留原始图片
|
v1.2.7: 修复合并图片紧密拼接问题
|
||||||
|
|
||||||
端口: 19018
|
端口: 19018
|
||||||
"""
|
"""
|
||||||
@@ -25,7 +25,7 @@ def index():
|
|||||||
|
|
||||||
@app.route('/api/health')
|
@app.route('/api/health')
|
||||||
def health():
|
def health():
|
||||||
return jsonify({'status': 'ok', 'version': '1.2.6', 'time': datetime.now().isoformat()})
|
return jsonify({'status': 'ok', 'version': '1.2.7', 'time': datetime.now().isoformat()})
|
||||||
|
|
||||||
@app.route('/api/save', methods=['POST'])
|
@app.route('/api/save', methods=['POST'])
|
||||||
def save_image():
|
def save_image():
|
||||||
@@ -64,9 +64,9 @@ def list_images():
|
|||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
print("=" * 50)
|
print("=" * 50)
|
||||||
print("图片编辑器 - Image Editor v1.2.6")
|
print("图片编辑器 - Image Editor v1.2.7")
|
||||||
print("=" * 50)
|
print("=" * 50)
|
||||||
print("操作后显示预览效果,保留原始图片")
|
print("修复合并图片紧密拼接问题")
|
||||||
print(f"访问地址: http://localhost:19018")
|
print(f"访问地址: http://localhost:19018")
|
||||||
print("=" * 50)
|
print("=" * 50)
|
||||||
app.run(host='0.0.0.0', port=19018, debug=True)
|
app.run(host='0.0.0.0', port=19018, debug=True)
|
||||||
BIN
outputs/edited_1776778260696.png
Normal file
BIN
outputs/edited_1776778260696.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 768 KiB |
BIN
outputs/edited_1776778342793.png
Normal file
BIN
outputs/edited_1776778342793.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 767 KiB |
BIN
outputs/edited_1776778549740.png
Normal file
BIN
outputs/edited_1776778549740.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 796 KiB |
@@ -3,7 +3,7 @@
|
|||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<title>图片编辑器 - Image Editor v1.2.6</title>
|
<title>图片编辑器 - Image Editor v1.2.7</title>
|
||||||
<script src="https://cdn.tailwindcss.com"></script>
|
<script src="https://cdn.tailwindcss.com"></script>
|
||||||
<link href="https://cdn.jsdelivr.net/npm/remixicon@3.5.0/fonts/remixicon.css" rel="stylesheet">
|
<link href="https://cdn.jsdelivr.net/npm/remixicon@3.5.0/fonts/remixicon.css" rel="stylesheet">
|
||||||
<style>
|
<style>
|
||||||
@@ -1081,20 +1081,76 @@
|
|||||||
return { width: size.width || item.width, height: size.height || item.height };
|
return { width: size.width || item.width, height: size.height || item.height };
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 计算画布尺寸
|
||||||
|
let canvasWidth = 0, canvasHeight = 0;
|
||||||
|
|
||||||
|
if (uniformSize) {
|
||||||
|
// 统一尺寸:使用固定单元格大小
|
||||||
let maxWidth = 0, maxHeight = 0;
|
let maxWidth = 0, maxHeight = 0;
|
||||||
state.mergeImageOrder.forEach(item => {
|
state.mergeImageOrder.forEach(item => {
|
||||||
const size = getActualSize(item);
|
const size = getActualSize(item);
|
||||||
maxWidth = Math.max(maxWidth, size.width);
|
maxWidth = Math.max(maxWidth, size.width);
|
||||||
maxHeight = Math.max(maxHeight, size.height);
|
maxHeight = Math.max(maxHeight, size.height);
|
||||||
});
|
});
|
||||||
|
canvasWidth = cols * maxWidth + (cols - 1) * gap;
|
||||||
|
canvasHeight = rows * maxHeight + (rows - 1) * gap;
|
||||||
|
} else {
|
||||||
|
// 不统一尺寸:紧密拼接,累加实际尺寸
|
||||||
|
if (direction === 'horizontal') {
|
||||||
|
// 横向:累加宽度,取最大高度
|
||||||
|
state.mergeImageOrder.forEach(item => {
|
||||||
|
const size = getActualSize(item);
|
||||||
|
canvasWidth += size.width + gap;
|
||||||
|
canvasHeight = Math.max(canvasHeight, size.height);
|
||||||
|
});
|
||||||
|
canvasWidth -= gap; // 去掉最后一个多余的gap
|
||||||
|
} else if (direction === 'vertical') {
|
||||||
|
// 纵向:累加高度,取最大宽度
|
||||||
|
state.mergeImageOrder.forEach(item => {
|
||||||
|
const size = getActualSize(item);
|
||||||
|
canvasHeight += size.height + gap;
|
||||||
|
canvasWidth = Math.max(canvasWidth, size.width);
|
||||||
|
});
|
||||||
|
canvasHeight -= gap;
|
||||||
|
} else {
|
||||||
|
// 网格:每行累加宽度,累加行高度
|
||||||
|
for (let r = 0; r < rows; r++) {
|
||||||
|
let rowWidth = 0, rowHeight = 0;
|
||||||
|
for (let c = 0; c < cols; c++) {
|
||||||
|
const idx = r * cols + c;
|
||||||
|
if (idx < state.mergeImageOrder.length) {
|
||||||
|
const size = getActualSize(state.mergeImageOrder[idx]);
|
||||||
|
rowWidth += size.width + gap;
|
||||||
|
rowHeight = Math.max(rowHeight, size.height);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
rowWidth -= gap;
|
||||||
|
canvasWidth = Math.max(canvasWidth, rowWidth);
|
||||||
|
canvasHeight += rowHeight + gap;
|
||||||
|
}
|
||||||
|
canvasHeight -= gap;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
canvas.width = cols * maxWidth + (cols - 1) * gap;
|
canvas.width = canvasWidth;
|
||||||
canvas.height = rows * maxHeight + (rows - 1) * gap;
|
canvas.height = canvasHeight;
|
||||||
|
|
||||||
// 绘制合并结果到画布(预览)
|
// 绘制合并结果到画布(预览)
|
||||||
ctx.fillStyle = bgColor;
|
ctx.fillStyle = bgColor;
|
||||||
ctx.fillRect(0, 0, canvas.width, canvas.height);
|
ctx.fillRect(0, 0, canvas.width, canvas.height);
|
||||||
|
|
||||||
|
// 绘制图片
|
||||||
|
let currentX = 0, currentY = 0;
|
||||||
|
|
||||||
|
if (uniformSize) {
|
||||||
|
// 统一尺寸:固定单元格,居中绘制
|
||||||
|
let maxWidth = 0, maxHeight = 0;
|
||||||
|
state.mergeImageOrder.forEach(item => {
|
||||||
|
const size = getActualSize(item);
|
||||||
|
maxWidth = Math.max(maxWidth, size.width);
|
||||||
|
maxHeight = Math.max(maxHeight, size.height);
|
||||||
|
});
|
||||||
|
|
||||||
state.mergeImageOrder.forEach((orderItem, index) => {
|
state.mergeImageOrder.forEach((orderItem, index) => {
|
||||||
if (index >= cols * rows) return;
|
if (index >= cols * rows) return;
|
||||||
const col = index % cols;
|
const col = index % cols;
|
||||||
@@ -1110,6 +1166,33 @@
|
|||||||
ctx.drawImage(originalImg.img, x + offsetX, y + offsetY, size.width, size.height);
|
ctx.drawImage(originalImg.img, x + offsetX, y + offsetY, size.width, size.height);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
} else {
|
||||||
|
// 不统一尺寸:紧密拼接,无居中偏移
|
||||||
|
state.mergeImageOrder.forEach((orderItem, index) => {
|
||||||
|
const size = getActualSize(orderItem);
|
||||||
|
const originalImg = state.images.find(img => img.name === orderItem.name);
|
||||||
|
|
||||||
|
if (!originalImg) return;
|
||||||
|
|
||||||
|
if (direction === 'horizontal') {
|
||||||
|
ctx.drawImage(originalImg.img, currentX, 0, size.width, size.height);
|
||||||
|
currentX += size.width + gap;
|
||||||
|
} else if (direction === 'vertical') {
|
||||||
|
ctx.drawImage(originalImg.img, 0, currentY, size.width, size.height);
|
||||||
|
currentY += size.height + gap;
|
||||||
|
} else {
|
||||||
|
// 网格模式
|
||||||
|
const col = index % cols;
|
||||||
|
const row = Math.floor(index / cols);
|
||||||
|
if (col === 0) currentX = 0;
|
||||||
|
ctx.drawImage(originalImg.img, currentX, currentY, size.width, size.height);
|
||||||
|
currentX += size.width + gap;
|
||||||
|
if (col === cols - 1 || index === state.mergeImageOrder.length - 1) {
|
||||||
|
currentY += size.height + gap;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// 显示预览效果(不清除原始图片)
|
// 显示预览效果(不清除原始图片)
|
||||||
const mergedData = canvas.toDataURL('image/png');
|
const mergedData = canvas.toDataURL('image/png');
|
||||||
|
|||||||
Reference in New Issue
Block a user