Создание изображений и манипуляции с ними при помощи библиотеки gd
Автор: Shuveb Hussain
Перевод: Владимир Меренков


gd это open source библиотека, написанная для облегчения создания и обработки изображений. Она позволяет вам открывать изображения в таких форматах как jpeg, png, xpm и некоторых других. (Из "некоторых других" можно назвать WBMP. Прим.ред.) Вы можете думать о gd как о чем-то, что позволяет: открывать изображения различных форматов и конвертировать их в обобщенный bit-mapped формат в памяти, производить графические операции над этими изображениями, такие как рисование линий, дуг, эллипсов или многоугольников и, наконец, сохранять результирующие изображения в любом из ранее упомянутых форматов. Например, вы можете, используя gd, написать простую программу, запускаемую из командной строки, которая сможет конвертировать файл из формата JPEG в формат PNG. Но gd может больше. С ее помощью можно изменять цвета, копировать, вырезать, объединять или вращать изображения. Еще одна область, где полезна gd - создание изображений "на лету". С gd вы можете программно создать изображение, цвета для него, порисовать на нем и сохранить на диск. Лучше всего gd подходит для создания изображений для web страниц. Это делается возможным с помощью PHP.

Если у вас GNU/Linux система, использующая RPM для управления пакетами, попробуйте ввести

        rpm -q gd

чтобы узнать установлена ли gd. Вы можете скачать последнюю версию исходников с www.boutell.com

(Напоминаю обладателям дистрибутива ALT Linux Master 2.2, что в нём библиотека gd представлена в двух версиях, 1.8.4 и 2.0.4, и пакеты называются libgd1 и libgd2 соответственно. Пакеты с утилитами называются gd1-utils и gd2-utils. В Mandrake Linux 9.1 всё тоже самое за исключением того, что версия 1.x отсутсвует. В RedHat 9.0 пакет, содержащий библиотеки действительно называется gd. Пакет с утилитами -- gd-progs. Прим.ред.)

Создание изображений

Следующая программа создает черную картинку размером 100х100 пикселей с белой диагональной линией.

100x100 image created by gd

Если не хотите набирать вручную, используйте этот листинг

/* File : gd-eg1.c */
#include < gd.h >
#include < stdio.h >

int main() {
        gdImagePtr im; // объявление изображения
        FILE *out; // выходной файл
        int black,white;

        im = gdImageCreate(100,100); // создать изображение 100 на 100 пикселей

        black = gdImageColorAllocate(im, 0, 0, 0); // задать черный цвет
        white = gdImageColorAllocate(im, 255, 255, 255); // задать белый цвет
        gdImageLine(im, 0, 0,100,100, white); // нарисовать линию, 
	// используя заданный белый цвет.

        out = fopen("test.jpg", "w"); // открыть файл
        gdImageJpeg(im, out, -1); // записать изображение
        // в файл, используя установки качества по умолчанию

        /* будем хорошими, уберем за собой */
        fclose(out);
        gdImageDestroy(im);
}

Компилируйте программу следующей командой:

$ gcc gd-eg1.c -lgd

Запустите результирующий a.out файл и вы должны получить файл test.jpg, созданный в текущей директории. Рассмотрев его, вы увидите черную картинку размером 100 на 100 пикселей с пересекающей ее белой линией. Программа, я уверен, проста, но я немного объясню код.

        gdImagePtr im; // объявление изображения  

объявляет указатель на дескриптор изображения.

        im = gdImageCreate(100,100); // создать изображение 100 на 100 пикселей

теперь мы создаем изображение 100 на 100 пикселей и сохраняем возвращаемую функцией ссылку на него в переменной im. Это очень похоже на файловый дескриптор (file handle). Дальнейшие манипуляции производятся с использованием этого указателя.

        black = gdImageColorAllocate(im, 0, 0, 0); // задать черный цвет
        white = gdImageColorAllocate(im, 255, 255, 255); // задать белый цвет   

перед тем как начать что-нибудь рисовать, вы должны определить цвет. Первый определяемый цвет для вновь созданного изображения будет цветом его фона. У функции gdImageColorAllocate четыре аргумента. Первый - указатель на изображение и последующие три это значения красного, зеленого и синего соответственно. Итак, вызов gdImageColorAllocate(im, 0, 0, 0) для вновь созданного изображения закрасит его фон в черный цвет. Мы храним индексы цветов в переменных, т.к. функции рисования и изображения текста требуют значение цвета в качестве аргумента.

        gdImageLine(im, 0, 0,100,100, white); // нарисовать линию, 
	                                      // используя заданный белый цвет.       

Эта функция рисует на изображении, на которое указывает im, линию от левого верхнего угла (0, 0) в правый нижний (100, 100), используя для определения цвета переменную white.

        gdImageJpeg(im, out, -1); // записать изображение в файл, 
	                          // используя установки качества по умолчанию

вызов этой функции записывает изображение в файл на диске в формате JPEG. Последний аргумент этой функции - установка качества для изображений формата JPEG. Он может принимать значения между 1 и 100, где 100 - это наивысшее качество. При передаче значения -1 будет использована установка качества по умолчанию. Подобно этой, существуют функции, которые сохраняют изображения в различных форматах

        gdImagePng(im,out) // сохранить как PNG (обратите внимание на 
	                   // отсутствие установок качества)
        // gdImageGd и gdImageGd2 -- функции для сохранения
	// изображений в формате, определенном библиотекой.

        gdImageDestroy(im);

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

Примите, пожалуйста, во внимание, что формат PNG сейчас хорошо поддерживается и использует более эффективные алгоритмы компрессии. У этого формата также есть достижение, которого нет у формата JPEG: прозрачность (transparency). Изображения формата GIF хотя и достаточно хороши, для полного сжатия используют алгоритм компрессии LZW, запатентованный Unisys. Поддержка формата GIF в gd вскорости будет прекращена. Вы должны прочитать о гонениях против софтверных патентов ... Некоторые web сайты даже объявили себя свободными от GIF, подобно дезодорантам, которые объявляют себя "свободными от фреонов, наносящих повреждения озоновому слою". Подробнее об этом читайте на www.burnallgifs.org

Манипуляция с изображениями

gd позволяет также манипулировать готовыми изображениями вместо того, чтобы создавать новые на пустом месте. Чтобы проиллюстрировать это, следующая программа откроет изображение Tux-а, увеличит немного и изобразит на нем строку "Tux, the Linux Penguin". Кроме рисования текста на изображении, в этой программе мы намереваемся рассмотреть чуть больше функций.

Если не хотите набирать пример вручную, используйте этот листинг

До После
Before manipulation After manipulation
/* File : gd-eg2.c */
#include < gd.h >
#include < stdio.h >

int main()
{
        gdImagePtr oldtux, newtux; // объявление указателей на изображения
        FILE *out, *in;
        int red,white;
        int brect[8];
        char *err;

        in = fopen("tuxin.jpg","r");
        oldtux = gdImageCreateFromJpeg(in);
        newtux = gdImageCreate(150,165); // создание изображения 150 на 165 пикселей

        white = gdImageColorAllocate(newtux, 255, 255, 255); // задать белый цвет
        red = gdImageColorAllocate(newtux, 255, 0, 0); // задать красный цвет

	gdImageCopyResized(newtux,oldtux,0,0,0,0,150,150,oldtux->sx,oldtux->sy);

        err = gdImageStringFT(newtux,brect, red,
	  "/usr/X11R6/lib/X11/fonts/TTF/luxisr.ttf",10,0,0,160,"Tux, The Linux Penguin");

        if(err) fprintf(stderr,"Error : %s\n",err);

        out = fopen("tuxout.jpg", "w"); // открыть файл
        gdImagePng(newtux, out); // записать изображение в файл в формате PNG

        /* будем хорошими, уберем за собой */
        fclose(out);
        fclose(in);
        gdImageDestroy(oldtux);
        gdImageDestroy(newtux);
}
(Хм... Не знаю как у вас, но у меня тестовая программа изменила цвет правой лапки Тукса с зелёной, на серую. Прим.ред.)

Как вы можете видеть, данная программа использует немного больше функций.Эти функции объяснены ниже.

gdImageCopyResized

Эта функция копирует прямоугольную область одного изображения в другое. В процессе копирования размер изображения может быть изменен. Прототип функции выглядит так:

void gdImageCopyResized(gdImagePtr dst, gdImagePtr
src, int dstX, int dstY, int srcX, int srcY, int
destW, int destH, int srcW, int srcH);

sx и sy являются членами структуры gdImagePtr и содержат ширину и высоту изображения соответственно.

Вы могли бы обратить внимание, что изображение в результате растяжения перестало быть "гладким". Если у вас версия 2.0 или выше, предпочтительнее было бы использоватьg функцию gdImageCopyResampled, которая сглаживает неровные края, получившиеся в результате растягивания или сжатия изображения. Если вы хотите копировать часть изображения без изменения его размера, тогда попробуйте gdImageCopy. Для вращения копируемого изображения, попробуйте использовать новую функцию gdImageCopyRotated.

gdImageStringFT

Эта функция пишет на изображении текст, используя библиотеку freetype, об этом говорят буквы "FT" в имени функции. У вас должна быть установлена freetype и gd должна быть скомпилирована с поддержкой freetype.

Прототип функции:

char *gdImageStringFT(gdImagePtr im, int *brect, int
fg, char *fontname, double ptsize, double angle, int
x, int y, char *string)

В случае проблем эта функция возвращает символьный указатель, который указывает на сообщение об ошибке, в противном случае возвращается 0. Массив brect заполнен координатами прямоугольника, ограничивающего напечатанную строку.

(
        brect[0]        нижний левый угол, X координата
        brect[1]        нижний левый угол, Y координата
        brect[2]        нижний правый угол, X координата
        brect[3]        нижний правый угол, Y координата
        brect[4]        верхний правый угол, X координата
        brect[5]        верхний правый угол, Y координата
        brect[6]        верхний левый угол, X координата
        brect[7]        верхний левый угол, Y координата
Прим.пер.)

Вы можете также определить размер ограничивающего прямоугольника без реального печатания строки. Чтобы сделать это передайте NULL вместо указателя на изображение. По какой-то странной причине вы должны передавать в функцию абсолютный путь к вашему шрифту. Так что если даже файл шрифта находится в текущей директории, вы должны указать полный путь. Используются только TTF шрифты. Если вам нужна простота, можете использовать функцию gdImageString. Freetype не нужна для нормальной работы этой функции, она использует любой из пяти встроенных в gd шрифтов.

Спасаясь от оков общества, Shuveb вынужден жить в небольшом историческом городке на юге Индии. Он считает, что жизнь это не Сон В Летнюю Ночь или Буря, а комедия ошибок, живущая по принципу Как Вам Это Понравится. В свободное от философских размышлений время он C программист, который часто находится в замешательстве относительно того, что на этот раз будет вытворять вон та ма-а-аленькая "звёздочка" с указателем на переменную. APR Bristol -- это та компания, которая имеет несчастье оплачивать его обучение Linux.


Copyright (c) 2003, Shuveb Hussain. Copying license http://www.linuxgazette.com/copying.html
Published in Issue 91 of Linux Gazette, June 2003


Вернуться на главную страницу