背景需求:
在Python学具设计的过程中,阿夏努力从大班主题教学活动书上寻找适宜的内容。春夏与秋冬主题下有一个《春天拼图》,拼图是大班孩子非常喜欢的一种游戏玩具,个别化学习中已经提供“方块拼图”、"凹凸积木块拼图”、“俄罗斯方块图” 多种拼图块。
阿夏希望能够把孩子们自己绘画的作品,批量生成“方块”“凹凸块”“俄罗斯”等积木块。经过一个月的代码收集、反复测试。优化流程,终于将单张图片变成了想要的“4*6格横版拼图”。
操作过程
文件预设:
由于代码里面有十几条的路径设置,请一模一样地在桌面上word2pdf2png新建文件夹,并放入“图片.jpg、文件夹:拼图、文件夹:照片调整、代码.py”??
复制代码
name=input('请输入图片的名称\n')
geshi=input('请输入图片格式(小写)\n')
yangshi=float(input('输入造型数字 1:适宜0.56;2:纯方块:7\n'))
pic_width=int(input('请输入底边像素\n'))# 长度 把MB图片缩小一点,生成的拼图块格式也小一点1024
pic_height=int(input('请输入侧边像素\n'))# 宽度768
pic_puzzle_longnum=int(input('请输入侧边的积木块数量\n'))# 积木块数量4*6=12块 中的4 768
pic_puzzle_shortnum=int(input('请输入底边的积木块数量\n'))# 积木块数量4*6=12块 中的6 1024
pic_puzzle_side_long=float(input('请输入word里面积木块图片的长度\n'))# 小拼图块的长度 1.5正方形
pic_puzzle_side_short=float(input('请输入word里面积木块图片的宽度\n'))# 小拼图块的宽度 1.5正方形
fenlan=int(input('请输入word里面分栏数量\n'))# 1.5 4*6时 6列
'''
A4短边 最多4格,1.7
3格 2.3
2格 3.6
拼贴后的作品只有A4一半大小
项目1:横版照片
造型:0.56凹凸,7方形
样式:4:3
像素:1024*768
格子:4*6=24块
积木块长宽:1.7*1.7
分栏:6
项目2:横版照片 16宫格照片
样式:1:1
像素:1024*1024
格子:4*4
积木块长宽:1.7*1.7
分栏:5
项目3:横版照片 9宫格照片
样式:1:1
像素:1024*1024
格子:3*3
积木块长宽:2.3*2.3
分栏:3
(比4*6图片小)
项目4:横版照片 4宫格照片
样式:1:1
像素:1024*1024
格子:2*2
积木块长宽:3.6*3.6
分栏:2
(比4*6图片小)
2张A4打印纸
成品a4一半
项目1:横版照片
造型:0.56凹凸,7方形
样式:4:3
像素:1024*768
格子:4*6=24块
积木块长宽:2.3*2.3
分栏:4
'''
# pic=['jpg','png','tif']
# for i in pic:
# # print(i)
# geshi.append(i)
# print(geshi)
# bmp,jpg,png,tif,gif,pcx,tga,exif,fpx,svg,psd,
# cdr,pcd,dxf,ufo,eps,ai,raw,WMF,webp,avif,apng 等。”
print('------第一部分:把照片缩小格式(4:3横版、3:4竖版、1:1九宫格-------')
# 先缩小图片格式,这样导出的拼图块们的容量小一点(适合打印版本A4)
# 不用第一部分,每张拼图块图片很大,4MB照片拆分24张,每张1MB(适合电子白板教学,高清图片)
'''作者:幸福清风https://blog.csdn.net/xun527/article/details/117085712'''
from PIL import Image
import os.path
import glob
def convertjpg(jpgfile,outdir,width=pic_width,height=pic_height): #横版本 把 16-266KB的照片转换成540*405像素,照片大小16*43KB,拆分后正好4*6一页
# def convertjpg(jpgfile,outdir,width=405,height=540): #竖版照片 把 16-266KB的照片转换成540*405像素,照片大小16*43KB,拆分后正好4*6一页
# 400*300宽高像素 15-24K
# 520*390宽高像素 29-30K
# 1024,height=768 哪怕只有45K,也是格子很大
img=Image.open(jpgfile)
try:
new_img=img.resize((width,height),Image.BILINEAR)
if not os.path.exists(outdir):
os.mkdir(outdir)
new_img.save(os.path.join(outdir,os.path.basename(jpgfile)))
except Exception as e:
print(e)
'''单张照片()'''
path = r"C:\Users\Administrator\Desktop\word2pdf2png\{}.{}".format(name,geshi)# 来源
for jpgfile in glob.glob(path):
convertjpg(jpgfile,r"C:\Users\Administrator\Desktop\word2pdf2png\照片调整")# 去向
# '''# 全部照片'''
# path = r"C:\Users\Administrator\Desktop\word2pdf2png\原图\*.{}".format(geshi)
# for jpgfile in glob.glob(path):
# convertjpg(jpgfile,r"C:\Users\Administrator\Desktop\word2pdf2png\照片调整")
print('------第二部分:生成带凹凸拼图-------')
'''https://blog.csdn.net/zbbzb/article/details/120127932 作者:zbbzb'''
import os
from PIL import Image
# 分隔成n*m个方块
# 分割几行几列, 二维数组保存
def SplitImages(img_path, row, col):
path_name = os.path.dirname(img_path)
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 = []
l = (i + 1) * splitL
for j in range(col):
w = (j + 1) * splitW
imb = Image.new('RGBA', (splitW, splitL),(255,255,255,0))
pimb = imb.load()
for k in range(j * splitW, w):
for z in range(i * splitL, l):
pimb[k - splitW * j, z - i * splitL] = pimg[k,z]
dirPath = path_name + "/" + str(i*10 + j) + ".png"
# imb.save(dirPath)
rowList.append(imb)
imbList.append(rowList)
return imbList
# 最终版:随机凹凸, 考虑圆心偏移
import os
from PIL import Image
import random
# 分割几行几列, 二维数组保存
def SplitImages(img_path, row, col):
path_name = os.path.dirname(img_path)
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 = []
l = (i + 1) * splitL
for j in range(col):
w = (j + 1) * splitW
imb = Image.new('RGBA', (splitW, splitL),(255,255,255,0))
pimb = imb.load()
for k in range(j * splitW, w):
for z in range(i * splitL, l):
pimb[k - splitW * j, z - i * splitL] = pimg[k,z]
dirPath = path_name + "/" + str(i*10 + j) + ".png"
# imb.save(dirPath)
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):
path_name = os.path.dirname(imgPath)
img = Image.open(imgPath).convert("RGBA")
imgSize = img.size
col = len(imbList[0])
row = len(imbList)
if col == 1 and row == 1:
return
splitW = int(imgSize[0]/col)
splitL = int(imgSize[1]/row)
minV = min(splitW, splitL)
r_d = int(minV / 4) # 要计算 两个不能比 l 长 并且加上 offset 也不能超过 l
r_offset = int(minV / 8)
pSplitW = splitW + (r_d + r_offset) * 2
pSplitL = splitL + (r_d + r_offset) * 2
pimg = img.load()
# 存(row - 1) * (col - 1) 个中心点
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])
dirPath = path_name + "/" + str(i*10 + j) + ".png"
# imbList[i][j].save(dirPath)
pointList.append(colPointList)
for i in range(row):
for j in range(col):
imbImg = imbList[i][j]
new_img = imbImg
# 圆心靠左 靠右, 默认靠右
lrandNum = random.randint(0, 999999)
drandNum = random.randint(0, 999999)
lrRight = True
drRight = True
if lrandNum < 500000:
lrRight = False
if drandNum < 500000:
drRight = False
new_img_imb = new_img.load()
if j != col - 1:
if lrRight :
new_next_img = imbList[i][j + 1]
new_next_img_imb = new_next_img.load()
# 左右
for k in range((j + 1) * splitW, (j + 1) * splitW + r_d + r_offset):
for z in range(i * splitL, (i + 1) * splitL):
r_w = pointList[i][j]['colPoint'][0] + r_offset
r_l = pointList[i][j]['colPoint'][1]
r = ((pow(abs(k - r_w),2) + pow(abs(z - r_l),2))) ** yangshi
# 凹凸圆球的直径,作者原设置0.5,感觉三个凹型的拼图连接地方太细了,幼儿容易剪断,所以这里改成0.55
# 测试结果:0.3不规则矩形块(图形类似俄罗斯方块)
# 0.7 方块,四周 有很小的圆点(不连接) 内部有很小空心圆点(适合电子版)
# 0.6 方块,四周 有很大的圆点(不连接) 内部有很小空心圆点(适合电子版)
if r < r_d:
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)
imbList[i][j + 1] = new_next_img
else:
new_next_img = imbList[i][j + 1]
new_next_img_imb = new_next_img.load()
# 左右
for k in range((j + 1) * splitW - r_d - r_offset, (j + 1) * splitW):
for z in range(i * splitL, (i + 1) * splitL):
r_w = pointList[i][j]['colPoint'][0] - 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:
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:
if drRight:
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, (i + 1) * splitL + r_d + r_offset):
r_w = pointList[i][j]['rowPoint'][0]
r_l = pointList[i][j]['rowPoint'][1] + r_offset
r = ((pow(abs(k - r_w),2) + pow(abs(z - r_l),2))) ** yangshi
if r < r_d:
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)
imbList[i + 1][j] = new_down_img
else:
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, (i + 1) * splitL):
r_w = pointList[i][j]['rowPoint'][0]
r_l = pointList[i][j]['rowPoint'][1] - r_offset
r = ((pow(abs(k - r_w),2) + pow(abs(z - r_l),2))) ** yangshi
if r < r_d:
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
imbList[i][j] = new_img
for i in range(row):
for j in range(col):
dirPath = r"C:/Users/Administrator/Desktop/word2pdf2png" + "/拼图/" + str(i*10 + j) + ".png"
# 在路径下的“拼图”文件夹下
#
imbList[i][j].save(dirPath)
if __name__ == '__main__':
dirPath =r"C:/Users/Administrator/Desktop/word2pdf2png/照片调整/"
SplitCircle(SplitImages(dirPath + "{}.{}".format(name,geshi), pic_puzzle_longnum, pic_puzzle_shortnum) , dirPath + "{}.{}".format(name,geshi))
# 横版高4长6
# 第一个数字是高度4张图片 第二个数字是宽度3张
'''
71.8KB的图片4*6 24张3*8摆放在word 上下左右 1 1 1 1
'''
print('-----第三部分:拼图块导入docx打印-----')
'''
https://blog.csdn.net/qq_44354520/article/details/103831685?ops_request_misc=&request_id=&biz_id=102&utm_term=python%E5%A4%8D%E5%88%B6%E5%9B%BE%E7%89%87%E5%88%B0word&utm_medium=distribute.pc_search_result.none-task-blog-2~all~sobaiduweb~default-5-103831685.nonecase&spm=1018.2226.3001.4187
Linear Algebra and Geometry
'''
import time
from docx.shared import Cm # 导入cm模块
from docx import Document
from docx.shared import Inches
import os
from PIL import Image
from pygame import PixelArray
import docx
from docx import Document
from docx.shared import Pt
from docx.shared import RGBColor
from docx.enum.text import WD_PARAGRAPH_ALIGNMENT
from docx.oxml.ns import qn
# 要插入的图片所在的文件夹
fold='C:\\Users\\Administrator\\Desktop\\word2pdf2png\\拼图\\'
# , dirs和pics是list类型
for root, dirs, pics in os.walk(fold):
# doc=Document('页码.docx') # 带页码模板
doc=Document()
# 设置打印纸的基本格式——页边距
from docx.shared import Cm # 导入cm模块
doc.sections[0].top_margin = Cm(1)# sections[1]是第二节=第二页 上边距
doc.sections[0].bottom_margin = Cm(1)# sections[1]是第二节=第二页 下边距
doc.sections[0].left_margin = Cm(1) # sections[1]是第二节=第二页 左边距
doc.sections[0].right_margin = Cm(1)# sections[1]是第二节=第二页 右边距
# 设置其他页边距
doc.sections[0].gutter=Cm(0)# sections[1]是第二节=第二页 装订线 默认为0 左
doc.sections[0].header_distance=Cm(0)# sections[1]是第二节=第二页 页眉边距
doc.sections[0].footer_distance=Cm(0)# sections[1]是第二节=第二页 页脚边距
# 装订线还有一个位置属性,暂时未发现如何设置,默认为左,如果需求设置成右,可以建个模板docx文档导入。
# 设置纸张方向和大小 LANDSCAPE=横 PORTRAIT纵 默认信纸 纵
from docx.shared import Cm # 导入CM #
from docx.enum.section import WD_ORIENTATION # 导入纸张方向
doc.sections[0].page_height = Cm(21) # 设置A4纸的高度
doc.sections[0].page_width = Cm(29.7) # 设置A4纸的宽
doc.sections[0].orientation = WD_ORIENTATION.LANDSCAPE # 设置纸张方向为横向 L
# 行距
# doc.paragraph.paragraph_format.line_spacing = 0.1 #数字段间距
# 分栏
from docx.oxml.ns import qn
doc.sections[0]._sectPr.xpath('./w:cols')[0].set(qn('w:num'),'{}'.format(fenlan)) #把fenlan分栏设置为2栏
for i in range(0,len(pics)):
#不需要把文件后缀名去掉,后面的PIL库里的open可以直接识别出文件名后缀
# print(pics[i],'\n')
# pics[i] = os.path.splitext(pics[i])[0]
# print(pics[i], '\n')春天拼图
#我前半部分的路径直接复制黏贴了,没用root和dirs
filepath = 'C:\\Users\\Administrator\\Desktop\\word2pdf2png\\拼图\\'+pics[i]
# filepath = root + '\\' + str(pics[i])
try:
# doc.add_picture(filepath,width=Pixel(156),height=Pixel(167))
doc.add_picture(filepath,width=Inches(pic_puzzle_side_long),height=Inches(pic_puzzle_side_short))
# 这里是插入图片的固定尺寸,小图也会变大
except Exception:
pic_tmp=Image.open(filepath)
# 如果格式有问题,就用save转换成默认的jpg格式
pic_tmp.save(pic_tmp)
# 把处理后的图片放进Document变量doc中
doc.add_picture(filepath,idth=Inches(pic_puzzle_side_long),height=Inches(pic_puzzle_side_short))
# 把Document变量doc保存到指定路径的docx文件中
# doc = docx.Document('D:\\test\\pic\\合并图片.docx')
doc.save('C:\\Users\\Administrator\\Desktop\\word2pdf2png\\拼图\\{}.docx'.format(name))
#
print("pic", i+1, "successfully added.")
print('-----第三部分结束:请到桌面\word2pdf2png内部寻找-----')
文件运行后,需要输入大量参数
已经测试的相关参数
?以4:3横版图片 生成24格 4*6格拼图(1.7*1.7CM单块)为例
运行终端?
输入各种参数
?终端运行过程
??拼图块所在位置?
?单个拼图块24块+打印用docx文件
?
?春天拼图.docx效果(4*6)
?Python内单个图片大小1.7*1.7,
wordA4实际单个打印尺寸:4.32*4.32(包含白边)
?使用PPT进行拼图
目测长宽比?:15CM*8CM
?
这个尺寸对于大班幼儿裁剪来说有难度(目前没有测试),因此阿夏将单个拼图从1.7*1.7CM放大到2.3*2.3CM
?以4:3横版图片 生成24格 4*6格拼图(2.3*2.3CM单块)为例
?单个拼图块面积增加,因此分栏从6变成4
?
每行4格,共6行的排列方式 (2页)
打印的单个拼图的长宽也相应变大
?PPT拼图后发现2.3CM拼图块比1.7CM拼图块大
?目测长宽比?:21CM*15CM这个尺寸相对适合大班幼儿进行裁剪,拼贴。
后续复学后看实际打印尺寸,及幼儿操作情况,不断优化代码数据,以便确定几个常用的拼图尺寸(九宫格尺寸、4*6、4*3尺寸)把这个Python学具代码确定下来。
|