Как мне быстрее читать фрагменты текста с помощью libpng?

С помощью libpng я пытаюсь извлечь фрагменты текста из 44-мегабайтного PNG-изображения (и желательно проверить, что данные PNG не искажены (например, отсутствуют IEND и т. д.)). Я мог бы сделать это с помощью png_read_png и png_get_text, но для меня это заняло слишком много времени, 0,47 секунды, что, я почти уверен, из-за огромного количества фрагментов IDAT в изображении. Как это сделать побыстрее?


Мне не нужны были пиксели, поэтому я попытался заставить libpng игнорировать фрагменты IDAT.

Чтобы libpng игнорировал IDAT куски, я пробовал:

  1. png_read_info(p_png, p_png_information); png_read_image(p_png, nullptr); png_read_end(p_png, p_png_information); пропускать IDAT чанки; разбился и провалился.
  2. png_set_keep_unknown_chunks, чтобы libpng не знал о IDAT, и png_set_read_user_chunk_fn(p_png, nullptr, discard_an_unknown_chunk) (discard_an_unknown_chunk — это функция, которая делает return 1;), чтобы отбрасывать неизвестные фрагменты; странная ошибка CRC произошла в первом фрагменте IDAT и завершилась неудачно.

Так и не удалось.


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

Работает как надстройка Node.js C++, в основном написанная на C++, в Windows 10, с процессором i9-9900K с тактовой частотой 3,6 ГГц и гигабайтами памяти.

Прочитайте файл изображения на SSD с помощью fs.readFileSync, метода Node.js, возвращающего Buffer, и передайте его в libpng для обработки.

Да, сначала я ругал libpng за долгие вычисления. Теперь я вижу, что могут быть и другие причины, вызывающие задержку. (Если это так, то этот вопрос будет плохим с проблемой XY.) Спасибо за ваши комментарии. Я проверю свой код еще раз более тщательно.


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

Поскольку каждый шаг для подачи входных данных PNG в надстройку C++ оставался неизменным, я в конечном итоге вручную выбирал и декодировал только текстовые фрагменты, используя магию указателя C и немного магии C++. И производительность была впечатляющей (0,0020829 секунд при обработке), причем почти мгновенно. Хотя не знаю почему и как.

B:\__A2MSUB\image-processing-utility>npm run test

> [email protected] test B:\__A2MSUB\image-processing-utility
> node tests/test.js

----- “read_png_text_chunks (manual decoding, not using libpng.)” -----
[
  {
    type: 'tEXt',
    keyword: 'date:create',
    language_tag: null,
    translated_keyword: null,
    content: '2020-12-13T22:01:22+09:00',
    the_content_is_compressed: false
  },
  {
    type: 'tEXt',
    keyword: 'date:modify',
    language_tag: null,
    translated_keyword: null,
    content: '2020-12-13T21:53:58+09:00',
    the_content_is_compressed: false
  }
]
----- “read_png_text_chunks (manual decoding, not using libpng.)” took 0.013713 seconds.

B:\__A2MSUB\image-processing-utility>

Почему бы вам не запустить его под профилировщиком и посмотреть, куда тратится время, вместо того, чтобы гадать? Libpng имеет открытый исходный код, а Vtune в настоящее время бесплатен.

rustyx 24.12.2020 10:36

Может быть, вы можете поделиться PNG через Dropbox, Google Drive или что-то подобное? Что вы подразумеваете под «предпочтительно проверить данные PNG»? Подтвердить что? Каковы размеры в пикселях и битовая глубина / тип цвета этого массивного файла, потому что а) ваш диск должен читать 44 МБ, что может занять 0,3 с на диске со скоростью 150 МБ / с, и б) вы можете выделить ГБ памяти для расширения сжатого PNG в.

Mark Setchell 24.12.2020 14:06

Вы также можете уточнить свою среду — на Raspberry Pi Zero с USB 2.0 Memory Stick 0,47 с будет впечатляющим.

Mark Setchell 24.12.2020 14:28
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
3
675
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

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

Если вы добавите параметр -7, то сможете не только проверить структуру, но и извлечь текст:

pngcheck -7 a.png

Выход

File: a.png (60041572 bytes)
date:create:
    2020-12-24T13:22:41+00:00
date:modify:
    2020-12-24T13:22:41+00:00
OK: a.png (10000x1000, 48-bit RGB, non-interlaced, -0.1%).

Я сгенерировал PNG-файл размером 60 МБ, и приведенная выше проверка занимает 0,067 с на моем MacBook Pro.

Ответ принят как подходящий

Мне пришлось сделать что-то подобное, но я хотел, чтобы libpng выполнял анализ всех фрагментов метаданных (например, фрагментов eXIf, gAMA, pHYs, zEXt, cHRM и т. д.). Некоторые из этих фрагментов могут появляться после IDAT, что означает, что метаданные нельзя прочитать только с помощью png_read_info. (Единственный способ добраться до них — сделать полную декодировку изображения, что стоит дорого, а затем вызвать png_read_end.)

Мое решение состояло в том, чтобы создать синтетический поток байтов PNG, который передается в libpng через набор обратного вызова чтения с использованием png_set_read_fn. В этом обратном вызове я пропускаю все фрагменты IDAT в исходном PNG-файле, и когда я добираюсь до фрагмента IEND, я вместо этого испускаю фрагмент IDAT нулевой длины.

Теперь я вызываю png_read_info: он анализирует все метаданные во всех фрагментах, которые видит, останавливаясь на первом IDAT, который в моем синтетическом потоке PNG на самом деле является концом исходного PNG-изображения. Теперь у меня есть все метаданные, и я могу запросить их у libpng через функции png_get_xxx.

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

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

Какой хитрый подход только с libpng!

Константин Ван 03.08.2021 14:10

Другие вопросы по теме