Какой формат изображения более эффективен при использовании памяти: PNG, JPEG или GIF?

70

Какой формат изображения более эффективен для экономии памяти? PNG, JPEG или GIF?

Tredecies Ноктюрн
источник
4
Формат файла не имеет ничего общего с текстурами или расположением объектов.
Kylotan

Ответы:

153

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

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

Место хранения

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

В общем, JPEG сжимает лучшее для фотографий и изображений без четких границ. Однако качество ваших изображений будет ухудшаться, поскольку в JPEG используется сжатие с потерями (вы можете точно настроить уровень сжатия / ухудшение качества при экспорте изображений в формате JPEG. Дополнительную информацию см. В документации к программному обеспечению для обработки изображений).

Однако, как бы ни был хорош JPEG, он не поддерживает прозрачность . Это очень важно, если вы хотите, чтобы изображения были видны другим, или если вы хотите изображения неправильной формы. GIF - хороший выбор, но он был в значительной степени заменен PNG (есть только несколько вещей, которые GIF поддерживает, но PNG не поддерживает, но они в значительной степени не имеют отношения к программированию игр).

PNG поддерживает прозрачность (и полупрозрачность), сжимает данные без ухудшения качества (т. Е. Использует сжатие без потерь) и сжимает довольно хорошо, но не так сильно, как JPG.

Проблема возникает, когда вам нужно хорошее сжатие, а также прозрачность. Если вы не возражаете против слегка ухудшенных изображений, вы можете использовать программы квантования PNG, такие как pngquant , которые вы можете протестировать онлайн на TinyPNG . Имейте в виду, что ухудшение изображения, выполняемое самим квантованием, отличается от ухудшения качества изображения в JPEG (которое включает в себя квантование, а также другие агрессивные методы), поэтому обязательно попробуйте оба варианта с широким разнообразием настроек.

Если вы хотите агрессивно минимизировать размер вашего дистрибутива, вы можете вручную обработать каждое изображение следующим образом:

if the image has transparency then
    try pngquant on the image
    if the results are not satisfactory then
        revert to the non-quantized image
    end
    store as PNG
else
    try storing it as JPG with different quality settings
    if no single setting yields an image of an acceptable quality then
        try pngquant on the image
        if the results are not satisfactory then
            revert to the non-quantized image
        end
        store as PNG
    else
        store as JPG
    end
end

Совет: некоторые изображения можно хранить в одном формате, а другие - в другом.

Существуют и другие специализированные форматы, такие как DXT, ETC и PVRTC. Они поддерживают сжатие, а также могут быть загружены сжатыми в память, но они поддерживаются только определенными графическими процессорами, и большинство из этих графических процессоров поддерживают только один из них, поэтому, если вы не знаете точные спецификации аппаратного обеспечения вашего целевого оборудования ( iPhone / iPad, который поддерживает текстуры PVRTC), вам следует избегать этих форматов.

Память программ

Я включил это здесь, потому что это то, что обычно называют "памятью". Однако, если ваша игра использует графическое ускорение (и если вы делаете игру после 1998 года, скорее всего, так и есть), то единственное, что потребляет память, - это ваши текстурные дескрипторы (всего несколько байтов на изображение), что составляет всего лишь зависит от количества изображений, а не от их размера или формата (это имеет несколько предостережений, но в основном не имеет значения).

Если у вашей платформы нет выделенной видеопамяти, аппаратное ускорение или другие необычные случаи, то следующий раздел, касающийся VRAM, будет происходить полностью или частично в ОЗУ, но основные принципы будут такими же.

Видеопамять

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

Теперь VRAM, используемый вашими изображениями, будет примерно соответствовать width * height * bitdepth каждому изображению, загруженному в VRAM. Здесь есть пара вещей, на которые стоит обратить внимание:

  1. Ширина и высота, в которой ваши изображения хранятся в VRAM, не обязательно будут соответствовать вашим исходным изображениям. Некоторые графические процессоры могут обрабатывать только текстуры с размерами в степени 2, поэтому изображение 320x240 может фактически храниться в пространстве 512x256 в VRAM, при этом неиспользуемая память эффективно теряется. Иногда вам даже не разрешается загружать текстуры с размерами, не равными степени 2 (как в GLES 1.1).

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

  2. Глубина очень важна. Обычно текстуры загружаются в VRAM в 32-битном ARGB или 32-битном XRGB, но если ваше оборудование поддерживает 16-битную глубину, и вы не возражаете против более низкой разрядности, вы можете вдвое уменьшить количество VRAM, потребляемое каждым изображением. , что может быть чем-то интересным для рассмотрения.

  3. Но независимо от того, что вы делаете, самым важным фактором при рассмотрении количества VRAM, которое ваша игра использует, является количество изображений, которые вы имеете в VRAM в данный момент времени. Это число, которое вы, скорее всего, хотите сохранить как можно ниже, если хотите получить хорошую игру. Загрузка и выгрузка текстур в VRAM стоит дорого, поэтому вы не можете просто загружать каждое изображение, когда собираетесь его использовать. Вы должны найти баланс между предварительной загрузкой изображений, которые вы, скорее всего, будете использовать, и выгрузить их, если вы уверены, что больше не будете их использовать. Делать это правильно не тривиально, и вы должны думать о своей собственной стратегии для вашей конкретной игры.

Скорость исполнения

Хотя это и не «память», это очень связано с производительностью в играх. Рисование изображений стоит дорого, и вы хотите, чтобы ваш рендеринг работал как можно быстрее. Конечно, здесь формат не имеет значения, но есть и другие вещи:

  1. Размер изображения (на самом деле это будет «размер выборки»): чем больше область изображения, которое вы собираетесь нарисовать, тем больше времени потребуется для ее рисования. Рендеринг огромного изображения в небольшом участке экрана не очень эффективен, поэтому есть метод, называемый mipmapping , который состоит из торговли VRAM за скорость рендеринга, сохраняя ваши изображения несколько раз в нескольких разрешениях и используя наименьшее, которое может дать Вы нужного качества в любой момент времени. Mipmapping может выполняться при загрузке изображений, что повлияет на скорость загрузки и использование VRAM, или при предварительной обработке (путем ручного сохранения разных версий одного и того же изображения или использования формата, который изначально поддерживает mipmapping, такого как DDS), что повлияет на хранилище и использование VRAM, но это мало повлияет на скорость загрузки.

  2. Визуализация изменений состояния. Скорее всего, вы захотите нарисовать несколько разных изображений на экране одновременно. Тем не менее, графический процессор может использовать только один исходный образ в любой момент времени (это не так, но, пожалуйста, потерпите меня здесь). Используемое в настоящее время изображение для рендеринга является одним из многих состояний рендеринга , и это дорого. Поэтому, если вы собираетесь использовать одно и то же изображение несколько раз (помните, когда я упомянул атласы текстур ?), Вы заметите огромный выигрыш в производительности, если вы будете использовать изображение как можно чаще, прежде чем изменить состояние рендера и начать использовать другое изображение (кроме этого есть другие состояния рендеринга, и точная настройка порядка, в котором вы рисуете свои вещи, чтобы минимизировать изменения состояния рендеринга, является очень распространенным действием при повышении производительности игры)

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

Панда Пижама
источник
25
+1. Это очень полный ответ, который охватывает очень много вопросов. Я не уверен, что размер текстовых дескрипторов требовал столько же места, сколько он получил, и упоминание DXT / ETC / PVRTC должно действительно включать то, что каждый из них работает только на некоторых платформах - они не являются кросс-платформенными стандарты, которые можно использовать повсюду, как JPEG, PNG и GIF. Но в целом очень впечатлило. Это намного больше, чем просто «небольшая аннотация» поверх моего ответа! : D
Тревор Пауэлл
9
@PandaPajama: Возможно нет, но это удивительно лучший ответ, чем этот вопрос заслуживает.
Марки Томас
1
+1 и больше, если бы я мог. Это потрясающий ответ, и он должен быть стандартным ориентиром для любого вопроса об «эффективности памяти», поскольку он настолько эффективно развенчивает распространенный миф о том, что использование меньшего количества памяти - это всегда лучший подход, а не только для изображений. Один пункт, который я хотел бы добавить, заключается в том, что в неускоренном случае, если какая-либо распаковка на лету необходима при рисовании, это может привести к недопустимому снижению производительности.
Максимус Минимус
2
Я хотел бы предложить PNGGauntlet . Он может выполнять огромные оптимизации без потерь для размеров файлов PNG, которые могут сложиться, особенно если у вас много спрайтов. К сожалению, это только Windows, но альтернативы перечислены на домашней странице для других ОС.
orlp
1
@DavidDimalanta У меня нет опыта работы с libgdx, но, как я могу видеть из документации setEnforcePotImages, он отключает применение мощности текстур 2-го размера для OpenGLES 1.0. Это не очень хорошая идея, так как не все аппаратные средства поддерживают текстуры не-степени-2. OpenGLES 2.0 требует поддержки текстур, не относящихся к степени 2, поэтому, если вы нацеливаетесь на 2.0, вы можете использовать текстуры любого размера. Для получения дополнительной информации обратитесь к документации по libgdx.
Panda Pajama
26

После того как изображение загружено с диска и отформатировано для рендеринга, оно будет использовать одинаковый объем памяти независимо от того, было ли это изображение сохранено на диск с использованием PNG, JPEG или GIF.

Общее правило: JPEG - это формат с потерями, который ухудшает качество изображения, чтобы уменьшить его на диске. PNG, с другой стороны, является форматом изображения без потерь, и поэтому обычно приводит к увеличению размера файла на диске. GIF также технически является форматом без потерь, но поддерживает только максимум 256 цветов на изображение, поэтому при сохранении в формате GIF изображение с высоким качеством часто будет иметь значительные потери качества.

Это только для их представления на диске, хотя. В памяти они оба будут расширяться в один и тот же формат текстур, используя один и тот же объем памяти, независимо от того, сохраняли ли вы их на диск в формате PNG, JPEG или GIF.

Тревор Пауэлл
источник
То есть размер файла зависит не от расширения файла, а от размера файла?
Ноктюрн Tredecies
Ни. Размер в памяти зависит от размеров изображения и его глубины. Любое сжатие файла изображения удаляется, когда изображение загружается в память для вывода на экран. (Поскольку графические процессоры не могут отображать PNG, JPEG или др. Изображения растянуты в общие растровые изображения, чтобы графические процессоры могли с ними работать.)
Тревор Пауэлл,
2
Это не на 100% верно. Большинство современных графических процессоров (включая встроенные) поддерживают загрузку и хранение сжатых текстур в графической памяти, причем такие форматы, как DXT, ETC и PVRTC, являются наиболее распространенными во встроенном мире. Конечно, вам придется хранить ваши текстуры в этих форматах в первую очередь вместо PNG / JPG / GIF.
Панда Пижама
6
Вопрос был явным выбором между PNG / JPG / GIF, ни один из которых не поддерживается изначально ни в одном из известных мне графических процессоров. У первоначального автора было достаточно проблем с различием между размером файла на диске и занимаемым в ОЗУ пространством, и я чувствовал, что добавление большего количества форматов файлов только запутает фундаментальную проблему. Тем не менее, не стесняйтесь дать свой ответ.
Тревор Пауэлл
2
Мой комментарий это просто аннотация. Если бы я должен был дать ответ, я, скорее всего, написал бы то же самое, что и вы, плюс мой комментарий в качестве заключительного заключительного заявления. Мне больше нечего добавить, поэтому я буду избегать повторения, предоставляя свой собственный ответ.
Панда Пижама
3

По-разному.

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

PNG без потерь и наиболее эффективен для пиксельной графики с четкими линиями и небольшим количеством цветов. Он также поддерживает альфа-прозрачность.

GIF не может делать ничего, что PNG не может делать лучше, за исключением его способности хранить анимацию. Но это актуально только в контексте веб-приложений. В разработке игр вы обычно создаете анимацию с помощью таблицы спрайтов.

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

Philipp
источник
2

Я не знаю много о libgdx, но о форматах изображений и графике:

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

GIF устарел, он может хранить только палитровые цвета (до 8 бит на пиксель) с одним выделенным цветом для полной прозрачности. Это позволяет небольшие анимации на основе кадров. Когда-то был патент на его алгоритм упаковки, так что он не мог быть использован везде легально. Из-за этого патента была разработана PNG.

PNG - это более или менее сжатое растровое изображение, которое может хранить RGB + альфа (до 32 бит) и другие пиксельные форматы. Он предназначен для быстрого распаковывания небольших частей этого изображения, что удобно для очень маленьких и медленных устройств (например, 10-летний мобильный телефон), но современные библиотеки просто распаковывают их в растровые изображения при загрузке.

PNG лучше, чем GIF по размеру, скорости и возможностям, но если вы хотите эффективно хранить растровые изображения, я бы посоветовал: .PNM.BZ2 ([править] Из-за другого метода упаковки .PNM.BZ2 не всегда более эффективен чем .PNG. [/ edit])

PNM / PBM / PGM / PAM - это простые растровые форматы с KISS-заголовками в виде простого текста. Использование gzip приведет к тому, что размер файла будет похож на PNG, поэтому bzip2 - лучшее решение для этого. Если вы собираетесь использовать растровые изображения внутри вашей программы, вы можете использовать сжатые растровые изображения bzip2 в контейнере .tar или .zip. Если у вас нет bzip2, использование PNM в zip-контейнере (zip с максимальным сжатием) может быть аналогично использованию PNG. - Таким образом, хранение PNG в ZIP-файле может принести лишь небольшую выгоду или не принесет никакой пользы - скорее всего, это просто увеличит время загрузки изображения.

Кроме того, это хороший выбор для хранения нескольких маленьких спрайтов / изображений в одном растровом изображении, особенно когда они нужны вам в одной и той же ситуации вместе.

комонада
источник
Доступен ли файл PNM для чтения на всех ОС смартфона и настольного компьютера?
Дэвид Дималанта
1
@ Дэвид Дималанта: я не знаю, где это поддерживается, а где нет. Если вы хотите программировать с PNM, то вам редко нужно использовать какую-либо библиотеку, потому что этот формат слишком прост, чтобы выбрать какой-либо API. Благодаря этому он доступен для чтения и записи со всеми существующими языками программирования, которые поддерживают чтение / запись двоичных файлов. Конечно, вы можете использовать Netpbm на любой ОС, не только на Unix. С другой стороны, я не знаю, какие библиотеки общих изображений не поддерживают это. Это не сжатый формат, поэтому он редко используется для хранения изображений на диске. см. en.wikipedia.org/wiki/Netpbm_format
comonad
1

В качестве формата хранения JPEG, вероятно, является лучшим выбором для некоторых текстур, таких как трава или стены, где потеря информации, вероятно, не обнаруживается. Вслед за PNG, когда вам нужна прозрачность или когда вы не можете расплатиться с потерей информации, например спрайтов в 2D-игре (игрок, враги, сундук с сокровищами), вы, вероятно, захотите использовать PNG для этих изображений.

Говоря о стоимости памяти, формат, используемый для хранения игровой графики в файловой системе, вообще не имеет значения. Либо, если вы храните пиксельные буферы в VRAM или RAM (программный рендерер), вы, вероятно, храните их в несжатом виде, поскольку игры предпочитают быстрое считывание пикселей по сравнению с памятью, используемой каждым пиксельным буфером.

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

Сжатые данные изображения имеют немного больше смысла, если бы было возможно быстрое аппаратное декодирование. По крайней мере, для нормального отображения я помню этот http://en.wikipedia.org/wiki/3Dc . С этим вы можете сохранить некоторые VRAM. Я пока не знаю других примеров аппаратного декодирования.

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

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

Хатору Ханьсу
источник
Возможно ли также, что это не JPEG и не PNG влияет на память, а размер файла?
Ноктюрн Tredecies
Да. Вы выберете любой из обсуждаемых форматов, думая о экономии места на диске или пропускной способности. При загрузке изображений в игру любая библиотека / движок, которую я знаю, будет декодировать их в несжатые пиксельные буферы (представьте, что в пиксельных буферах это массив значений RGB или RGBA, где каждый канал обычно занимает 1 байт в RAM / VRAM при использовании 32 бит на пикселей, это, наверное, то, что все делают).
Hatoru Hansou