Использование библиотеки libjpeg
Зачастую результатом выполнения CGI приложения является не HTML документ, а картинка. В этой статье рассматривается просто и несложный способ генерации JPEG изображения с помощью библиотеки libjpeg.
Подключим заголовочные файлы. Так как мы пишем на C++ (уж не могу я отказаться от простых удобств этого языка), а libjpeg написана на C, то используем конструкцию extern «C»
#include <stdio.h> #include <stdlib.h> extern "C" { #include <jpeglib.h> }
Так как пишем мы CGI приложение, то первое что должна вывести наша программа — Content-Type. Кроме того определим высоту и ширину изображения и выделим для него память. Переменная quality будет задавать качество JPEG изображения (изменяется от 0 до 100).
Изображение будем хранить в формате RGB, то есть каждая точка будет описана тремя байтами: R — уровнем красного (от 0 до 255), G — уровнем зеленого (от 0 до 255) и B — уровнем синего (от 0 до 255). Именно для этого и используется умножение на 3.
void main(void) { printf("Content-Type: image/jpeg\n\n"); int width=400; int height=400; int quality=75; char *scr=(char*)malloc(width*height*3);
Нарисуем что-нибудь незамысловатое.
for (int i=0;i<width ;i++) for (int j=0;j<height;j++) { char *p=scr+j*width*3+i*3; *p=i+j;p++; *p=i-j;p++; *p=i*j; }
Инициализируем структуры jpeg_compress_struct и jpeg_error_mgr. Зададим выходной файл (stdout), зададим ширину, высоту и качество сжатия.
/* Compress to JPEG */ struct jpeg_compress_struct cinfo; struct jpeg_error_mgr jerr; cinfo.err = jpeg_std_error(&jerr); jpeg_create_compress(&cinfo); jpeg_stdio_dest(&cinfo, stdout); cinfo.image_width=width; cinfo.image_height=height; cinfo.input_components=3; cinfo.in_color_space=JCS_RGB; jpeg_set_defaults(&cinfo); jpeg_set_quality(&cinfo, quality, true); jpeg_start_compress(&cinfo, TRUE);
Теперь построчно обработаем изображение с помощью функции jpeg_write_scanlines
JSAMPROW row_pointer[1]; int row_stride; row_stride = cinfo.image_width*3; while (cinfo.next_scanline < cinfo.image_height) { row_pointer[0]=(JSAMPLE *)(scr+cinfo.next_scanline*row_stride); jpeg_write_scanlines(&cinfo, row_pointer, 1); }
И в завершении вызовем оставшиеся действия для обработки изображения (в самом простейшем случае ничего, ровным счетом, не произойдет) и освободим память.
jpeg_finish_compress(&cinfo); jpeg_destroy_compress(&cinfo); free(scr); }
С помощью следующей строки вы сможете откомпилировать эту программу. Опции -I и -L не обязательный. Под Linux у меня работало и без них, а вот под FreeBSD пришлось указать.
gcc -o jpeg -I/usr/local/include -L/usr/local/lib main.cpp -ljpeg
При выполнении этой программы у вас должно получится следующее изображение:
Исходный код: main.cpp
#include <stdio.h> #include <stdlib.h> extern "C" { #include <jpeglib.h> } void main(void) { printf("Content-Type: image/jpeg\n\n"); int width=400; int height=400; int quality=75; char *scr=(char*)malloc(width*height*3); for (int i=0;i<width;i++) for (int j=0;j<height;j++) { char *p=scr+j*width*3+i*3; *p=i+j;p++; *p=i-j;p++; *p=i*j; } /* Compress to JPEG */ struct jpeg_compress_struct cinfo; struct jpeg_error_mgr jerr; cinfo.err = jpeg_std_error(&jerr); jpeg_create_compress(&cinfo); jpeg_stdio_dest(&cinfo, stdout); cinfo.image_width=width; cinfo.image_height=height; cinfo.input_components=3; cinfo.in_color_space=JCS_RGB; jpeg_set_defaults(&cinfo); jpeg_set_quality(&cinfo, quality, true); jpeg_start_compress(&cinfo, TRUE); JSAMPROW row_pointer[1]; int row_stride; row_stride = cinfo.image_width*3; while (cinfo.next_scanline < cinfo.image_height) { row_pointer[0]=(JSAMPLE *)(scr+cinfo.next_scanline*row_stride); jpeg_write_scanlines(&cinfo, row_pointer, 1); } jpeg_finish_compress(&cinfo); jpeg_destroy_compress(&cinfo); free(scr); }
Более подробно про использование библиотеки читайте в файлe src/libjpeg.doc ее дистрибутива.
Скачать библиотеку libjpeg
Комментарии