【教学类-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 // 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 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

阿夏reasonsummer

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值