Как сохранить изображение с определенным размером файла?

Я создаю систему PHP, посредством которой пользователи могут создавать визуально сложное изображение с окончательным требованием 50 КБ или меньше .

Пользователь может выбрать, чтобы текст был напечатан на одном из 37 изображений шаблонов, поэтому результат представляет собой одно плоское изображение.

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

Затем у меня есть требование, чтобы размер файла окончательного изображения не превышал 50 КБ (это внешнее требование и не может быть изменено).

Последнее требование (опять же, внешнее) – это формат изображения .jpeg, .png или .gif .

Я просмотрел документацию GraphicsMagick , но не могу найти нигде, где упоминается возможность установки размера файла и автоматическое вычисление сжатия .

Я рассматривал возможность делать это программно с помощью тестового цикла compress-> save->, однако я могу себе представить, что это будет достаточно интенсивным, поскольку я не могу заранее вычислить размер файла на основе сжатия. Вот почему я прошу выяснить, была ли проблема решена в GraphicsMagick.

редактировать

Чтобы понять, почему существуют внешние требования:

Пользователь будет использовать эту систему для создания плоского изображения, которое они затем сохранят на своем ПК. Затем это изображение будет загружено в Adroll для использования в кампании Retargeting .

Вот требования Adroll к изображению. Моя система будет предоставлять только размеры изображений 728×90, 300×250 и 120×600.

Редактировать 27 ноября 2010

Поскольку это не представляется возможным с GraphicsMagick, я готов изучить другие решения, такие как прямое взаимодействие с библиотеками сжатия (libpng и т. Д.), Которые могут обеспечить функциональность.

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


Как аналог, для тех, кто так склонен:

Я за то, что A * должен искать: он имеет определенную начальную / конечную точку и находит наилучший возможный маршрут в самое быстрое время.

То, что я надеялся избежать, – это то, что Breadth / Depth First – Search: определенные начальные / конечные точки, но не может попасть на оптимальное решение после нахождения локального минимума и иметь потенциал для полного выведения из строя вычислительно.

Поскольку нет возможности сжиматься до целевого размера, о котором я знаю, я предлагаю искать косвенное решение:

  1. Сделайте некоторые быстрые статистические данные (возможно, сжав множество изображений с различными коэффициентами сжатия JPEG), чтобы узнать, какой средний размер сжатия и его стандартное отклонение для данного уровня качества.
  2. При принятии изображения попробуйте сжать подходящее качество. Если результирующий файл слишком большой, уменьшите качество и повторите попытку. При желании, если он окажется слишком маленьким, вы также можете увеличить качество.
  3. Остановитесь, когда результирующее изображение «близко» к вашему размеру цели, но меньше.

Чтобы немного вычислить математику на шаге 2:

Если вы выберете свое начальное качество таким образом, чтобы ваш средний расчетный размер + 3 * стандартное отклонение <ваш целевой размер, то 99,7% от сжатия приведут к созданию небольшого файла с первой попытки (при условии нормального распределения сжатых размеров).

Вы можете настроить начальное качество и логику, которая увеличивает или уменьшает ее, как вам угодно, балансируя между меньшей загрузкой сервера и файлами ближе к максимальному размеру («более эффективно использовать» ваши ограничения).

Посмотрите следующий пакет:

http://www.phpclasses.org/package/3810-PHP-Optimize-images-to-fit-in-a-given-file-size-limit.html

Довольно круто – я бы сказал, что автор заслуживает пива;)

Пример изображения, которое на самом деле 61081 байт (первое изображение jpeg для отображения размера файла на изображении?):

alt text

Можно ли использовать «-лимит-диск 50mb» GraphicMagick в коалиции с ресурсом «-list», чтобы вы могли проверить это на раннем этапе (или действительно опросить весь процесс) и внести коррективы?

http://www.graphicsmagick.org/GraphicsMagick.html#details-limit

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

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

Пример:

  • 50k jpg, 100×200 сжимается 30k
  • 100k jpg, 100×200 сжато 60k

-> когда вы получаете изображение 100x202px с 59k, сжатый размер будет приблизительно оценен 35k.

Итак, если я это правильно понимаю – вы создаете систему, которая позволяет пользователям писать текст на одном из изображений шаблонов, которые вы предоставляете. Если это правильно, почему вы сохраняете изображение вообще? Вы можете легко удалить ограничение размера 50 Кбит, сохранив сами пользовательские действия. Вы могли бы сделать что-то вроде: сохранить текст (вместе со своими свойствами и местоположением) и шаблон, в котором он включен.

Есть только три способа уменьшить конечный размер любого изображения:

  1. уменьшить разрешение
  2. уменьшить глубину цвета
  3. уменьшить сложность изображения

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

Уменьшение сложности изображения – неприятный зверь. Вы можете попытаться уменьшить межпиксельный «шум», чтобы создать большие области того же цвета, которые очень сжимаются в изображениях GIF / PNG. Простой фильтр размытия мог бы выполнить это, но он также мог бы повредить разборчивость любой мелкой печати / текста внутри изображения. Для цели JPG вы можете попытаться снизить качество сжатия, но опять же, это может испортить изображения, если вы снижаете качество слишком низко. Если простые преобразования на стороне сервера не могут справиться с этим, изображение должно быть переделано художником, который создал его в первую очередь.

Единственный практический метод, который я могу рассмотреть, чтобы автоматизировать это, – это цикл сжимания-сохранения-теста, который вы упомянули. Учитывая, что окончательные изображения относительно малы, это не будет большой нагрузкой на сервер. Сохранение gif / png – легкая операция. Сжатие JPG требует большей мощности процессора, но опять же, с небольшими изображениями, у современного сервера не должно быть проблем с выполнением 10 или 20 тестовых изображений в течение секунды или двух.

Хотя программный вариант цикла до достижения целевого размера файла, кажется, является популярным ответом, есть два способа сделать это с сжатием .jpeg :


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

Способ и электронное устройство для регулировки степени сжатия jpeg-изображения

На основе этой формулы:

log(NSF) = (log(SF1 / SF2) / log(FileSize1 / FileSize2)) * log(Target / FileSize1) + log(SF1) 

где

 SF1 is a first compression parameter SF2 is a second compression parameter FileSize1 is the size of the image compressed with SF1 FileSize2 is the size of the image compressed with SF2 Target is the target file size NSF is the target compression parameter. 

Неясно, находятся ли SF1, SF2 и NSF в диапазоне 0-1 или 0-100 и т. Д., И если FileSize1, FileSize2 и Target находятся в байтах, KiloBytes и т. Д. Экспериментируйте с правильной комбинацией здесь, чтобы найти из правильных единиц.


Второй метод исходит от Рики Д. Нгуена в Массачусетском технологическом институте:

Контроль скорости и распределения бит для перекодирования JPEG

Он предлагает изменить данные, которые используются для сжатия во время его возникновения. Этот вариант может оказаться нецелесообразным для реализации, поскольку он требует модификаций самого кода сжатия.


Из обоих этих примеров, безусловно, можно сохранить файл .jpeg с определенным размером целевого файла.

Сначала попробуйте 24-бит .png. Если это подходит, это будет лучшее качество, и все готово. В качестве альтернативы вы можете протестировать некоторые типичные изображения, и если ни один из них не подходит, вы можете полностью исключить формат из рассмотрения.

Для .gif и .jpg вам нужно искать наилучшее соответствие; ни один из них не может быть предсказан с достаточной уверенностью, и ни один из алгоритмов не подходит для кодирования с постоянной скоростью передачи. Вы можете использовать бинарный поиск, чтобы найти наилучший вариант. Вы можете выбрать коэффициенты сжатия из предопределенного списка, чтобы ограничить количество тестовых компрессий, которые вам нужно выполнить; например, если ваш список коэффициентов сжатия .jpg равен 4, 6, 8, 12, 18, 27, 44, 66, вам нужно будет выполнить максимум 4 тестовых сжатия.

.gif и paletted .png достаточно похожи, что вы должны просто выбрать один и забыть о другом.

Будет сложно выбрать между .gif / .png и .jpg на основе результатов сжатия; артефакты, вводимые каждым процессом, совершенно разные. Опять же, вам может быть лучше, сжимая несколько тестовых изображений до вашего целевого размера и исключая один формат или другой на основе тестирования на глаз.

Возможно, вы смотрите на проблему с неправильным углом. Выбрав PNG и минимизируя метаданные, хранящиеся на изображении, вы уменьшите размер файла. Это связано с тем, что PNG является структурой Bitmap. Пока GMagick не сохраняет текст в виде метаданных, он не будет влиять на размер файла. Только глубина цвета (которую вы также можете контролировать) повлияет на размер файла. Не чередование без фильтрации размера файла должно быть по существу таким же, как размер шаблона. Пока шаблоны меньше 50 КБ, вы должны быть в порядке.