将裁剪图像的文件夹填充到最大宽度

Posted

技术标签:

【中文标题】将裁剪图像的文件夹填充到最大宽度【英文标题】:Pad Folder Of Cropped Images To Maximum Width 【发布时间】:2019-12-25 12:37:44 【问题描述】:

有没有办法获取裁剪图像的文件夹,取它们的最大宽度,然后在右侧用白色填充其余部分,使它们的宽度都相同?

我编写了一个 python 脚本,它获取一个图像文件夹,裁剪掉它们的白色边框,然后在第二步中将它们重新缩放为 PDF。图片是来自脚本的引理,这就是为什么不是所有图片都填满整个线宽的原因。

问题是,如果一个图像在裁剪前没有填满线宽,白色会被自动裁剪掉,然后图像宽度太窄,如果再粘贴到PDF中,它就会被放大,并且方式超出比例。 因此,最好先裁剪它们,然后填充它们,然后继续创建 PDF。

下面是整个代码,虽然只有 trim 和 crop 方法可能会受到这个问题的影响。

# All the necessary parameters are accessible after line 55,
# but can of course be changed manually in the Code


# imports for the crop, rename to avoid conflict with reportlab Image import
from PIL import Image as imgPIL
from PIL import ImageChops
import os.path, sys

# import for the PDF creation
import glob
from reportlab.lib.pagesizes import A4
from reportlab.lib import utils
from reportlab.platypus import Image, SimpleDocTemplate, Spacer
from reportlab.lib.units import mm, inch

# get os path for Cropping
path = (os.path.dirname(os.path.abspath("cropPDF.py")))
dirs = os.listdir(path)


def trim(im, border="white"):
    bg = imgPIL.new(im.mode, im.size, border)
    diff = ImageChops.difference(im, bg)
    bbox = diff.getbbox()
    if bbox:
        return im.crop(bbox)


def crop():
    for item in dirs:
        try:
            fullpath = os.path.join(path, item)
            if os.path.isfile(fullpath):
                im = imgPIL.open(fullpath)
                f, e = os.path.splitext(fullpath)
                imCrop = trim(im, "white")
                imCrop.save(f + ".png", "PNG", quality=100)
        except:
            pass


def add_page_number(canvas, doc):
    canvas.saveState()
    canvas.setFont('Times-Roman', numberFontSize)
    page_number_text = "%d" % (doc.page)
    canvas.drawCentredString(
        pageNumberSpacing * mm,
        pageNumberSpacing * mm,
        page_number_text
    )
    canvas.restoreState()


#############################

executeCrop = True

outputName = "output.pdf"

margin = 0.5
imageWidthDefault = 550
spacerHeight = 7
scalingIfImageTooTall = 0.95  # larger than 95 can result in an empty page after the image

includePagenumbers = True
numberFontSize = 10
pageNumberSpacing = 5

############################

if executeCrop:
    crop()

filelist = glob.glob("*.png")  # Get a list of files in the current directory
filelist.sort()

doc = SimpleDocTemplate(
    outputName,
    topMargin=margin * mm,
    leftMargin=margin * mm,
    rightMargin=margin * mm,
    bottomMargin=margin * mm,
    pagesize=A4
)

story = []  # create the list of images for the PDF

for fn in filelist:
    img = utils.ImageReader(fn)
    img_width, img_height = img.getSize()  # necessary for the aspect ratio
    aspect = img_height / float(img_width)

    documentHeight = doc.height

    imageWidth = imageWidthDefault
    imageHeight = imageWidth * aspect

    if imageHeight > documentHeight:
        imageHeight = documentHeight * scalingIfImageTooTall
        imageWidth = imageHeight / aspect

    img = Image(
        fn,
        width=imageWidth,
        height=imageHeight
    )
    story.append(img)
    space = Spacer(width=0, height=spacerHeight)
    story.append(space)

if includePagenumbers and not len(filelist) == 0:  # if pagenumbers are desired, or not
    doc.build(
        story,
        onFirstPage=add_page_number,
        onLaterPages=add_page_number,
    )
elif not len(filelist) == 0:
    doc.build(story)
else:  # to prevent an empty PDF that can't be opened
    print("no files found")

【问题讨论】:

【参考方案1】:

我现在使用from PIL import ImageOps创建了一个解决方案

这两个新方法提供了所需的功能,第一个找到所有图像的最大宽度,第二个为文件夹中的每个图像创建一个空白图像,并将原始图像粘贴到顶部:

def findMaxWidth():
maxWidth = 0
for item in dirs:
    try:
        fullpath = os.path.join(path, item)
        if os.path.isfile(fullpath):
            im = imgPIL.open(fullpath)
            maxWidth = max(maxWidth, im.size[0])
    except:
        pass
return maxWidth


def padImages():
maxWidth = findMaxWidth()
for item in dirs:
    try:
        fullpath = os.path.join(path, item)
        if os.path.isfile(fullpath):
            im = imgPIL.open(fullpath)
            f, e = os.path.splitext(fullpath)

            width,height = im.size #get the image dimensions, the height is needed for the blank image

            image = imgPIL.new('RGB', (maxWidth, height), (255, 255, 255)) #create a white image with the max width         
            image.paste(im, (0,0) ) #paste the original image overtop the blank one, flush on the left side
            image.save(f + ".png", "PNG", quality=100)
    except:
        pass

【讨论】:

以上是关于将裁剪图像的文件夹填充到最大宽度的主要内容,如果未能解决你的问题,请参考以下文章

给定图像和纵横比的最大裁剪区域

批量裁剪图像到固定高度 (CLI)

避免图像裁剪并将其投射到固定的图像尺寸

在android中裁剪图像以适应宽度和截断高度

调整jquery css大小时的猫头鹰轮播响应裁剪宽度

在 div 内裁剪居中的图像