Обработка необработанных данных

Обработка необработанных данных

Для улучшения производительности API Aspose.PSD мы ввели метод обработки необработанных данных с версии 2.4.0. Обработка необработанных данных теперь используется внутренне и имеет внешнее API, чтобы ее можно было использовать извне библиотеки для улучшения общей производительности. Иногда обработка оказывается немного сложной и требует объяснения. Обработка необработанных данных в настоящее время доступна только для формата BMP.

Чтобы помочь разработчикам достичь наилучшей производительности, API Aspose.PSD предоставляет систему обработки необработанных данных, которая имеет внешнее API для настройки. Разработчики вызывают методы LoadRawData и SaveRawData для использования обработки необработанных данных. Для использования этих методов также необходимо задать желаемый формат необработанных данных с помощью класса RawDataSettings. Класс RawDataSettings позволяет разработчикам указать любой формат необработанных данных. Однако для достижения наилучшей производительности необходимо использовать тот формат необработанных данных, в котором данные сохранены. Класс RawDataSettings, определенный в классе RasterImage, помогает определить формат необработанных данных изображения. При передаче экземпляра RawDataSettings в метод LoadRawData данные возвращаются в исходном виде без каких-либо преобразований, что может улучшить производительность. С другой стороны, необходимо учитывать все возможные форматы размещения необработанных данных, что иногда может быть немного сложным.

Для упрощения процесса обработки, на счет некоторого понижения производительности, вы можете указать желаемые RawDataSettings, создав и инициализируя класс с требуемыми настройками необработанных данных. Существуют случаи, когда невозможно вернуть необработанные данные в указанном формате (например, преобразование из цветового пространства CMYK в RGB недоступно в версии 2.4.0). Более того, могут возникнуть ситуации, когда обработка необработанных данных не доступна для формата изображения. Для определения возможности использования методов семейства LoadRawData и SaveRawData необходимо запросить свойство IsRawDataAvailable.

Инсайт

Для формата данных пикселей RGB доступны индексированные (основанные на палитре) и форматы необработанных данных на основе RGB. Индексированные форматы необработанных данных содержат индексы элементов палитры в диапазоне 0..(2^количество бит - 1). Индексированные форматы необработанных данных имеют глубину цвета 1, 2, 4 и 8 бит на пиксель. Остальные форматы - основанные на RGB. При загрузке необработанных данных обязательно учитывайте, что байтов должно быть достаточно для загрузки данных, в противном случае будет сгенерировано соответствующее исключение. Вы можете оценить размер массива байт, умножив размер строки на количество требуемых строк. Размер строки может варьироваться и зависит от формата хранения необработанных данных.

Для достижения наилучшей производительности всегда используйте размер строки необработанных данных, равный значению свойства RasterImage.RawLineSize. Однако иногда может потребоваться добавить дополнительное заполнение строкам необработанных данных, или уменьшить его, и в этом случае может использоваться другой размер строки. Если требуется подмножество ограничивающего прямоугольника изображения, учитывайте сдвиги битов, которые могут возникать для индексированных форматов пикселей RGB. Например, предположим, что у нас есть изображение размером 100x100 пикселей и формат необработанных данных с глубиной цвета 1 бит на пиксель. Вы хотите загрузить прямоугольные необработанные данные с координатами (7,0) и размерами (2,1), или другими словами, вы хотите получить 2 пикселя, начиная с x=7 и y=0. В этом случае вы должны получить следующий формат данных:

todo:image_alt_text

Это означает, что вы получаете 2 байта, где первый байт содержит 7 нежелательных пикселей, затем 1 желаемый пиксель, и второй байт содержит 1 желаемый пиксель и затем 7 нежелательных пикселей. Вы можете спросить, почему мы не сдвинули данные и не объединили эти 2 пикселя в один байт? Ответ прост: для поддержания высокой производительности. Все внутренние операции обычно выполняются со всеми данными, начиная с первого пикселя и заканчивая последним доступным пикселем. Есть редкие ситуации, когда требуется подмножество пикселей. Кроме того, нам неизвестно, как будут обрабатываться эти пиксели в дальнейшем, поэтому сдвиг снизит производительность и сделает код ненужно сложным. Всегда оценивайте правильный бит (необходимо определить правильный байт, поскольку данные всегда поступают с заполненным первым байтом), с которого начнутся запрошенные пиксели. Для вычисления правильного бита может использоваться простая формула: (rect.Left * количество бит) % 8.

Преобразование цветов индексированного RGB

Для достижения максимальной производительности всегда используйте одинаковые настройки исходных и конечных необработанных данных, форматы пикселей и размеры строк. Однако иногда может потребоваться выполнить преобразование данных. Например, вы можете загрузить изображение RGB с глубиной цвета 1 бит на пиксель и сохранить его с глубиной цвета 2 бита на пиксель, или загрузить изображение RGB с глубиной цвета 4 бита и снизить диапазон цвета до 2 бит на пиксель. В любом случае должно быть применено цветовое преобразование. Преобразование индексированных изображений RGB иногда может быть сложным и невозможным без применения некоторых настроек. Нам необходимо определить, как диапазон цвета исходного изображения сопоставляется с целевым цветовым пространством. Для выполнения этой задачи у нас есть различные режимы:

  • Сопоставление палитры (DitheringMethods.PaletteConversion)
  • Сопоставление необработанных данных (DitheringMethods.PaletteIgnore)
  • Пользовательское преобразование (DitheringMethods.CustomConverter)

При использовании преобразования палитры исходное цветовое пространство пытается соответствовать целевому цветовому пространству как можно ближе. Например, предположим у нас есть изображение 4-бит с следующими цветами: [0] RGB=0, 0, 0 [1] RGB=17, 17, 17 [2] RGB=34, 34, 34 [3] RGB=51, 51, 51 [4] RGB=68, 68, 68 [5] RGB=85, 85, 85 [6] RGB=102, 102, 102 [7] RGB=119, 119, 119 [8] RGB=136, 136, 136 [9] RGB=153, 153, 153 [10] RGB=170, 170, 170 [11] RGB=187, 187, 187 [12] RGB=204, 204, 204 [13] RGB=221, 221, 221 [14] RGB=238, 238, 238 [15] RGB=255, 255, 255

Исходное изображение выглядит следующим образом:

todo:image_alt_text

И мы преобразовываем 4-битное изображение в изображение с глубиной цвета 1 бит следующим образом:

[0] RGB = 0, 0, 0 [1] RGB = 255, 255, 255

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

todo:image_alt_text

В режиме сопоставления необработанных данных используется другой сценарий. Палитры исходного и целевого цвета просто игнорируются, и индексы источников отображаются на индексы пунктов назначения. Если найдено значение, которое не может быть сопоставлено с целевым диапазоном (при уменьшении количества бит), тогда используется значение свойства RasterImage.RawFallbackIndex. Значение по умолчанию равно 0 и будет отображено на первый цвет в целевой палитре. Если это значение свойства лежит за пределами целевого диапазона, соответствующее исключение генерируется. Это приводит к менее предсказуемым результатам, которые можно увидеть на следующем изображении:

todo:image_alt_text

Режим преобразования палитры является более правильным решением для задачи сопоставления цветов, но он также требует немного больше времени на завершение, поскольку требуются вычисления для оценки правильного сопоставления палитр. (Обычно между двумя методами практически нет различий в производительности.) С другой стороны, режим преобразования необработанных данных выполняется немного быстрее и может использоваться для грубого цветового преобразования, когда точное сопоставление цветов не столь важно. Например, есть ситуации, когда палитра цветов усечена и ее можно безопасно преобразовать в меньшее количество битов, поскольку дополнительные биты все равно не используются.

Для использования любого из этих подходов используйте свойство RawDitheringMethod класса RasterImage. По умолчанию оно установлено на метод преобразования палитры для достижения наилучшего внешнего вида результатов. Вы можете изменить это свойство перед любым преобразованием (например, при сохранении изображения в поток). Обратите внимание, что методы преобразования палитры и игнорирования палитры не будут применены, если вы загрузили изображение и перезаписали некоторые из оригинальных пиксельных данных, поскольку новые данные попадают в кеш, а кеш хранит данные в максимально доступном формате 32ARGB (на момент версии 2.4.0, подлежит изменениям). Этот формат используется для преодоления проблем возможных различий в диапазонах цветов для загруженных и сохраненных изображений. Кроме того, методы преобразования палитры и игнорирования палитры не будут применены, если изображение загружено в режиме RGB и преобразовано в индексированный режим или наоборот.

Пользовательские конвертеры цвета

Иногда не достаточно использовать стандартный подход к цветовому преобразованию. Возможно, вам захочется использовать пользовательский алгоритм для полной свободы при использовании цветовых преобразований. Когда форматы пикселей исходного и конечного изображения являются форматами индексированных RGB, можно использовать более простой интерфейс IIndexedColorConverter. Вам нужно установить свойство RasterImage.RawIndexedColorConverter на экземпляр интерфейса IIndexedColorConverter и использовать значение DitheringMethods.CustomConverter для свойства RawDitheringMethod. При таком сочетании любое индексированное цветовое преобразование выполняется через указанный экземпляр IIndexedColorConverter. У пользовательского индексированного цветового конвертера определен следующий метод:

 void FillIndexedtoIndexedMap(byte[] map, PixelDataFormat sourceFormat, PixelDataFormat destFormat);

Метод FillIndexedtoIndexedMap вызывается при необходимости конвертации изображения индексированных RGB в формат изображения индексированных RGB (когда любой из 1,2,4 или 8 битов конвертируется друг в друга). Массив map име