Я пытаюсь прочитать анимированный gif с помощью ImageMagick. Соответствующий файл доступен в Интернете, расположен здесь.
Мой код (связанный с ImageMagick/MagickWand 7)
#include <stdlib.h>
#include <MagickWand/MagickWand.h>
int main(void){
MagickWand *magick_wand;
MagickWandGenesis();
magick_wand = NewMagickWand();
MagickReadImage(magick_wand, "animated.gif");
return 0;
}
Если я запущу это в отладчике и перейду к строке сразу после того, как изображение будет прочитано, процесс займет 1,4 ГБ памяти, согласно top. Я нашел анимированные gif-файлы с похожими размерами файлов, и они не приближаются к такому объему потребления памяти. К сожалению, мой опыт работы с анимированными gif-файлами очень ограничен, поэтому я не уверен, что разумно, а что нет.
У меня есть несколько вопросов: это разумно? Это ошибка? Кто-нибудь знает, чем отличается потребление памяти одним файлом от другого? Есть ли способ контролировать потребление памяти ImageMagick? По-видимому, есть файл с именем policy.xml, который можно использовать для указания верхних пределов памяти, но я установил его на низкое значение и все равно получаю такое поведение.
Если вам интересен более широкий контекст, стоящий за этим вопросом, в реальной жизни я использую библиотеку Python под названием Wand, чтобы сделать это в веб-приложении CMS. Если пользователь загружает этот конкретный файл, это приводит к тому, что убийца OOM завершает процесс сервера приложений (ограничение OOM на этих машинах установлено довольно низким).
[Обновлять]:
Мне удалось заставить ограничения памяти в policy.xml работать, но мне нужно установить значения «памяти» и «карты». Установка любого низкого уровня, но не другого, не работает. Меня все еще интересуют другие моменты.
ImageMagick6 распаковывает все изображение в память при загрузке и представляет каждый пиксель как шестнадцатибитное число. Для этого нужно много памяти! ImageMagick7 использует числа с плавающей запятой, а не 16-битные числа, поэтому он снова будет в два раза больше. Ваш GIF имеет размер 1920 x 1080 пикселей RGBA и имеет 45 кадров, так что это 1920 * 1080 * 45 * 4 * 4 байта или около 1,4 ГБ.
Чтобы сэкономить память, вы можете заставить IM открывать большие изображения через временный файл на диске. Это будет проще для вашей оперативной памяти, но будет намного медленнее.
Другие библиотеки обработки изображений могут использовать меньше памяти — например, libvips могут передавать изображения по запросу, а не загружать их в оперативную память, и это может дать большую экономию. С твоим изображением и pyvips я вижу:
$ python3
Python 3.10.7 (main, Nov 24 2022, 19:45:47) [GCC 12.2.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import pyvips
>>> import os, psutil
>>> process = psutil.Process(os.getpid())
>>> # n=-1 means load all frames, access = "sequential" means we want to stream
>>> x = pyvips.Image.new_from_file("huge2.gif", n=-1, access = "sequential")
>>> # 50mb total process size after load
>>> process.memory_info().rss
49815552
>>> # compute the average pixel value for the entire animation
>>> x.avg()
101.19390990440672
>>> process.memory_info().rss
90320896
>>> # total memory use is now 90mb
>>>