【教学类-34-12】20250509(通义万相)4*3蝴蝶拼图(圆形、三角、正方、半圆的凹凸小块+数字提示+参考图灰色)
背景介绍
制作了四款异形角拼图,初步实现效果
【教学类-34-10】20250503(通义万相)4*3蝴蝶拼图(圆形、三角、正方、半圆的凹凸小块+参考图灰色)-CSDN博客文章浏览阅读1.4k次,点赞46次,收藏15次。【教学类-34-10】20250503(通义万相)4*3蝴蝶拼图(圆形、三角、正方、半圆的凹凸小块+参考图灰色)https://blog.csdn.net/reasonsummer/article/details/147654458?sharetype=blogdetail&sharerId=147654458&sharerefer=PC&sharesource=reasonsummer&spm=1011.2480.3001.8118
存在问题
拼图多了,切开来,搞不清楚是那个蝴蝶的拼图的图片。
所以我需要在拼图块后面画上数字。
WORD模版
代码展示
1、圆形凹凸拼图3:4+数字编号+灰色参考图
'''
目的:3*4彩色拼图(圆形凹凸),+背面数字编号,有灰色参考图,插入WORD,
作者:deepseek,阿夏
时间:20250503
'''import os
import time
import random
from PIL import Image, ImageDraw, ImageEnhance
from docx import Document
from docx.shared import Cm, Pt
from docx.shared import RGBColor
from docx.enum.text import WD_PARAGRAPH_ALIGNMENT
from docx.oxml.ns import qn
from docx2pdf import convert# sj=int(input('1:顺序插入、2:乱序\n'))
# 配置参数
yangshi = 0.56
wide = 3
high = 4
Number = wide * high
border_width = 5 # 5磅黑色实线# 路径设置
path = r'D:\20250506彩色蝴蝶无白色'
prz = os.path.join(path, "01图片")
pathz = [os.path.join(prz, f) for f in os.listdir(prz) if f.endswith(".png")]
print(f"找到{len(pathz)}张原始图片")# 画布尺寸配置
canvas_width = 2830 # 画布宽度
canvas_height = 1950 # 画布高度
cell_width = canvas_width // high
cell_height = canvas_height // widedef convert_to_light_gray(image):"""将图像转为浅灰色(保留透明度)"""# 转为灰度图gray = image.convert('L')# 提高亮度enhancer = ImageEnhance.Brightness(gray)light_gray = enhancer.enhance(1.9)# 合并回RGBA图像return Image.merge('RGBA', (light_gray, light_gray, light_gray, image.split()[3]))def draw_border_on_edge(img, border_width=5):"""在透明与非透明交界处绘制黑色实线"""img = img.convert("RGBA")width, height = img.sizedraw = ImageDraw.Draw(img)pixels = img.load()edge_map = set()# 找出所有边缘像素for x in range(width):for y in range(height):if pixels[x, y][3] > 0: # 如果当前像素不透明for dx in [-1, 0, 1]:for dy in [-1, 0, 1]:if dx == 0 and dy == 0:continuenx, ny = x + dx, y + dyif 0 <= nx < width and 0 <= ny < height:if pixels[nx, ny][3] == 0: # 相邻像素透明edge_map.add((x, y))break# 在边缘像素处绘制黑线for x, y in edge_map:for i in range(max(0, x-border_width//2), min(width, x+border_width//2+1)):for j in range(max(0, y-border_width//2), min(height, y+border_width//2+1)):if (i - x)**2 + (j - y)**2 <= (border_width//2)**2:draw.point((i, j), fill=(0, 0, 0, 255))return imgdef SplitImages(img_path, row, col):"""分割原始图片为row×col的小图"""img = Image.open(img_path).convert("RGBA")imgSize = img.sizesplitW = int(imgSize[0]/col)splitL = int(imgSize[1]/row)pimg = img.load()imbList = []for i in range(row):rowList = []for j in range(col):imb = Image.new('RGBA', (splitW, splitL), (255,255,255,0))pimb = imb.load()for k in range(j * splitW, (j + 1) * splitW):for z in range(i * splitL, (i + 1) * splitL):pimb[k - j * splitW, z - i * splitL] = pimg[k,z]rowList.append(imb)imbList.append(rowList)return imbListdef Resize(img, rizeW, rizel, pastePoint=None): """调整图像大小"""if pastePoint is None:pastePoint = [0, 0]new_im = Image.new('RGBA', [rizeW, rizel], (255,255,255,0))new_im.paste(img, pastePoint)return new_imdef SplitCircle(imbList, imgPath, output_folder):"""生成凹凸拼图效果并直接保存到目标文件夹"""img = Image.open(imgPath).convert("RGBA")imgSize = img.sizecol = len(imbList[0])row = len(imbList)splitW = int(imgSize[0]/col)splitL = int(imgSize[1]/row)minV = min(splitW, splitL)r_d = int(minV / 4)r_offset = int(minV / 8)pSplitW = splitW + (r_d + r_offset) * 2pSplitL = splitL + (r_d + r_offset) * 2pimg = img.load()pointList = []for i in range(row):colPointList = []for j in range(col):colPoint = []rowPoint = []if j != col - 1:colPoint = [splitW * (j + 1), int(splitL/2) + i * splitL]if i != row - 1:rowPoint = [int(splitW / 2) + j * splitW, splitL * (i + 1)]colPointList.append({'colPoint': colPoint, 'rowPoint': rowPoint})imbList[i][j] = Resize(imbList[i][j], pSplitW, pSplitL, [r_d + r_offset, r_d + r_offset])pointList.append(colPointList)small_images = []for i in range(row):for j in range(col):imbImg = imbList[i][j]new_img = imbImglrRight = random.choice([True, False])drRight = random.choice([True, False])new_img_imb = new_img.load()if j != col - 1:new_next_img = imbList[i][j + 1]new_next_img_imb = new_next_img.load()for k in range((j + 1) * splitW - (0 if lrRight else r_d + r_offset), (j + 1) * splitW + (r_d + r_offset if lrRight else 0)):for z in range(i * splitL, (i + 1) * splitL):r_w = pointList[i][j]['colPoint'][0] + (r_offset if lrRight else -r_offset)r_l = pointList[i][j]['colPoint'][1]r = ((pow(abs(k - r_w),2) + pow(abs(z - r_l),2))) ** yangshiif r < r_d:if lrRight:new_img_imb[k - j * splitW + r_d + r_offset, z - i * splitL + r_d + r_offset] = pimg[k, z]new_next_img_imb[k - (j + 1) * splitW + r_d + r_offset, z - i * splitL + r_d + r_offset] = (255,255,255,0)else:new_next_img_imb[k - (j + 1) * splitW + r_d + r_offset, z - i * splitL + r_d + r_offset] = pimg[k, z]new_img_imb[k - j * splitW + r_d + r_offset, z - i * splitL + r_d + r_offset] = (255,255,255,0)imbList[i][j + 1] = new_next_img if i != row - 1:new_down_img = imbList[i + 1][j]new_down_img_imb = new_down_img.load()for k in range(j * splitW, (j + 1) * splitW):for z in range((i + 1) * splitL - (r_d + r_offset if not drRight else 0), (i + 1) * splitL + (0 if not drRight else r_d + r_offset)):r_w = pointList[i][j]['rowPoint'][0]r_l = pointList[i][j]['rowPoint'][1] + (r_offset if drRight else -r_offset)r = ((pow(abs(k - r_w),2) + pow(abs(z - r_l),2))) ** yangshiif r < r_d:if drRight:new_img_imb[k - j * splitW + r_d + r_offset, z - i * splitL + r_d + r_offset] = pimg[k, z]new_down_img_imb[k - j * splitW + r_d + r_offset, z - (i + 1) * splitL + r_d + r_offset] = (255,255,255,0)else:new_down_img_imb[k - j * splitW + r_d + r_offset, z - (i + 1) * splitL + r_d + r_offset] = pimg[k, z]new_img_imb[k - j * splitW + r_d + r_offset, z - i * splitL + r_d + r_offset] = (255,255,255,0)imbList[i + 1][j] = new_down_img# 直接保存小图到目标文件夹idx = i * high + jfile_path = os.path.join(output_folder, f"{idx:02d}.png")new_img.save(file_path)img_with_border = draw_border_on_edge(Image.open(file_path), border_width)img_with_border.save(file_path)small_images.append(Image.open(file_path).convert('RGBA'))return small_imagesdef generate_combined_image(small_images, output_path):"""生成组合图"""canvas = Image.new('RGBA', (canvas_width, canvas_height), (255, 255, 255, 0))for row in range(wide):for col in range(high):index = row * high + colsmall_img = small_images[index]cell_center_x = col * cell_width + cell_width // 2cell_center_y = row * cell_height + cell_height // 2paste_x = cell_center_x - small_img.width // 2paste_y = cell_center_y - small_img.height // 2canvas.alpha_composite(small_img, (paste_x, paste_y))gray_canvas = convert_to_light_gray(canvas)gray_canvas.save(output_path)return output_pathimport os
from docx import Document
from docx.shared import Cm, Pt
from docx.enum.text import WD_PARAGRAPH_ALIGNMENT
from docx.oxml.ns import qn
import randomdef generate_word_doc(small_images, combined_path, output_docx_path, img_index, sj=1):'''生成Word文档参数:small_images: 小图路径列表combined_path: 组合图路径output_docx_path: 输出的Word文档路径img_index: 当前处理的原图序号sj: 1表示按默认顺序插入,2表示随机打乱插入顺序'''# 假设path、wide、high、Number是全局变量# 加载模板文档template_path = os.path.join(path, f'02长方形模板{wide}乘{high}.docx')doc = Document(template_path)# 确保文档中有至少三个表格# if len(doc.tables) < 3:# raise ValueError("模板文档必须包含至少三个表格")# 创建索引列表indices = list(range(Number)) # Number = wide * high = 12if sj == 2: # 随机打乱顺序random.shuffle(indices)else:pass# 第一个表格: 插入12张小图 (3行4列)table1 = doc.tables[0]for row in range(wide):for col in range(high):# 获取索引(随机或顺序)idx = indices[row * high + col] if sj == 2 else (row * high + col)cell = table1.cell(row, col)# 清除单元格原有内容for paragraph in cell.paragraphs:for run in paragraph.runs:run.clear()# 添加新图片paragraph = cell.paragraphs[0]run = paragraph.add_run()# 图片名称img_path = os.path.join(os.path.dirname(combined_path), f"{idx:02d}.png")run.add_picture(img_path, width=Cm(6.71), height=Cm(6.4)) # 宽度6.71cm, 高度6.4cmparagraph.alignment = WD_PARAGRAPH_ALIGNMENT.CENTER# 第二个表格: 插入序号 (3行4列)table2