【教学类-34-12】20250509(通义万相)4*3蝴蝶拼图(圆形、三角、正方、半圆的凹凸小块+数字提示+参考图灰色)

发布于:2025-05-10 ⋅ 阅读:(24) ⋅ 点赞:(0)

背景介绍

制作了四款异形角拼图,初步实现效果

【教学类-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 // wide

def 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.size
    draw = 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:
                            continue
                        nx, ny = x + dx, y + dy
                        if 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 img

def SplitImages(img_path, row, col):
    """分割原始图片为row×col的小图"""
    img = Image.open(img_path).convert("RGBA")
    imgSize = img.size
    splitW = 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 imbList

def 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_im

def SplitCircle(imbList, imgPath, output_folder):
    """生成凹凸拼图效果并直接保存到目标文件夹"""
    img = Image.open(imgPath).convert("RGBA")
    imgSize = img.size
    col = 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) * 2
    pSplitL = splitL + (r_d + r_offset) * 2
    pimg = 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 = imbImg
            lrRight = 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))) ** yangshi
                        if 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))) ** yangshi
                        if 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 + j
            file_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_images

def 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 + col
            small_img = small_images[index]
            cell_center_x = col * cell_width + cell_width // 2
            cell_center_y = row * cell_height + cell_height // 2
            paste_x = cell_center_x - small_img.width // 2
            paste_y = cell_center_y - small_img.height // 2
            canvas.alpha_composite(small_img, (paste_x, paste_y))
    
    gray_canvas = convert_to_light_gray(canvas)
    gray_canvas.save(output_path)
    return output_path

import 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 random

def 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 = 12
    if 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.4cm
            paragraph.alignment = WD_PARAGRAPH_ALIGNMENT.CENTER

    # 第二个表格: 插入序号 (3行4列)
    table2 

网站公告

今日签到

点亮在社区的每一天
去签到