subney 发表于 2021-6-29 19:04

用python制作单页照片墙

需求:手上有几百张图片,如果要展示,最好是生成缩略图,而不是给原图。但是几百张缩略图看起来也累,最好一图搞定。
方法:借用Python PIL库。
```
from PIL import Image
import os
from collections import namedtuple

#快速创建一个数据类
Canvas=namedtuple('Canvas',['row','column','image'])

#把传进来的文件列表筛选一下,排除非图片文件
def __filter_images(files:list,image_types:list)->list:
images=[]
for file in files:
    extension=os.path.splitext(file)[-1].lower()
    #这一步写地丑了
    for t in image_types:
      if t in extension:
      images.append(file)
      break
return images

#根据参数创建一张空白图片
def __create_canvas(images_count,thunmb_size,max_width,gap):
columns=1
canvas_width=0
calc_width=lambda col: col*thunmb_size + (col-1)*gap
#一点点增加列数,直到接近最大图片宽度
while True:
    canvas_width=calc_width(columns)
    if canvas_width>max_width:
      break
    columns+=1
#最后要回退一列
columns-=1
canvas_width=calc_width(columns)
#同样的方式,计算图片高度
rows=1
while rows*columns<images_count:
    rows+=1
#回退一行高度
canvas_height=rows*thunmb_size+(rows-1)*gap
canvas=Image.new('RGB',(canvas_width,canvas_height))
return Canvas(rows,columns,canvas)

#生成素材图片的缩略图
def __createThunmbnail(image:Image.Image,thumb_size):
#主要工作是保持图片原有宽高比例的情况下
#生成比指定size小的小图
#这里可以改进,根据不同的模式:cover、stretch等处理图片
width,height=image.size
scale_x=width/thumb_size
scale_y=height/thumb_size
if scale_x>scale_y:
    width=thumb_size
    height=height/scale_x
else:
    height=thumb_size
    width=width/scale_y
image.thumbnail((width,height))
return image

#将小图片粘贴到合成图中
def __paste_thumbnail(target:Image.Image,source:Image.Image,row:int,column:int,thumb_size,gap):
#计算位置的左边界
left=column*(thumb_size+gap)
#计算位置的上边界
top=row*(thumb_size+gap)
#因为小图的尺寸不一样,需要在格子中居中
offset_x,offset_y=0,0
if source.size<thumb_size:
    offset_x=(thumb_size-source.size)//2

if source.size<thumb_size:
    offset_y=(thumb_size-source.size)//2

target.paste(source,(left+offset_x,top+offset_y))
return target

#生成大图的主函数
#folder:图片目录
#thumbSize:小图的最大尺寸
#max_width:大图的最大宽度
#gap:小图之间的默认间距
#image_types:筛选图片格式的列表
def generateThumnnail(folder,thunmbSize=(256,256),max_width=1080,gap=10,image_types=['gif','jpg','png'])->Image.Image:
#读取图片素材
images=__filter_images(os.listdir(folder),image_types)
#因为python读取的文件不包含目录部分,需要重新合成完整路径
images=
#生成空白大图
row,column,blank_image=__create_canvas(len(images),thunmbSize,max_width,gap)
#迭代图片素材的序号
index=0
for r in range(row):
    for c in range(column):
      #行列相乘的结果可能大于素材总数,所以需要判断一下
      if index>=len(images):
      return blank_image
      #加载素材图
      raw=Image.open(images)
      #得到小图
      thumb=__createThunmbnail(raw,thunmbSize)
      #把小图贴到大图的相应位置
      __paste_thumbnail(blank_image,thumb,r,c,thunmbSize,gap)
      index+=1
      # print(r,c,index)
return blank_image


```
素材图文件夹如下:

成品如下:原图太大,一压缩,效果赶上打码了……

存在的问题:小图之间的空白太难看,一时想不到好的排列算法。暴力算法都头疼。
还有一个问题:我好像见过实现这个功能的软件,那这轮子造的可太糙了{:1_907:}

cs7392000 发表于 2021-6-29 19:07

感谢楼主分享

fanvalen 发表于 2021-6-29 20:11

我记得好像有个排序的,但是一时想不起叫什么名字了,
就是很多文字围绕一个关键词在周围环绕,关键词还特别大周围的小
算了算了

树洞先生 发表于 2021-6-29 20:22

CollageIt   楼主可以试试这个不过还是感谢你的分享

subney 发表于 2021-6-30 09:34

fanvalen 发表于 2021-6-29 20:11
我记得好像有个排序的,但是一时想不起叫什么名字了,
就是很多文字围绕一个关键词在周围环绕,关键词还特 ...

难道是词云?
页: [1]
查看完整版本: 用python制作单页照片墙