Самоучитель PHP 4 - Котеров Д. В.
.pdf318 |
Часть IV. Стандартные функции PHP |
Эти функции загружают изображения из файла в память и возвращают его идентификатор. Как и после вызова imageCreate(), дальнейшая работа с картинкой возможна только через этот идентификатор. При загрузке с диска изображение распаковывается и хранится в памяти уже в неупакованном формате, для того чтобы можно было максимально быстро производить с ним различные операции, такие как масштабирование, рисование линий и т. д. При сохранении на диск или выводе в браузер функцией imagePng() (или, соответственно, imageJpeg() и imageGif()) картинка автоматически упаковывается.
Стоит заметить, что не обязательно все три функции будут доступны в вашей версии PHP. Скорее всего, в ней не окажется функции imageCreateFromGif(), а возможно, и imageCreateFromJpeg(), потому что от первой разработчики GD просто отказались, а вторая появилась сравнительно недавно. Надеюсь, в скором времени ситуация нормализуется, но сейчас, к сожалению, это не так.
Определение параметров изображения
Как только картинка создана и получен ее идентификатор, GD становится совершенно все равно, какой формат она имеет и каким путем ее создали. То есть все остальные действия с картинкой происходят через ее идентификатор, вне зависимости от формата, и это логично — ведь в памяти изображение все равно хранится в распакованном виде (наподобие BMP), а значит, информация о ее формате нигде не используется. Так что вполне возможно открыть PNG-изображение с помощью imageCreateFromPng() и сохранить ее на диск функцией imageJpeg(), уже в другом формате. В дальнейшем можно в любой момент времени определить размер загруженной картинки, воспользовавшись функциями imageSX() и imageSY():
int imageSX(int $im)
Функция возвращает горизонтальный размер изображения, заданного своим идентификатором, в пикселах.
int imageSY(int $im)
Возвращает высоту картинки в пикселах.
int imageColorsTotal(int $im)
Эту функцию имеет смысл применять только в том случае, если вы работаете с изображениями, "привязанными" к конкретной палитре — например, с файлами GIF. Она возвращает текущее количество цветов в палитре. Как мы вскоре увидим, каждый вызов imageColorAllocate() увеличивает размер палитры. В то же время известно, что если при небольшом размере палитры GIF-картинка сжимается очень хорошо, то при переходе через степень двойки (например, от 16 к 17 цветам) эффективность сжатия заметно падает, что ведет к увеличению размера (так уж устроен
Глава 23. Работа с изображениями |
319 |
формат GIF). Если мы не хотим этого допустить и собираемся вызывать imageColorAllocate() только до предела 16 цветов, а затем перейти на использование imageColorClosest(), нам очень может пригодиться рассматриваемая функция.
Сохранение изображения
Давайте займемся функцией, поставленной в листинге 23.1 "на предпоследнее место", которая, собственно, и выполняет большую часть работы — выводит изображение в браузер пользователя. Оказывается, эту же функцию можно применять и для сохранения рисунка в файл.
int imagePng(int $im [,string $filename]) или int imageJpeg(int $im [,string $filename]) или int imageGif(int $im [,string $filename])
Эти функции сохраняют изображение, заданное своим идентификатором и находящееся в памяти, на диск, или же выводят его в браузер. Разумеется, вначале изображение должно быть загружено или создано при помощи функции imageCreate(), т. е. мы должны знать его идентификатор $im.
Если аргумент $filename опущен, то сжатые данные в соответствующем формате выводятся прямо в стандартный выходной поток, т. е. в браузер. Нужный заголовок Content-type при этом не выводится, ввиду чего нужно выводить его вручную при помощи Header(), как это было показано в примере из листинга 23.1.
Некоторые браузеры не требуют вывода правильного Content-type, а опре- деляют, что перед ними рисунок, по нескольким первым байтам присланных данных. Ни в коем случае не полагайтесь на это! Дело в том, что все еще су- ществуют браузеры, которые этого делать не умеют. Кроме того, такая техника идет вразрез со стандартами HTTP.
Фактически, вы должны вызвать одну из трех команд, в зависимости от типа изображения:
Header("Content-type: image/png") для PNG
Header("Content-type: image/jpeg") для JPEG
Header("Content-type: image/gif") для GIF
Рекомендую их вызывать не в начале сценария, а непосредственно перед вызовом imagePng(), imageGif() или imageJpeg(), поскольку иначе вы не сможете никак увидеть сообщения об ошибках и предупреждения, которые, возможно, будут сгенерированы программой.
320 |
|
Часть IV. Стандартные функции PHP |
|
|
|
|
|
|
К рассмотренным только что функциям можно сделать точно такие же замеча- ния, как и к семейству imageCreateFromXXX(), т. е., некоторые из них могут отсутствовать — скорее всего, последняя. Однако случаются и забавные казу- сы. Я видел версию PHP, в которой не поддерживалась вообще ни одна из этих функций, ровно как и функции imageCreateFromXXX(). В то же время imageCreate() работала (во всяком случае, так казалось). Возникает инте- ресный вопрос: мы можем создавать изображения, рисовать в них линии, кру- ги, выводить текст, но не в состоянии ни сохранить их где-нибудь, ни даже за- грузить уже готовую картинку с диска. Зачем тогда вообще были нужны все остальные функции?..
Работа с цветом в формате RGB
Наверное, теперь вам захочется что-нибудь нарисовать на пустой или только что загруженной картинке. Но чтобы рисовать, нужно определиться, каким цветом это делать. Проще всего указать цвет заданием тройки RGB-значений (от red-green-blue) — это три цифры от 0 до 255, определяющие содержание красной, зеленой и синей составляющих в нужном нам цвете. Число 0 обозначает нулевую яркость соответствующей компоненты, а 255 — максимальную интенсивность. Например, (0,0,0) зада-
ет черный цвет, (255,255,255) — белый, (255,0,0) — ярко-красный, (255,255,0) —
желтый и т. д.
Правда, GD не умеет работать с такими тройками напрямую. Она требует, чтобы перед использованием RGB-цвета был получен его специальный идентификатор. Дальше вся работа опять же осуществляется через этот идентификатор. Скоро станет ясно, зачем нужна такая техника.
Создание нового цвета
int imageColorAllocate(int $im, int $red, int $green, int $blue)
Функция возвращает идентификатор цвета, связанного с соответствующей тройкой RGB. Обратите внимание, что первым параметром функция требует идентификатор изображения, загруженного в память или созданного до этого. Практически каждый цвет, который планируется в дальнейшем использовать, должен быть получен (определен) при помощи вызова этой функции. Почему "практически" — станет ясно после рассмотрения функции imageColorClosest().
Получение ближайшего цвета
Давайте разберемся, зачем это придумана такая технология работы с цветами через промежуточное звено — идентификатор цвета. А дело все в том, что некоторые форматы изображений (такие как GIF и частично PNG) не поддерживают любое количе-
Глава 23. Работа с изображениями |
321 |
ство различных цветов в изображении. А именно, в GIF количество одновременно присутствующих цветов ограничено цифрой 256, причем чем меньше цветов используется в рисунке, тем лучше он "сжимается" и тем меньший размер имеет файл. Тот набор цветов, который реально использован в рисунке, называется его палитрой.
Представим себе, что произойдет, если все 256 цветов уже "заняты" и вызывается функция imageColorAllocate(). В этом случае она обнаружит, что палитра заполнена полностью, и найдет среди занятых цветов тот, который ближе всего находится к запрошенному — будет возвращен именно его идентификатор. Если же "свободные места" в палитре есть, то они и будут использованы этой функцией (конечно, если в палитре вдруг не найдется точно такой же цвет, как запрошенный — обычно дублирование одинаковых цветов всячески избегается).
int imageColorClosest(int $im, int $red, int $green, int $blue)
Наверное, вы уже догадались, зачем нужна функция imageColorClosest(). Вместо того чтобы пытаться выискать свободное место в палитре цветов, она просто возвращает идентификатор цвета, уже существующего в рисунке и находящегося ближе всего к затребованному. Таким образом, нового цвета в палитру не добавляется. Если палитра невелика, то функция может вернуть не совсем тот цвет, который вы ожидаете. Например, в палитре из трех цветов "красный-зеленый-синий" на запрос желтого цвета будет, скорее всего, возвращен идентификатор зеленого — он "ближе всего" с точки зрения GD соответствует понятию "зеленый".
Эффект прозрачности
Функцию imageColorClosest() можно и нужно использовать, если мы не хотим допустить разрастания палитры и уверены, что требуемый цвет в ней уже есть. Однако есть и другое, гораздо более важное, ее применение — определение эффекта прозрачности для изображения. "Прозрачный" цвет рисунка — это просто те точки, которые в браузер не выводятся. Таким образом, через них "просвечивает" фон. Прозрачный цвет у картинки всегда один, и задается он при помощи функции imageColorTransparent().
int imageColorTransparent(int $im [,$int col])
Функция imageColorTransparent() указывает GD, что соответствующий цвет $col (заданный своим идентификатором) в изображении $im должен обозначиться как прозрачный. Возвращает она идентификатор установленного до этого прозрачного цвета, либо false, если таковой не был определен ранее.
Не все форматы поддерживают задание прозрачного цвета — например, JPEG не может его содержать.
Например, мы нарисовали при помощи GD птичку на кислотно-зеленом фоне и хотим, чтобы этот фон как раз и был "прозрачным" (вряд ли у птички есть части тела
322 |
Часть IV. Стандартные функции PHP |
такого цвета, хотя с нашей экологией все может быть...). В этом случае нам потребуются такие команды:
$tc=imageColorClosest($im,0,255,0); imageColorTransparent($im,$tc);
Обратите внимание на то, что применение функции imageColorAllocate() здесь совершенно бессмысленно, потому что нам нужно сделать прозрачным именно тот цвет, который уже присутствует в изображении, а не новый, только что созданный.
Получение RGB-составляющих
array imageColorsForIndex(int $im, int $index)
Функция возвращает ассоциативный массив с ключами red, green и blue (именно в таком порядке), которым соответствуют значения, равные величинам компонент RGB в идентификаторе цвета $index. Впрочем, мы можем и не обращать особого внимания на ключи и преобразовать возвращенное значение как список:
$c=imageColorAt($i,0,0); list($r,$g,$b)=array_values(imageColorsForIndex($i,$c)); echo "R=$r, g=$g, b=$b";
Эта функция ведет себя противоположно по отношению к imageCollorAllocate()
или imageColorClosest().
Графические примитивы
Здесь мы рассмотрим минимальный набор функций для работы с картинками. Приведенный список функций не полон и постоянно расширяется вместе с развитием GD. Но все же он содержит те функции, которые вы будете употреблять в 99% случаев. За полным списком функций обращайтесь к документации или на http://ru.php.net.
Копирование изображений
int imageCopyResized(int $dst_im, int $src_im, int $dstX, int $dstY, int $srcX, int $srcY, int $dstW, int $dstH, int $srcW, int $srcH)
Эта функция — одна из самых мощных и универсальных, хотя и выглядит просто ужасно. С помощью нее можно копировать изображения (или их участки), перемещать и масштабировать их…. Пожалуй, 10 параметров для функции — чересчур, но разработчики PHP пошли таким путем. Что же, это их право...
Итак, $dst_im задает идентификатор изображения, в который будет помещен результат работы функции. Это изображение должно уже быть создано или загружено и иметь надлежащие размеры. Соответственно, $src_im — идентификатор изображе-
Глава 23. Работа с изображениями |
323 |
ния, над которым проводится работа. Впрочем, $src_im и $dst_im могут и совпадать.
Параметры ($srcX, $srcY, $srcW, $srcH) (обратите внимание на то, что они следуют при вызове функции не подряд!) задают область внутри исходного изображения, над которой будет осуществлена операция — соответственно, координаты ее верхнего левого угла, ширину и высоту.
Наконец, четверка ($dstX, $dstY, $dstW, $dstH) задает то место на изображении $dst_im, в которое будет "втиснут" указанный в предыдущей четверке прямоугольник. Заметьте, что, если ширина или высота двух прямоугольников не совпадают, то картинка автоматически будет нужным образом растянута или сжата.
Таким образом, с помощью функции imageCopyResized() мы можем:
rкопировать изображения;
rкопировать участки изображений;
rмасштабировать участки изображений;
rкопировать и масштабировать участки изображения в пределах одной картинки.
В последнем случае возникают некоторые сложности, а именно, когда тот блок, из которого производится копирование, частично налагается на место, куда он должен быть перемещен. Убедиться в этом проще всего экспериментальным путем. Почему разработчики GD не предусмотрели средств, которые бы корректно работали и в этом случае, не совсем ясно.
Прямоугольники
int imageFilledRectangle(int $im,int $x1,int $y1,int $x2,int $y2,int $c)
Название этой функции говорит за себя: она рисует закрашенный прямоугольник в изображении, заданном идентификатором $im, цветом $col (полученным, например,
при помощи функции imageColorAllocate()). Координаты ($x1,$y1) и ($x2,$y2)
задают координаты верхнего левого и правого нижнего углов, соответственно (отсчет, как обычно, начинается с левого верхнего угла и идет слева направо и сверху вниз).
Эта функция часто применяется для того, чтобы целиком закрасить только что созданный рисунок, например, прозрачным цветом:
$i=imageCreate(100,100); $c=imageColorAllocate($i,0,0,0); imageColorTransparent($i,$c);
imageFilledRectangle($i,0,0,imageSX($i)-1,imageSY($i)-1,$c); // дальше работаем с изначально прозрачным фоном
int imageRectangle(int $im, int $x1, int $y1, int $x2, int $y2, int $col)
Функция imageRectangle() рисует в изображении прямоугольник с границей толщиной 1 пиксел цветом $col. Параметры задаются так же, как и в функции imageFilledRectangle().
324 |
Часть IV. Стандартные функции PHP |
Линии
int imageLine(int $im, int $x1, int $y1, int $x2, int $y2, int $col)
Эта функция рисует сплошную тонкую линию в изображении $im, проходящую через точки ($x1,$y1) и ($x2,$y2), цветом $col. Линия получается слабо связанной (про связность см. чуть ниже).
int imageDashedLline(int $im,int $x1,int $y1,int $x2,int $y2,int $col)
Функция imageDashedLine() работает почти так же, как и imageLine(), только рисует не сплошную, а пунктирную линию. К сожалению, ни размер, ни шаг штрихов задавать нельзя, так что, если вам обязательно нужна пунктирная линия произвольной фактуры, придется заняться математическими расчетами и использовать imageLine().
Дуга сектора
int imageArc(int $im,int $cx,int $cy,int $w,int $h,int $s,int $e,int $c)
Функция imageArc() рисует в изображении $im дугу сектора эллипса от угла $s до $e (углы указываются в градусах против часовой стрелки, отсчитываемых от горизонтали). Эллипс рисуется такого размера, чтобы вписываться в прямоугольник ($x,$y,$w,$h), где $w и $h задают его ширину и высоту, а $x и $y — координаты левого верхнего угла. Сама фигура не закрашивается, обводится только ее контур, для чего используется цвет $c.
Закраска произвольной области
int imageFill(int $im, int $x, int $y, int $col)
Функция imageFill() выполняет сплошную заливку одноцветной области, содержащей точку с координатами ($x,$y) цветом $col. Нужно заметить, что современные алгоритмы заполнения работают довольно эффективно, так что не стоит особо заботиться о скорости ее работы. Итак, будут закрашены только те точки, к которым можно проложить "одноцветный сильно связанный путь" из точки ($x,$y).
Две точки называются связанными сильно, если у них совпадает по крайней мере одна координата, а по другой координате они отличаются не более, чем на 1 в любую сторону.
int imageFillToBorder(int $im, int $x, int $y, int $border, int $col)
Эта функция очень похожа на imageFill(), только она выполняет закраску не одноцветных точек, а любых, но до тех пор, пока не будет достигнута граница цвета
Глава 23. Работа с изображениями |
325 |
$border. Под границей здесь понимается последовательность слабо связанных то- чек.
Две точки называются слабо связанными, если каждая их координата отлича- ется от другой не более, чем на 1 в любом направлении. Очевидно, всякая сильная связь является также и слабой.
Многоугольники
int imagePolygon(int $im, list $points, int $num_points, int $col)
Эта функция рисует в изображении $im многоугольник, заданный своими вершинами. Координаты углов передаются в массиве-списке $points, причем $points[0]=x0, $points[1]=y0, $points[2]=x1, $points[3]=y1, и т. д. Пара-
метр $num_points указывает общее число вершин — на тот случай, если в массиве их больше, чем нужно нарисовать. Многоугольник не закрашивается — только рисуется его граница цветом $col.
int imageFilledPolygon(int $im, list $points, int $num_points, int $col)
Функция imageFilledPolygon() делает практически то же самое, что и imagePolygon(), за исключением одного очень важного свойства: полученный многоугольник целиком заливается цветом $col. При этом правильно обрабатываются вогнутые части фигуры, если она не выпукла.
Работа с пикселами
int imageSetPixel(int $im, int $x, int $y, int $col)
Эта функция практически не интересна, т. к. выводит всего один пиксел цвета $col в изображении $im, расположенный в точке ($x,$y). Не думаю, чтобы с помощью нее можно было закрасить хоть какую-нибудь сложную фигуру, потому что, как мы знаем, PHP довольно медленно работает с длинными циклами, а значит, даже рисование обычной линии с использованием этой функции будет очень дорогим занятием.
int imageColorAt(int $im, int $x, int $y)
В противоположность своему антиподу — функции imageSetPixel() — функция imageColorAt() не рисует, а возвращает цвет точки, расположенной на координатах ($x,$y). Возвращается идентификатор цвета, а не его RGB-представление.
Функцию удобно использовать, опять же, для определения, какой цвет в картинке должен быть прозрачным. Например, все у той же птички на кислотно-зеленом фоне мы достоверно знаем, что прозрачный цвет точно приходится на точку с координатами (0,0). Таким образом, теперь мы сможем в любой момент сменить цвет фона на
326 |
Часть IV. Стандартные функции PHP |
мертвенно-голубой (который тоже у реальной птицы вряд ли встретится), и программа все равно будет работать правильно.
Работа с фиксированными шрифтами
Библиотека GD имеет некоторые возможности по работе с текстом и шрифтами. Шрифты представляют собой специальные ресурсы, имеющие собственный идентификатор, и чаще всего загружаемые из файла или встроенные в GD. Каждый символ шрифта может быть отображен лишь в моноцветном режиме, т. е. "рисованные" символы не поддерживаются. Встроенных шрифтов всего 5 (идентификаторы от 1 до 5), чаще всего в них входят моноширинные символы разных размеров. Остальные шрифты должны быть предварительно загружены.
Загрузка шрифта
int imageLoadFont(string $file)
Функция загружает файл шрифтов и возвращает идентификатор шрифта — это будет цифра, большая 5, потому что пять первых номеров зарезервированы как встроенные. Формат файла — бинарный, а потому зависит от архитектуры машины. Это значит, что файл со шрифтами должен быть сгенерирован по крайней мере на машине с процессором такой же архитектуры, как и у той, на котором вы собираетесь использовать PHP. Вот формат этого файла (табл. 23.1). Левая колонка задает смещение начала данных внутри файла, а группами цифр, записанных через дефис, определяется, до какого адреса продолжаются данные.
|
|
Таблица 23.1. Формат файла со шрифтом |
|
|
|
Смещение |
Тип |
Описание |
|
|
|
Byte 0-3 |
long |
Число символов в шрифте (nchars) |
byte 4-7 |
long |
Индекс первого символа шрифта (обычно 32 — пробел) |
|
|
|
|
|
Таблица 23.1 (окончание) |
|
|
|
Смещение |
Тип |
Описание |
|
|
|
byte 8-11 |
long |
Ширина (в пикселах) каждого знака (width) |
byte 12-15 |
long |
Высота (в пикселах) каждого знака (height) |
byte 16-... |
array |
Массив с информацией о начертании каждого символа, по |
|
|
одному байту на пиксел. На один символ, таким образом, |
|
|
приходится width*height байтов, а на все — |
|
|
width*height*nchars байтов. 0 означает отсутствие точки в |
|
|
данной позиции, все остальное — ее присутствие |
|
|
|
Глава 23. Работа с изображениями |
327 |
Параметры шрифта
После того как шрифт загружен, его можно использовать (встроенные шрифты, конечно же, загружать не требуется).
int imageFontHeight(int $font)
Возвращает высоту в пикселах каждого символа в заданном шрифте. int imageFontWidth(int $font)
Возвращает ширину в пикселах каждого символа в заданном шрифте.
Вывод строки
int imageString(int $im, int $font, int $x, int $y, string $s, int $col)
Выводит строку $s в изображение $im, используя шрифт $font и цвет $col. Координаты ($x,$y) будут координатами левого верхнего угла прямоугольника, в который вписана строка.
int imageStringUp(int $im, int $font, int $x, int $y, string $s, int $c)
Эта функция также выводит строку текста, но не в горизонтальном, а в вертикальном направлении. Верхний левый угол, по-прежнему, задается координатами ($x,$y).
Работа со шрифтами TrueType
Библиотека GD поддерживает также работу со шрифтами PostScript и TrueType. Мы с вами рассмотрим только последние, т. к., во-первых, их существует великое множество (благодаря платформе Windows), а во-вторых, с ними проще всего работать в
PHP.
Для того чтобы заработали приведенные ниже функции, PHP должен быть от- компилирован и установлен вместе с библиотекой FreeType, доступной по ад- ресу http://www.freetype.org. В Windows-версии PHP она установлена по умолчанию.
Всего существует две функции для работы со шрифтами TrueType. Одна из них выводит строку в изображение, а вторая — определяет, какое положение эта строка бы заняла при выводе.
Вывод строки
list imageTTFText(int $im, int $size, int $angle, int $x, int $y, int $col, string $fontfile, string $text)
