我正在尝试批量处理文件夹中包含的图像,以调整大小和优化它们以供在线使用。
以下脚本有效,但是在获得所需输出之前,我必须运行两次。我希望它能这样工作:
将目标文件夹中的每个图像调整为特定大小,在文件名中添加“ _small.png”,并将其另存为子文件夹“ optimized_images”中的新文件,该子文件夹与原始组的文件夹位于同一目录中图片。
在“ optimized_images”(“ _ small.png”)中获取新生成的图像,并进行转换以减小原始文件的大小,并添加“ -opt.png”后缀以表明它已被优化。
获取功能1生成的文件(由于它们已经过优化),它们不再需要(因为它们已经过优化),并删除它们以减少混乱。
当我运行脚本时,我从function1得到了预期的响应,目标文件中的所有文件都会适当调整大小并保存在“ optimized_images”文件夹中。但是我必须在功能2和3生效之前第二次运行脚本。它确实有效,但是我之前从未遇到过这样的问题。知道为什么会这样吗?
我认为这可能与文件打开/关闭操作有关,但是我认为我会在适当的时候关闭它们。我将Image.open语法交换为“与Image.open(path)一起用作图像:”,但这并不能解决问题。
我认为os.listdir或os.path可能存在一些问题,可能需要对其进行“重置”才能遍历两次文件目录,但是我找不到任何东西。
from PIL import Image
import os, sys
path = "../path/to/images/"
new_folder = '/optimized_images/'
optimized_path = path + new_folder[1:]
dirs = os.listdir( path )
optimized_dirs = os.listdir( optimized_path )
def resize_aspect_fit(final_size=250, dirs=dirs, optimized_path=optimized_path, optimized_dirs=optimized_dirs):
for item in dirs:
if item == '.DS_Store':
continue
if os.path.isfile(path+item):
with Image.open(path+item) as im:
f, e = os.path.splitext(path+item)
size = im.size
ratio = float(final_size) / max(size)
new_image_size = tuple([int(x*ratio) for x in size])
im = im.resize(new_image_size, Image.ANTIALIAS)
new_im = Image.new("RGBA", (final_size, final_size), color=(255,255,255,0))
new_im.paste(im, ((final_size-new_image_size[0])//2, (final_size-new_image_size[1])//2))
new_path, new_filename = f.rsplit('/', 1)
new_im.save(new_path + new_folder + new_filename + '_small.png', 'PNG', quality=10, optimize=True)
new_im.close()
def png_conversion(optimized_dirs=optimized_dirs, optimized_path=optimized_path):
for item in optimized_dirs:
if item == '.DS_Store':
continue
f, e = os.path.splitext(optimized_path+item)
with Image.open(f + e) as im:
im.load()
# Get the alpha band
alpha = im.split()[-1]
im = im.convert('RGB').convert('P', palette=Image.ADAPTIVE, colors=255)
# Set all pixel values below 128 to 255,
# and the rest to 0
mask = Image.eval(alpha, lambda a: 255 if a <=128 else 0)
# Paste the color of index 255 and use alpha as a mask
im.paste(255, mask)
# The transparency index is 255
e = e.split('.png')[0]
im.save(f + e + "-opt.png", transparency=255)
im.close()
def unoptimized_cleanup(optimized_dirs=optimized_dirs, optimized_path=optimized_path):
for item in optimized_dirs:
if item.endswith('small.png'):
os.remove(os.path.join(optimized_path, item))
#functions called in order
resize_aspect_fit(final_size=250, dirs=dirs)
png_conversion(optimized_dirs=optimized_dirs, optimized_path=optimized_path)
unoptimized_cleanup(optimized_dirs=optimized_dirs, optimized_path=optimized_path)
我希望对于以下文件夹结构:
folder/image1.png
folder/image2.png
输出应如下所示,并具有适当大小和较小的文件:
folder/optimized_images/image1_small-opt.png
folder/optimized_images/image2_small-opt.png
我从中获取的相关资源:
Converting PNG32 to PNG8 with PIL while preserving transparency
Python/PIL Resize all images in a folder
答案 0 :(得分:1)
问题是在运行步骤1之前创建了变量optimized_dirs
。因此,在执行步骤1之前,您要在该目录中创建文件列表,该列表此时为空。如果您第二次运行它,则文件位于optimized_dirs
中,因此可以正常工作。
一种解决方案是在函数optimized_dirs
中读取png_compression
的内容,即在其中移动os.listdir( optimized_path )
。
顺便说一句:我看到您在使用[1:]
来防止双斜杠的路径上做了一些魔术。使用os.path.join
构建路径更加健壮,这将确保目录之间始终存在一个斜杠,而不管是在每个目录的开头还是结尾都指定它们。