Основы использования GD (part 1) - предлагаю в FAQ

The employer

Новичок
Основы использования GD (part 1) - предлагаю в FAQ

Типовые операции с изображениями посредством GD

Импорт и экспорт изображений
Импорт
Экспорт
Корректный экспорт полупрозрачных PNG


Импорт и экспорт изображений

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


Импорт

Средствами PHP можно импортировать изображения откуда угодно - из файлов,
из базы данных, из интернета.

Формально, для импорта из файлов и из интернета должен применяться целый набор
функций, имеющих однотипные названия - imagecreatefrom<тип>, где <тип>
указывает на формат изображения - PNG, GIF, JPEG, WBMP, XBM, XPM, GD, GD2.

На практике я рекомендую не пользоваться этим зоопарком, а применять связку
из функций file_get_contents + imagecreatefromstring. Это избавляет
от необходимости привязывать код к типам графических ресурсов -
если в дальнейшем вам понадобится работать с JPEG вместо PNG, не нужно
будет везде в коде менять названия применяемых фукций.


Кроме того, специализированные функции не позволят импортировать файл,
если тип содержащего в нем изображения не соответствует использованной
функции. Расширение имени файла здесь роли не играет - файл с картинкой
в формате GIF, но названный "image.png" не будет импортирован функцией
imagecreatefrompng. В ситуации, когда тип файла заранее неизвестен (например,
импорт из интернета, или импорт изображения, загруженного
на сервер пользователем) - лучше воспользоваться механизмом распознавания
типа файла, встроенным в imagecreatefromstring.


Код:
PHP:
$raw = file_get_contents( $filename );
$img = imagecreatefromstring( $raw );
unset( $raw );
После выполнения в $img будет ссылка на ресурс - изображение во внутреннем
формате GD.


У данного способа есть и недостаток: если вам критичен пиковый объем памяти,
потребляемый скриптом - используйте все-таки функции imagecreatefrom<тип>,
а лучше переложите работу с изображениями на плечи специализированных пакетов
типа ImageMagic.


Импорт из базы данных отличается тем, что строку для imagecreatefromstring
нужно получить не из файла, а из BLOB-поля в базе.

Импорт из интернета может производиться при помощи fopen wrapper или
при помощи CURL. Второй способ я здесь не рассматриваю, он заслуживает
отдельного описания.

Чтобы иметь возможность пользоваться fopen wrapper, в php.ini должна быть
установлена опция allow_url_fopen = true. В этом случае функции
file_get_contents в качестве параметра можно передавать не только имя файла
на локальном диске, но и URL, ссылающийся на ресурс в интернете. Это может быть
URL картинки на сайте, или ссылка на FTP.

Код:
PHP:
$raw = file_get_contents( $URL );
$img = imagecreatefromstring( $raw );

Экспорт

Три типичных задачи экспорта - вывод изображения в браузер, экспорт в БД,
экспорт в файл.

Для экспорта нужно определиться с типом изображения, которое должно получиться
при конвертации из внутреннего формата GD. Библиотека поддерживает форматы
JPEG, GIF, PNG, WBMP и свои собственные GD и GD2. На вебе нас интересуют
только первые три формата.

Чтобы вывести изображение в браузер или в файл, следует вызвать одну из функций
imagejpeg, imagegif, imagepng. В качестве параметра им следует передать
переменную, ссылающуюся на ресурс-изображение. Второй параметр у всех функций
представляет собой имя файла, в который требуется сохранить результат конвертации.

Код:
PHP:
imagegif( $img, $filename );
Если имя файла на задано, все функции выдают изображение в выходной буфер.
Чтобы изображение правильно отобразилось в браузере, вместе с ним должны быть
отправлены корректные HTTP-заголовки.

Код:
PHP:
header( 'Content-type: image/jpeg' );
imagejpeg( $img );
У imagejpeg и у imagepng есть необязательный параметр - quality (фактически,
степень сжатия изображения). У imagepng есть и еще один необязательный
параметр - filter. Если нужно вывести изображение в браузер, но при этом
необходимо задать степень сжатия или применить фильтры - в качестве параметра
$filename нужно задать null.

Код:
PHP:
header( 'Content-type: image/jpeg' );
imagejpeg( $img, null, 50 );
Чтобы экспортировать изображение в строку, нужно воспользоваться механизмом
буферизации вывода.

Код:
PHP:
ob_start();
imagejpeg( $img );
$raw = ob_get_clean();

Корректный экспорт полупрозрачных PNG

Один из двух внутренних форматов библиотеки GD - true color image -
позволяет задавать различную степень прозрачности для каждой точки
изображения, от полной прозрачности до полной непрозрачности, с шагом 1/256.

Степень прозрачности для каждой точки задается отдельно, и никак
не связана с цветом этой точки. Говорят, что у информации о каждой точке
изображения есть два "канала" - цветовой канал, который задает цвет точки,
и альфа-канал, который задает ее степень прозрачности.

По умолчанию, при экспорте изображений из внутреннего формата GD учитывается
только цветовой канал. Для изображений типа GIF или JPEG этого достаточно,
потому что эти форматы не поддерживают полупрозрачность (GIF поддерживает
полную прозрачность, но она устроена иначе - присвоением прозрачным точкам
специального цвета, объявленного в палитре как прозрачный).

Однако, формат PNG поддерживает полноценнный альфа-канал, так что
полупрозрачные изображения можно выводить в этом формате.

Чтобы при экспорте в PNG не была потеряна информация об альфа-канале,
нужно добавить перед самим экспортом два вызова специальных функций.

Код:
PHP:
ob_start();
imagealphablending( $img, false );
imagesavealpha( $img, true);
imagepng( $img );
$raw = ob_get_clean();
 

Духовность™

Продвинутый новичок
Сижу, смотрю телевизор. Звонок в дверь. Стоит хз кто на пороге и говорит - предлагаю вот эту картину, дешёвую репродукцию, повесить у тебя на стене, на самом видном месте. Как мне реагировать?...
 

Фанат

oncle terrible
Команда форума
Это избавляет
от необходимости привязывать код к типам графических ресурсов -
фигня. подставить имя функции в зависимости от формата - это две строчки. а file_get_contents сожрет лишнюю память, которая при работе с картинками совсем не лишняя
Корректный экспорт полупрозрачных PNG
это полезно.

но моя статья на тему "Основы использования GD" уместилась бы в 1 строчку:
Не используйте эту убогую либу с ее полутора форматами, заюзайте через командную строку imagemagick. Все равно со временем придется, так зачем зря время терять?
 

The employer

Новичок
Автор оригинала: triumvirat
Сижу, смотрю телевизор. Звонок в дверь. Стоит хз кто на пороге и говорит - предлагаю вот эту картину, дешёвую репродукцию, повесить у тебя на стене, на самом видном месте. Как мне реагировать?...
Ситуация с моей стороны: есть ресурс, на котором вроде бы заявлено, что с его помощью люди помогают друг другу в освоении и работе с PHP. Я в процессе работы сталкиваюсь с какими-то задачами, решаю их, и готов поделиться с другими своими решениями. Трачу на это определенное время и усилия. Размещаю. Приходит "санитар леса" и рассказывает мне о том, что я, оказывается, приперся без спросу в его личную квартиру, где лично он сидит, развлекает себя телевизором и "хз кого" видеть не желает.

Реагировать? Это интернет - реагируй как тебе вздумается.
 

baev

‹°°¬•
Команда форума
На практике я рекомендую не пользоваться этим зоопарком, а применять связку
из функций file_get_contents + imagecreatefromstring. Это избавляет
от необходимости привязывать код к типам графических ресурсов -
если в дальнейшем вам понадобится работать с JPEG вместо PNG, не нужно
будет везде в коде менять названия применяемых фукций.
— а ещё доводы в пользу отказа от «узкоспециализированных» функций есть?
 

The employer

Новичок
Автор оригинала: *****
фигня. подставить имя функции в зависимости от формата - это две строчки. а file_get_contents сожрет лишнюю память, которая при работе с картинками совсем не лишняя
Здесь есть один нюанс: если тип заранее неизвестен, то его так и так придется определять. По расширению имени файла не получится.

Автор оригинала: *****
но моя статья на тему "Основы использования GD" уместилась бы в 1 строчку:
Не используйте эту убогую либу с ее полутора форматами, заюзайте через командную строку imagemagick. Все равно со временем придется, так зачем зря время терять?
Ну не обязательно придется. Простые вещи вроде генерации превьюшек для больших изображений, конвертации, масштабирования-поворота, комбинирования изображений (типа наложения "водяных знаков") - все это делается при помощи GD достаточно просто. А так да, imagemagic посерьезней. Но, кстати, с ней необязательно работать через командную строку, в PECL есть объектно-ориентированная обертка. Я сам собираюсь ее попробовать - но сначала надо зафиксировать полученный опыт с GD, чтобы не пропал даром.

-~{}~ 29.06.09 21:19:

Автор оригинала: baev
— а ещё доводы в пользу отказа от «узкоспециализированных» функций есть?
Вторая причина - если ты заранее не знаешь тип файла, и/или нет уверенности в том, что тип файла и тип изображения соответствуют. Тогда лучше воспользоваться встроенным в GD механизмом распознавания типа изображения. А это проще всего сделать через imagecreatefromstring. Почему этот механизм не был разработчиками GD задействован для "специализированных" функций - ума не приложу.
 

Духовность™

Продвинутый новичок
The employer
тебя не смущает, что в интернете КУЧА статей, описывающих работу с GD? Ты какбе ничего нового то и не сказал, тебя это не смущает?
 

The employer

Новичок
Автор оригинала: triumvirat
The employer
тебя не смущает, что в интернете КУЧА статей, описывающих работу с GD? Ты какбе ничего нового то и не сказал, тебя это не смущает?
Нет. Я тебе больше скажу - все, что необходимо для работы с PHP в целом и с GD в частности - есть в PHP Manual. Теперь, со своих позиций, объясни смысл существования всей той КУЧИ статей, о которой ты говоришь. Объясни в первую очередь себе, потому что я не собираюсь захламлять ветку подобной дискуссией ни о чем.
 

Фанат

oncle terrible
Команда форума
его так и так придется определять
это тоже не бином ньютона, и уж всяко не стоит лишних мегабайт памяти.
Простые вещи вроде генерации превьюшек для больших изображений
ага, в форматах тиф, бмп...
а взять еще прожорливость гд в отношении памяти.
в PECL есть объектно-ориентированная обертка
ЩАЗ. Брошу командную строку, в которой любые параметры указываются несколькими символами и буду писать на страницу объектно-ориентированного кода.
 

Духовность™

Продвинутый новичок
Теперь, со своих позиций, объясни смысл существования всей той КУЧИ статей, о которой ты говоришь.
теперь мне объясни, смысл твоего поста, если есть куча статей, в которых все разжевано намного эффективнее?
 

Фанат

oncle terrible
Команда форума
triumvirat
а кто эффективность определяет? ты, что ли?
 

The employer

Новичок
Автор оригинала: *****
это тоже не бином ньютона, и уж всяко не стоит лишних мегабайт памяти.
Я сейчас отредактирую текст первого поста - дополню, по итогам обсуждения.

Автор оригинала: *****
ага, в форматах тиф, бмп...
Как правило, на вебе используются только gif, jpeg и png. Можно, конечно, дать юзеру возможность загрузить на сайт статью с иллюстрациями в TIFF - но какой в этом смысл решительно непонятно. Я с необходимостью работать с GD сталкивался на контент-проектах, там ни о каких TIFF или там RAW речи нет, весь процесс строится под веб, и до сервера доходят уже jpeg и png.

Автор оригинала: *****
а взять еще прожорливость гд в отношении памяти.
Расскажи подробнее, в чем проявляется эта прожорливость? И с чем сравнивать, с какой билиотекой? Если с использованияем imagemagic посредством командной строки - так это не вполне корректное сравнение, ты же понимаешь.

Автор оригинала: *****
ЩАЗ. Брошу командную строку, в которой любые параметры указываются несколькими символами и буду писать на страницу объектно-ориентированного кода.
Удобно в первую очередь тем, что можно держать картинки в базе. На кластерах это избавляет от некоторого геморроя по синхронизации файлов. Производительность при этом не страдает по причине применения кэширования, когда при первом обращении к несуществующей на данной ноде картинки - картинка поднимается из базы и генерируется соответствующий файл.
 

Фанат

oncle terrible
Команда форума
Как правило, на вебе используются
При чем здесь веб?
TIFF - но какой в этом смысл решительно непонятно.
я тебе объясню. у пользователя на работе стоит МФУ Кенон. в котором есть одна большая зеленая кнопка "Сканировать". После нажатия на которую в папке "Мои документы" появляется файл тиф.
Расскажи подробнее, в чем проявляется эта прожорливость?
в поиск по слову allocate
о боже. я думал, ты вменяемый.
 

The employer

Новичок
Автор оригинала: *****
При чем здесь веб?

я тебе объясню. у пользователя на работе стоит МФУ Кенон. в котором есть одна большая зеленая кнопка "Сканировать". После нажатия на которую в папке "Мои документы" появляется файл тиф.
Такие задачи мне на PHP решать не приходилось, соответственно об этом я не пишу. У меня были другие задачи - у пользователя большая кнопка "Добавить иллюстрацию", по этой кнопке картинка должна быть загружена на сервер, проверена на соответствие гайдлайнам (объем не более..., размеры по оризонтали не менее... и не более..., соотношение сторон изображения не менее... и не более...), должна быть сгенерирована превьюшка, должны быть проведены еще некоторые операции (наложение watermark, если это уместно).

Автор оригинала: *****
в поиск по слову allocate
По слову allocate есть только горести людей, не понимающих что 2047*1535*4 да еще в двух экземплярах - это таки больше 23 мегабайт. Вряд ли можно винить в этом GD, или ты считаешь иначе? Сорри, но true color image с альфа-каналом, доступный для редактирования попиксельно - ну никак не может занимать меньше четырех байт на пиксель.

Автор оригинала: *****
о боже. я думал, ты вменяемый.
Страшное дело. А теперь я резко стал невменяемым? Отчего же?

Вот тебе ситуация: сайт сообщества, куча народу, все хотят заливать фотки себя любимых. И заливают (upload). И меняют их регулярно. Весь этот контент надо держать синхронизированным, потому что nlb может отправить при следующем заходе на другую ноду, где только что залитой фотки еще нет.

Разумеется, этот вопрос можно решать очень по-разному. Но было решено вот так, и работало несколько лет без проблем. Если интересно обсудить - предложи свой способ и давай обсудим преимущества и недостатки, учитывая как фактор также стоимость и скорость разработки и сопровождения. Если, конечно, ты сейчас понял что погорячился насчет оценки вменяемости. А то я краем уха слышал, что такую схему первым придумал еще некто Котеров, его тоже в невменяемые запишем?
 

Gorynych

Посетитель PHP-Клуба
ImageMgick, ImageMagick!!! И если придет Тони, я все же не поленюсь и найду время для того, чтобы показать разницу в размерах изображений после трансформации :)
 

grigori

( ͡° ͜ʖ ͡°)
Команда форума
The employer
ты удивишься, но г-на Котерова здесь считают журналистом/писателем, а не инженером-программистом :)

-~{}~ 29.06.09 23:27:

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

AmdY

Пью пиво
Команда форума
grigori
это субъективно.
The employer
весьма познавательно, но на полноценный фак не тянет, так что соглашусь с triumvirat, но как пост стоит оставить.
 

The employer

Новичок
Автор оригинала: grigori
The employer
ты удивишься, но г-на Котерова здесь считают журналистом/писателем, а не инженером-программистом :)
Уважаемый grigori, после некоторых фраз от определенных людей, имеющих, как я понимаю, отношение к администрации форума, я уже ничему не удивлюсь. Человека, постоянно работающего профессиональным программистом с 99 года, и доросшим до руководителя разработки не самого маленького сервиса Яндекса - не считать инженером-программистом? В смысле не считать его способным выдвигать нормальные взвешенные технические решения?

Нет-нет, с определенного момента меня не удивить даже этим.

Я лишь предлагаю задуматься о том, что подобные высказывания гораздо ярче характеризуют их автора (или сообщество, в котором приняты такие взгляды), чем самого бедолагу-Котерова. И дело тут совсем не в том, что кто-то считает себя лучшим разработчиком чем тот Котеров (и вполне может быть прав в этом вопросе).

Проблема, на самом деле, такая: а кто же тогда может рассчитывать на элементарное уважение в подобном (якобы профессиональном) сообществе? Каковы принципы распознавания "свой-чужой", принятые здесь? Если здесь принято проверять всех на соответствие определенным религиозным взглядам (винда рулез линупс отстой, или наоборот - неважно), так есть ли смысл тратить свое время на подобную тусовку? Если технические решения не обсуждаются и не оцениваются применительно к обстоятельствам, не исследуются границы их эффективности?

Я пока не знаю ответ на этот вопрос. Мне пока хочется думать, что здесь как и везде бывают просто неадекватные люди, или у нормальных людей бывают неудачные дни, когда без особых причин срываешься на окружающих. Больше всего меня на самом деле насторожило вот это вот "здесь считают". Одна надежда, что это попытка выдать чье-то частное мнение за всеобщее правило.

-~{}~ 30.06.09 20:37:

Типовые операции с изображениями посредством GD (part 2)

Два типа изображений в GD
Зачем вообще нужны изображения с палитрой?

Память
Сколько нужно памяти? Сколько-сколько?!
Как выделить и как освободить необходимый объем памяти

Создание изображений
Определение типа изображения


Два типа изображений в GD

Библиотека поддерживает два внутренних формата изображений - изображения
с палитрой и truecolor-изображения. Как они устроены?


Truecolor-изображения

Каждая точка (пиксель) truecolor-изображения описывается четырьмя байтами,
три из которых задают цвет в формате RGB, а четвертый устанавливает уровень
прозрачности данной точки - от нуля (полностью непрозрачная) до 127 (полностью
прозрачная). В первом случае видимый цвет точки полностью соответствует
установленному в RGB, во втором случае цвет установленный в RGB полностью
игнорируется.


Изображения с палитрой

Изображения с палитрой (еще их назвают изображениями в индексированном цвете)
устроены так: каждому пикселю изображения присвоено число, обозначающее
порядковый номер ячейки в палитре. А ячейка палитры содержит описание цвета
в формате RGB. Число, обозначающее ячейку палитры принято называть индексом
цвета, чтобы отличать от собственно цвета, описанного в той ячейке. В палитре
один цвет может быть назначен "прозрачным" - тогда ячейке палитры выставляется
специальный признак прозрачности, а значения цветов RGB игнорируются.


Зачем вообще нужны изображения с палитрой?

Главная историческая причина - такие изображения занимают меньше места
чем truecolor, при том что путем подбора цветов палитры можно добиться
в общем и целом пристойного результата.

Но у такого устройства есть еще несколько хороших побочных эффектов
(см. старую демо-сцену, до повального увлечения 3D-рендерингом).

Например, такое устройство цвета позволяет легко, "автоматически",
менять цвета произвольных областей изображения. Представим себе картинку
с изображением пешеходного светофора с двумя человечками - красный стоит,
зеленый идет.

Человечки нарисованы пикселями, ссылающимися на одинаковый цвет. Пиксели
стоящего человечка ссылаются на ячейку палитры номер один, пиксели идущего
человечка ссылаются на ячейку палитры номер два.

Теперь, чтобы зажечь сигнал "стой" на таком светофоре достаточно в ячейке
палитры номер один прописать красный цвет (0xFF0000), а в ячейке палитры
номер два прописать серый цвет (0x111111). Стоящий человечек станет красным,
идущий человечек станет серым. Теперь мы можем каким угодно образом поменять
изображение целовечков (заменить их на ниндзя-черепашек, например) - код
приложения, зажигающего светофор, менять не потребуется.


Память

Сколько нужно памяти? Сколько-сколько?!

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

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

Объясняется это просто: изображения в формате GIF, JPEG или PNG как правило
хранятся на диске упакованными, и распаковываются в свой полный размер только
тогда, когда с нимми нужно работать - показать на экране, распечатать,
отредактировать. Вот тогда они сразу начинают занимать все свои законные
тридцать метров. Вспомните, сколько памяти требуется фотошопу для работы
с вашими фотками.

Библиотека GD как раз предназначена для работы с изображениями.
Раз вы импортировали изображение в формат библиотеки - предполагается, что вы
можете сделать с ним что угодно, вплоть до редактирования каждого отдельного
пикселя. Сжатые форматы для этого не годятся, приходится все изображение
держать в памяти в распакованном виде.

В распакованном виде truecolor-изображения GD требуют четыре байта на каждую
точку - три байта для описания цвета точки, и один байт для описания степени
прозрачности точки.

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


Как выделить и как освободить необходимый объем памяти

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

На примере: если вам нужно на truecolor-изображение размером 1920x1080 наложить
полноцветный водяной знак размером 200x200 - то для того чтобы развернуть
в памяти эти два изображения вашему скрипту потребуется
1920x1080x4 + 200x200x4 = 8454400 байт, и кроме того скрипту потребуется
где-то хранить и остальные свои данные - переменные и объекты. Отсюда ясно,
что если у вас в php.ini стоит memory_limit = 8M - вашему скрипту совершенно
точно не хватит памяти для выполнения запланированных действий.

В такой ситуации перед началом работы с изображениями достаточно выполнить
операцию увеличения лимита памяти для данного конкретного скрипта:
PHP:
ini_set( "memory_limit", "128M" );
Этой строкой мы разрешаем скрипту использовать до 128 мегабайт памяти.
Можно вообще снять ограничения по памяти, но это требует осторожности -
при неаккуратном использовании сервер может быть заблокирован на некоторое
время:
PHP:
ini_set( "memory_limit", -1 );
Изображения, ставшие ненужными, можно удалить из памяти при помощи функции
imagedestroy. В качестве параметра этой функции следует передать
ресурс-изображение GD.


Создание каждого типа изображения

Truecolor-изображения создаются при помощи функции imagecreatetruecolor
или при импорте изображений в формате PNG и JPEG.

Изображения с палитрой создаются при помощи функций imagecreate
или при импорте изображений в формате GIF.

У изображения, созданного посредством createimage, палитра пустая.
Если вы хотите что-то нарисовать на этой картинке средствами GD - обязательно
добавьте в палитру хотя бы два цвета, иначе вы получите просто квадрат
одного цвета - либо черного (если в палитре не будет цветов), либо того
единственного цвета что будет в палитру добавлен.

В любом случае, если вы создаете пустое изображение -
GD заполняет его черным цветом.


Определение типа изображения

Функция imageistruecolor возвращает true, если ее параметр является
truecolor-изображением и false для изображения с палитрой.
 

Фанат

oncle terrible
Команда форума
Давайте не будем обсуждать Котерова :)
Да и вообще, наверное, тут нечего больше обсуждать
 
Сверху