Общие сведения

Статья демонстрирует основные приемы по загрузке и рендерингу изображений

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

Библиотека располагает набором кодеков и программных интерфейсов для работы с основными стандартизованными типами изображений. Кодеки поставляются в виде отдельных загружаемых библиотеки и их перечень может быть легко расширен. Для точной настройки кодеков используется конфигурационный файл /etc/system/config/img.conf. Полный перечень дополнительных компонентов библиотеки включает:

Основной набор кодеков включает:

img_codec_bmp.so
Кодек для формата Windows Bitmap. Полностью поддерживает формат Microsoft BMP, включая вариант для OS/2. Не поддерживает формат v1.x DDB.
img_codec_gif.so
Кодек для формата Graphics Interchange Format. Поддерживает GIF 87a и GIF 89a версии. Этот кодек поддерживает расширения, которые наиболее актуальны для формата: прозрачность, интерлейсинг, цепочки кадров и др. Расширения вроде встраивания текста, комментариев и пользовательских данных игнорируются.

Note: Кодек поддерживает декодирование, но не кодирование.

img_codec_jpg.so
Кодек для формата Joint Photographic Experts Group. Поддерживаются 24-битные RGB, YUV и изображения в оттенках серого.
img_codec_pcx.so
Кодек для формата PiCture eXchange (PCX).
img_codec_png.so
Кодек для формата Portable Networks Graphics. Предоставляет полную поддержку PNG с альфа-каналом, прозрачностью и интерлейсингом. Следующие аспекты игнорируются:
img_codec_sgi.so
Кодек для формата SGI. Поддерживаются черно-белые, цветные изображения и в оттенках серого (*sgi, *.rgb, *.rgba, *.bw).

Note: Кодек поддерживает декодирование, но не кодирование.

img_codec_tga.so
Кодек для формата Truevision Graphics Adapter. При декодировании кодек поддерживает Run Length Encoding (RLE) компрессию и следующие форматы: При кодировании кодек использует true color (8888) 32-битное RLE.

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

Также приложению следует выполнить следующие действия:

Подключение библиотеки
Загрузка изображения
Связывание изображения с GF
Вывод изображения в поверхность
Освобождение ресурсов

Посмотрим на эти шаги подробнее.

Подключение библиотеки

При вызове функции img_lib_attach() библиотека инициализирует и загружает доступные кодеки, указанные в конфигурационном файле /etc/system/config/img.conf. В этом файле можно настроить перечень кодеков и расширений файлов. Путь поиска конфигурационного файла можно переопределить с помощью переменной окружения LIBIMG_CFGFILE.

Пример использования img_lib_attach():

img_lib_t ilib = NULL;
int rc;
...
if ( (rc = img_lib_attach( &ilib )) != IMG_ERR_OK )
{
fprintf( stderr, "img_lib_attach() failed: %d\n", rc );
return (-1);
}

Загрузка изображения

Подразумеваются следующие шаги:

  1. Перечисление кодеков. Для этого нужно получить список загруженных кодеков: img_codec_list().


    Note: Если имеются дополнительные сведения об изображении (например, mime-тип или расширение файла), следует рассмотреть использование функций img_codec_list_byext() и img_codec_list_bymime(). Это позволит ограничить перечень подходящих кодеков. Также стоит учитывать, что расширение и mime-тип не обязаны гарантировать, что содержимое файла соответствует форматы. В общем случае целесообразно проверять полный перечень кодеков на совместимость с объектом.

  2. Определить источник данных. Это может быть файл, TCP/IP сокет или буфер в памяти. На данном этапе обычно получается порция данных или открывается файл изображения.

  3. Ассоциирование IO инетрфейса библиотеки с источником данных. Декодеры библиотеки требуют типичных способов доступа к данным, например, потока ввода-вывода. Используйте функцию io_open() для ассоциирования io_stream_t с источником данных из предыдущего шага.

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

  5. Инициализация и декодирование. На этом шаге декодер уведомляется о необходимости выполнить операции, что позволяет ему выделить требуемые ресурсы. Это осуществляется в вызове img_decode_begin().

  6. Декодирование кадра. Вызов img_decode_frame() позволяет получать декодированные кадры до тех пор, пока они не закончатся в источнике (в этом случае img_decode_frame() вернет IMG_ERR_NODATA).

  7. Завершение декодирования. Вызов img_decode_finish() позволяет декодеру освободить потребленные ресурсы.

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

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

Пример использования img_load_file():

int rc;
img_t img;
...
/* initialize an img_t by setting its flags to 0 */
img.flags = 0;
/* if we want, we can preselect a format (ie force the image to be
loaded in the format we specify) by enabling the following two
lines */
img.format = IMG_FMT_PKLE_ARGB1555;
img.flags |= IMG_FORMAT;
/* likewise, we can 'clip' the loaded image by enabling the following */
img.w = 100;
img.flags |= IMG_W;
img.h = 100;
img.flags |= IMG_H;
if ( (rc = img_load_file( ilib, argv[optind], NULL, &img )) != IMG_ERR_OK )
{
fprintf( stderr, "img_load_file(%s) failed: %d\n", argv[optind], rc );
return (-1);
}
fprintf( stdout, "img is %dx%dx%d\n", img.w, img.h, IMG_FMT_BPP( img.format ) );
/* for our purposes we''re done with the img lib */
img_lib_detach( ilib );

Связывание изображения с GF

Данный шаг более сложный. Следует определить зависим ли кадр от палитры и установить ее:

gf_palette_t palette;
...
if ( img.format & IMG_FMT_PALETTE )
{
/* setup palette if necessary */
palette.ncolors = img.npalette;
palette.colors = img.palette;
} else
if ( img.format == IMG_FMT_G8 )
{
/* we can render G8 images in GF by using a palette of grays */
palette.ncolors = 256;
palette.colors = (img_color_t *)g8pal;
}

Затем следует создать на основе изображения поверхность, сделав тем самым доступным его для GF API. Выполнить это можно с помощью gf_surface_attach() как указано ниже:

/* attach a surface to the image data; this allows us to blit the image
data to another surface (or the display) in GF */
int rc = gf_surface_attach( &img_surf, setup.gdev, img.w, img.h,
img.access.direct.stride,
img_fmt_to_gf( img.format ),
&palette, img.access.direct.data, 0 );
if ( rc != GF_ERR_OK )
{
fprintf( stderr, "gf_surface_attach() failed: %d\n", rc );
/* might fail here if the decoder gave us a format that cannot
map to GF; in this case we could have preselected a format
that is supported by GF (code above shows how to do this) */
return (-1);
}

Поверхности, созданные через gf_surface_attach(), имеют ряд ограничений:

Вывод изображения в поверхность

Перед блиттингом изображения в поверхность следует проконтролировать альфа-канал и обработку прозрачности:

gf_setup_t setup;
...
if ( img.flags & IMG_TRANSPARENCY )
{
/* we can handle transparency in GF using chroma */
gf_chroma_t chroma;
memset( &chroma, 0, sizeof chroma );
chroma.mode = GF_CHROMA_OP_SRC_MATCH | GF_CHROMA_OP_NO_DRAW;
if ( img.format & IMG_FMT_PALETTE )
{
chroma.color0 = img.palette[img.transparency.index];
} else
if ( IMG_FMT_BPP(img.format) < 24 )
{
chroma.color0 = img.transparency.rgb16;
} else {
chroma.color0 = img.transparency.rgb32;
}
gf_context_set_chroma( setup.context, &chroma );
}
if ( img.format & IMG_FMT_ALPHA )
{
gf_alpha_t alpha;
memset( &alpha, 0, sizeof alpha );
alpha.mode = GF_ALPHA_M1_SRC_PIXEL_ALPHA | GF_BLEND_SRC_M1 | GF_BLEND_DST_1mM1;
gf_context_set_alpha( setup.context, &alpha );
}

Блиттинг изображения в поверхность выполняется функцией gf_draw_blit2():

gf_draw_blit2( setup.context, img_surf, NULL, 0, 0,
img.w - 1, img.h - 1, setup.x1, setup.y1 );

Освобождение ресурсов

После завершения использования библиотеки работы с изображениями следует озаботиться освобождением ресурсов:

/* it's a good idea to do this before we free the image to ensure the
renderer is done with the data */
gf_draw_finish( setup.context );
/* unlock the h/w */
gf_draw_end( setup.context );
if ( img.format & IMG_FMT_ALPHA )
gf_context_disable_alpha( setup.context );
if ( img.flags & IMG_TRANSPARENCY )
gf_context_disable_chroma( setup.context );
/* release the attached surface; we're not going to blit from it any
more (in real life this surface could be recycled if needed) */
gf_surface_free( img_surf );
/* above code only releases the surface; we still have the actual image
data hanging around. We relied on the library to allocate this for
us. The following is all that's needed when we rely on this default
behaviour (note that this free() takes care of the palette also,
if applicable, since the lib allocates it all in one chunk) */
free( img.access.direct.data );




Предыдущий раздел: Библиотека Image