Изменение размера каждого кадра гифки с помощью Pillow без нехватки памяти - PullRequest
0 голосов
/ 07 августа 2020

В настоящее время у меня есть несколько функций, работающих вместе, чтобы изменить размер gif, чтобы он выглядел шире. Проблема в том, что с некоторыми гифками, которые при открытии превращаются в большие куски памяти (то есть у меня есть 2-мегабайтный gif, который при открытии занимает более 256 МБ памяти), эти функции в конечном итоге приводят к тому, что мой процесс завершается из-за нехватки памяти.

В идеале я бы хотел перебирать каждый кадр, вносить изменения и сохранять их все в циклическом анимированном gif. Это работает в большинстве случаев, но я бы хотел, чтобы это работало во всех возможных случаях. В частности, это работает со всеми гифками, которые я использовал в своей среде windows, но проблемы возникают там, где я размещаю процесс, поскольку в этой среде гораздо меньше памяти.

Это гифка, которая ломает вещи: https://media.discordapp.net/attachments/661994364104605705/740933535107514368/source.gif

Это код, который обрабатывает фреймы:

        for (i,frame) in enumerate(self.getFrames(im)):
            oldWidth, oldHeight = frame.size
            (width, height) = (frame.width * 3 * widenMultiple, frame.height // 1)  # Provide the target width and height of the image
            frame = frame.resize((width, height))
            if noCrop == 0 and width >= 2400 and height * 2 < width:
                frame = self.centerCrop(frame, width / (3), height)
            frameList.append(frame)

Это код, который получает фреймы (не мой, нашел это решение на git ):

    def getFrames(self, im):
        '''
        Iterate the GIF, extracting each frame.
        '''
        mode = self.analyseImage(im)['mode']

        p = im.getpalette()
        last_frame = im.convert('RGBA')

        try:
            while True:
                '''
                If the GIF uses local colour tables, each frame will have its own palette.
                If not, we need to apply the global palette to the new frame.
                '''
                if not im.getpalette():
                    im.putpalette(p)

                new_frame = Image.new('RGBA', im.size)

                '''
                Is this file a "partial"-mode GIF where frames update a region of a different size to the entire image?
                If so, we need to construct the new frame by pasting it on top of the preceding frames.
                '''
                if mode == 'partial':
                    new_frame.paste(last_frame)

                new_frame.paste(im, (0, 0), im.convert('RGBA'))
                yield new_frame

                last_frame = new_frame
                im.seek(im.tell() + 1)
        except EOFError:
            pass

Происходит то, что после нескольких итераций for l oop процесс выводит «убит» при тестировании с этой спецификацией c gif. Я еще не нашел другого примера, но предполагаю, что этот код в целом может потребовать много работы, потому что он, вероятно, считывает одни и те же вещи в память несколько раз, что приведет к очень нездоровому масштабированию эффективности использования пространства.

Я использую imageio для обработки файлов gif, но только для изменения длительности каждого кадра. Этот gif не представляет проблем с imageio, но, что бы он ни стоил, мне пришлось установить memTest=False при загрузке этого gif, используя imageio.mimread

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...