пиши быстро png - PullRequest
       20

пиши быстро png

21 голосов
/ 30 октября 2011

Резюме

Я хочу написать файл .png как можно быстрее, не заботясь о сжатии. То есть меня не волнует размер файла, но мне важно, чтобы запись происходила как можно быстрее.

Мотивация

Я создаю веб-приложение для карт, использующее OpenLayers на стороне клиента и python / C ++ на стороне сервера. Приложение должно уметь быстро рисовать динамический контент, когда пользователь перемещается по карте. У меня работают версии на основе плиток (256x256) и на основе одного изображения («одна плитка»), но в обоих случаях самая медленная часть рендеринга на самом деле сохраняет изображение в виде файла png (будь то на -диск или в памяти). Например, я могу быть в состоянии генерировать «сырую», «tga» или «tiff» версию определенного представления примерно за 200 мс, но для генерации версии .png требуется более 1,2 секунды только потому, что .png сохранение занимает почти целую секунду, тогда как время фактического сохранения других форматов составляет 100 мс или меньше (и даже несмотря на то, что «необработанный» файл в пять раз больше размера файла .png). И этот файл экономит время также значительно больше, чем время передачи полученного изображения с сервера на клиент. (Одним из важных свойств моего приложения является то, что в целом «серверная часть» будет работать на том же компьютере, что и браузер, поэтому время передачи незначительно даже для файлов большого размера.)

Я думал, что смогу быстро писать .png (при использовании libpng из C ++), вызвав

    png_set_compression_level( png_ptr, 0 );

перед вызовом любых png_write_... функций. Однако, несмотря на то, что этот вызов действительно останавливает libpng от сжатия файла (размер получаемого файла примерно равен размеру файла .raw), он не делает сохранение файла .png заметно быстрее.

Пожалуйста, помогите

Мне нужно использовать .png для этих изображений, потому что мне нужно, чтобы они были прозрачными наложениями поверх базовой карты, и мне нужно больше, чем 256 цветов, предлагаемых GIF. OpenLayers просто использует теги html img, поэтому я понимаю, что могу использовать только допустимые форматы img.

Я бы подумал, что был бы способ быстро написать файл .png, не делая никакого реального сжатия (я понимаю, что .png «всегда сжат», но я предполагал, что это может включать «нулевое сжатие»). Кажется, что вы должны иметь возможность писать как простой фиксированный заголовок, за которым следуют несжатые данные, а затем какой-то фиксированный нижний колонтитул. Или, может быть, та же идея, но построчно. Дело в том, что я могу очень быстро выполнять все виды циклических операций с этими 2,5 МБ необработанных данных в памяти в C ++ и очень быстро выгружать их в различные форматы файлов, поэтому мне кажется, что я должен иметь возможность записать их в фиксированном виде. , несжатый формат .png также быстро.

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

Ответы [ 2 ]

30 голосов
/ 13 ноября 2011

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

формат не слишком сложен и должен легко реализовывать кодировщик

примечание: все значения не подписаны. Многобайтовые целые числа находятся в «сетевом порядке байтов» (самый старший байт первый).


формат состоит из кусков . структура чанка:

  • длина содержимого чанка, 4 байта
  • идентификатор блока (ASCII), 4 байта
  • содержимое чанка, байты "длина содержимого чанка"
  • CRC идентификатора и содержимого (т.е. без учета длины), 4 байта

вашей реализации нужно только магическое число и три фрагмента :


подробный макет:

  • {137, 80, 78, 71, 13, 10, 26, 10} (магическое число), 8 байтов
  • длина байта блока IHDR, 4 байта (значение: 13)
  • {73, 72, 68, 82} («IHDR»), 4 байта
  • ширина, 4 байта
  • высота, 4 байта
  • битовая глубина (для цвета) , 1 байт (8 = 24/32 битного цвета)
  • тип цвета , 1 байт (2 = RGB)
  • метод сжатия , 1 байт (0 = DEFLATE алгоритм, не допускающий сжатия)
  • метод фильтрации , 1 байт (0 = нет фильтра)
  • метод чередования, 1 байт (0 = без чередования)
  • CRC блока IHDR , 4 байта
  • длина байта содержимого блока IDAT, 4 байта
  • {73, 68, 65, 84} ("IDAT"), 4 байта
  • необработанные данные изображения с переносом алгоритма DEFLATE, "длина байта содержимого чанка IDAT" байты
  • CRC блока IDAT , 4 байта
  • длина байта блока IEND, 4 байта (значение: 0)
  • {73, 69, 78, 68} («IEND»), 4 байта
  • CRC фрагмента IEND , 4 байта (может быть предварительно вычислено)

Кодировка данных DEFLATE без сжатия

ваши данные будут разбиты на куски по 65535 байт формат прост:

  • первые X кусков
    • заголовок, 1 байт (значение: 0)
    • данные, 65535 байт
  • финальный кусок
    • заголовок, 1 байт (значение: 1)
    • данные, 65535 байт или меньше

вот и все


так вот как вы делаете быстрый png файл

13 голосов
/ 05 июля 2013

Скорость сжатия для PNG зависит в основном от двух параметров:

  1. Уровень сжатия сжатия ZLIB.Установка его в 0, с png_set_compression_level, по сути, означает отключение этого сжатия.

  2. Пиксельная фильтрация.Это может варьироваться для каждой строки, и выбор часто делается с помощью некоторой эвристики, которая может быть эффективной для размера, но может занимать много времени.См. png_set_filter и png_set_filter_heuristics Если скорость является основной проблемой (и, что более важно, если сжатие ZLIB отключено), вы должны выбрать один фильтр: PNG_FILTER_NONE

Я думаю, что для оптимизации скорости осталось немного.По сравнению с «необработанным» форматом, таким как BMP или TGA, несжатый PNG по-прежнему будет иметь (небольшую) нагрузку по вычислению CRC32 для каждого блока, а также внутреннего Adler CRC для ZLIB.И это почти все.

(Для записи я написал полный кодер / кодировщик на чистом Java, который стремится к памяти и эффективности процессора: PNGJ )

...