Почему я должен запустить этот скрипт на Python дважды, чтобы правильно отформатировать изображения? - PullRequest
1 голос
/ 06 июня 2019

Цель:

Я пытаюсь пакетно обработать изображения, содержащиеся в папке, чтобы изменить их размер и оптимизировать их для использования в Интернете.

Проблема:

Следующий скрипт работает, но мне нужно запустить его дважды , прежде чем я получу нужный вывод.Вот как я ожидаю, что это сработает:

функция 1: resize_aspect_fit ()

Изменяет размеры каждого изображения в целевой папке до определенного размера, добавляет "_small.png" к имени файлаи сохраняет его как новый файл в подпапке «optimized_images», созданный в том же каталоге, что и исходная группа изображений.

function2: png_conversion ()

Принимает вновь созданные изображения внутри«optimized_images» («_small.png») и применяет преобразование, которое уменьшает размер исходного файла, добавляя суффикс «-opt.png», чтобы указать, что он был оптимизирован.

function3: unoptimized_cleanup ()

Принимает файлы, созданные функцией 1, которые больше не нужны (поскольку они были оптимизированы), и удаляет их, чтобы уменьшить беспорядок.

При запуске сценария я получаю ожидаемый ответиз функции 1 все файлы в целевом файле изменяются соответствующим образом и сохраняются в папке «optimized_images».Но мне нужно запустить сценарий второй раз, чтобы функции 2 и 3 вступили в силу.Это работает, но я никогда не сталкивался с такой проблемой раньше.Любая идея, почему это происходит?

Что я пробовал:

Я думал, что это может быть связано с операциями открытия / закрытия файлов, но я думаю, что закрываю их все в соответствующее время.Я поменял местами синтаксис Image.open, чтобы использовать «с Image.open (путь) как изображение:», но это не решило проблему.

Я подумал, что могут быть некоторые проблемы с 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

Соответствующие источники, которые я извлек из:

Преобразование PNG32 в PNG8 с PIL при сохранении прозрачности

Python / PIL Изменение размера всех изображений в папке

Извините за длинный вопрос / код, и заранее спасибо за любую помощь !!

1 Ответ

1 голос
/ 10 июня 2019

Проблема в том, что вы создаете переменную optimized_dirs перед выполнением шага 1. Поэтому перед выполнением шага 1 вы создаете список файлов в этом каталоге, который на данный момент пуст.Если вы запустите его во второй раз, файлы будут в optimized_dirs, и, следовательно, тогда он будет работать.

Решением было бы прочитать содержимое optimized_dirs внутри функции png_compression, то есть переместить os.listdir( optimized_path ) там.

Кстати: я вижу, что вы делаете магию для построения путей, где вы используете [1:] для предотвращения двойных слешей.Более надежно строить пути, используя os.path.join, что гарантирует, что между каталогами всегда будет один слеш, независимо от того, указаны вы в начале или в конце каждого из них.

...