很多PHPER在处理图片库的时候都会选择Imagine,不过这个库只有英文文档,昨日翻译一下,送给需要的同学。
Imagine是一个PHP5.3+的图片处理库,对于图片的处理可以使用GD2、Imagick或Gmagick。
能实现什么
Imagine具有强大的功能和简洁的API接口,众多PHP框架都采用Imagine来完成对图片的操作。
目前为止Imagine能实现功能如下
- 图片的大小调整及裁剪等操作。
- 绘图,创建基本图形和高级图表。
- 蒙版功能,实现图像的半透明或绝对透明功能。
安装Imagine
可以使用composer方便的进行Imagine安装,如下代码
php composer.phar require imagine/imagine
在这一章我们使用Imagine完成一些有趣的事情,通过这些事情你可以熟悉Imagine的使用流程。
目录结构
我们先来熟悉一下Imagine库的目录结构
上面目录具体干的事情如下
- Draw
- Effects
- Exception
- Filter
- Gd
- Gmagick
- Image
- Imagick
- resources
不要被这么多目录所迷惑,Imagine是一个设计非常清晰及现代的图片库,支持了主流的底层库,扩展性非常强,作者为了后期扩展方便提供了几个基础接口来撑起Imagine。
它们分别是
- ImagineInterface
- ImageInterface
- FontInterface
- DrawerInterface
- …
这里面最重要的是 ImagineInterface 和 ImageInterface 。
ImagineInterface
ImagineInterface是Imagine的核心,一起从它开始,它存在于 Imagine/Image/ImagineInterface.php ,当然这是一个接口,针对Gd、Imagick和Gmagick不同的库,在对应文件夹的 Imagine.php 文件对此接口进行了实现,具体位置请看下面列表。
- Imagine/Gd/Imagine.php
- Imagine/Gmagick/Imagine.php
- Imagine/Imagick/Imagine.php
ImagineInterface就像一个工厂,通过ImagineInterface接口的类可以新建、打开图像,并且返回一个 ImageInterface 对象,而在 ImageInterface 提供了对图片的具体操作。
现在我们来举一个例子
$imagine = new Imagine\Gd\Imagine();
$image = $imagine->open('/xxx/image.jpg');
上面的例子逻辑是这样的
- 首先建立一个ImagineInterface对象$imagine,这里使用的是GD库
- 使用 KaTeX parse error: Expected 'EOF', got '的' at position 9: imagine 的̲open方法打开本地的一张jp…image
ImageInterface
通过上面的ImagineInterface我们打开了一个对象,并且得到了ImageInterface的实例化对象,ImageInterface也是一个抽象的接口,针对不同的库有不同的实现,它们都在叫做Image的类中,目录如下
- Imagine/Gd/Image.php
- Imagine/Gmagick/Image.php
- Imagine/Imagick/Image.php
打开任何一个Image.php,你会发现很多熟悉的单词,比如copy、resize、save、fill等很多方法,这些就是对图片的具体操作,当然在这里还可以通过于FontInterface、DrawerInterface等实现更加牛x的效果。
接下来我们扩展下上面的例子
$imagine = new Imagine\Gd\Imagine();
$image = $imagine->open('/xxx/image.jpg');
$image->save('/xxx/image.png');
上面的例子是在xxx目录下对于打开的图片image.jpg,另存为image.png格式,很方便。
总结
我们来总结一下,Imagine的核心思路非常简单,提供足够清晰的接口并且容纳足够多的图片处理库,针对于对图片的不同操作,比如Draw、Effects、Filter等建立一系列的接口,然后在具体的库中对这些接口进行实现。
所以我们在Gd、Gmagick和Imagick文件下内你看到了相同名称的文件。
- Drawer.php
- Effects.php
- Font.php
- Image.php
- Imagine.php
- Layers.php
一套接口,各种库对其进行实现,这就是Imagine。
首先我们要学习下什么是元数据?
元数据是用来描述数据的数据(Data that describes other data),比如一张数码照片我们可以读取到拍此照片的相机类型、品牌等等,这些就是元数据。
大神阮一峰曾写了一篇小文来说元数据,感兴趣的可以看看。传送门
访问图像元数据
有了Imagine,读取元数据变的非常简单,我们只需要调用方法即可,请看例子。
$imagine = new Imagine\Gd\Imagine();
$image = $imagine->open('/xxx/image.jpg');
var_dump($image->metadata());
我们使用metadata方法得到基本的元数据,看看输出数据的解构。
通过结果我们看到metadata方法得到的是 \Image\Metadata\MetadataBag 类对象,包含的信息是 filepath 和 uri。
元数据读取器(metadata reader)
你可能差异元数据就这点信息么?还可以更多。
Imagine内置提供了两种元数据读取器,它们负责读出图像元数据并提供给上面的metadata,默认的读取器是 Imagine/Image/Metadata/DefaultMetadataReader.php。
还有一个叫做 Imagine/Image/Metadata/ExifMetadataReader.php,使用 ExifMetadataReader可以读取图像的Exif信息,接下来我们学习如何让Imgaine使用 ExifMetadataReader 读取器。
use Imagine\Image\Metadata\ExifMetadataReader;
$imagine = new Imagine\Gd\Imagine();
$image = $imagine->setMetadataReader(new ExifMetadataReader())->open('/xxx/image.jpg');
var_dump($image->metadata());
看明白了吧,我们需要调用 $imagine 的setMetadataReader方法并传入ExifMetadataReader对象。
注意 ExifMetadataReader的生效需要你的PHP拥有exif扩展,否则会有如下报错。
当这一切都满足后,你通过 metadata() 得到的 MetadataBag 对象将拥有Exif信息,你可以获得更多有用的。
自定义
一般来说使用 ExifMetadataReader 我们就足以满足业务需求了,但是Imagine还是提供了MetadataReaderInterface接口,允许我们自己定义自己的元数据读取器。
方法可以参考内置的另种读取器,继承于虚拟类 AbstractMetadataReader即可。
在Imagine处理图片时坐标是一个非常重要的概念,比如裁剪、伸缩等等都需要用到它,本章带你了解它。
坐标系统
在初中的时候我们学过坐标系,它叫笛卡尔坐标,如下图
这是我们学的,左下角是起点(x=0,y=0),但是Imagine坐标系统中起点位置有所不同,它以左上角为起点,相应地向右和向下延伸。另外就是没有负坐标。
相关类
Imagine中提供给了两个接口,分别是
- Imagine\Image\PointInterface 表示边界框中的单个点
- Imagine\Image\BoxInterface 代表尺寸(宽度,高度)
分别比Imagine\Image\下的Box类和Point类所实现,并且被其他类所使用,比如当我们调用$image->getSize的时候就用到。
PointInterface
每一个坐标都有如下方法
- getX()
- getY()
- in(BoxInterface $box)
- __toString()
BoxInterface
每个盒子或图像或形状都有一个大小,以下几种方法:
- getWidth() - 返回整数宽度
- getHeight() - 返回整数高度
- scale(KaTeX parse error: Expected 'EOF', got '返' at position 9: ratio)- 返̲回BoxInterface每个…ratio
- increase(KaTeX parse error: Expected 'EOF', got '返' at position 8: size)- 返̲回一个新的BoxInterfa…size添加给每一方
- contains(BoxInterface $box, PointInterface KaTeX parse error: Expected 'EOF', got '检' at position 15: start = null)-检̲查给定box包含在该当前内部BoxInterface在KaTeX parse error: Expected 'EOF', got '位' at position 6: start位̲置。如果没有start给出位置,则假定为(0,0)
- square()- 返回整数的当前平方,例如BoxInterface,用于确定框中像素的总数
- __toString()- 返回当前的字符串表示BoxInterface,例如100x100 px
- widen($width) - 将框调整为给定宽度,约束比例并返回新框
- heighten($height) - 将框调整到给定高度,约束比例并返回新框
场景
PointInterface 和 BoxInterface 经常用到其他方法或新建一个图像并绘制的场景,关于这些场景我们会在接下来的章节中逐渐涉及。
Imagine提供了比较强大的绘制能力,我们可以通过Imagine新建一个模板,然后绘制图形。在这一篇里你也能更加熟练的使用上一篇的坐标相关接口。
做一个图
我们现在实现一个需求,很简单,一张橙色背景400x300的图像,然后画一个线,开始啦
use Imagine\Gd\Imagine;
use Imagine\Image\Point;
use Imagine\Image\Box;
use Imagine\Image\Palette\RGB;
$palette = new RGB();
$imagine = new Imagine();
$box = new Box(400,300);
$image = $imagine->create($box,$palette->color('#FF6900'));
$image->draw()->line(new Point(200,150),new Point(250,250),$palette->color('#000000'));
$image->show('png');
上面代码的结果如下
结果分析
针对上面的图片,我们来复盘一下Imagine的实现思路。
- 首先我们要使用 $imagine->create 方法生成一个图像,图像包含尺寸和背景色。
- 尺寸是由上一篇的Box接口实现类来完成的,$box = new Box(400,300);,颜色则是RGB类。
- 然后调用$image的draw()方法,此方法的结果是得到一个drawer对象,同时拥有很多方法。
- 我们使用drawer对象的line方法,画一条线。
- 随后将图片以png的格式展示出来。
绘制方法一览
通过上面我们知道要绘图其实是调用了Image对象的draw方法,此刻我们看看draw内部的逻辑。
// Imagine/Gd/Image.php
public function draw()
{
return new Drawer($this->resource);
}
draw方法如此简单,仅仅return了Drawer的实例化对象,因此Imagine的绘图功能就回到了Drawer类上了。
还记得我们之前说的么?Imagine更多是提供了一系列的接口,因此在Gd等库中的Drawer类就是对DrawerInterface接口的实现,这个接口在 Imagine/Draw/DrawerInterface.php 中。
接下来我们看看Imagine的绘图功能到底有哪些?
- arc 弧线
- chord 弦
- ellipse 椭圆
- line 直线
- pieSlice 饼图
- dot 点
- polygon 多边形
- text 文字
对,DrawerInterface接口定义了8个方法,所以实现此接口的类都需要实现它们,绘图是最好练习Box和Point的途径,建议你多画一画。
一般来说,当我们使用Imagine时涉及到了颜色,不会直接传递颜色值,而是传递一个Palette对象,比如下面的例子。
$palette = new Imagine\Image\Palette\CMYK();
$imagine->create(new Imagine\Image\Box(10, 10), $palette->color('#FFFFFF'));
支持类
Imagine提供了两个类,RGB和CMYK。
- new Imagine\Image\Palette\RGB();
- new Imagine\Image\Palette\CMYK();
使用上首先调用响应的类,实例化
$palette = new Imagine\Image\Palette\RGB();
得到对象后调用color方法,传入颜色值,得到一个Color对象,这个Color对象经常作为其他方法的参数。
$white = $palette->color('fff', 100);
$white = $palette->color('ffffff', 100);
$white = $palette->color('#fff', 100);
$white = $palette->color('#ffffff', 100);
$white = $palette->color(0xFFFFFF, 100);
$white = $palette->color(array(255, 255, 255), 100);
color方法有两个参数
- 颜色值
- 透明度
改变模式
这个需求你可能很少遇见但是它存在,我们将一个图片从CMYK模式改为RGB模式,可以如下操作。
$image = $imagine->open('my-cmyk-jpg.jpg');
$image->usePalette(new Imagine\Image\Palette\RGB())
->save('my-rgb-jpg.jpg');
注意
这里需要注意,不同的驱动对颜色的支持有所区别
- GD仅支持RGB图像。
- Imagick支持CMYK,RGB和灰度色彩空间。
- Gmagick仅支持CMYK和RGB色彩空间。
图层的概念经常出现在作图软件中,比如PS软件导出PSD文件,还有就是gif格式的图片,Imagine通过其layers方法提供了此功能。
注意 并不是所有的库都支持图层,比如GD库就不支持,因此如果你想使用图层请不要选择它。
关于图层我在这里并不打算做详细的讲解,一来这是进阶内容,二来使用图层生成动画操作并不常用,不过有些操作依然很有用,那就是图层的读取,比如你想抽取一个gif动图的某一层,甚至包含对一些多图层图片的数据分析,使用imagine更加适合。
常用方法
得到一个图片图层的数量
$image = $imagine->open('image.jpg');
echo "Image contains " . count($image->layers()) . " layers";
循环每个图层
$image = $imagine->open('image.jpg');
foreach ($image->layers() as $layer) {
// ...
}
导出gif动画的每一层为图片
$i = 0;
foreach ($imagine->open('cats.gif')->layers() as $layer) {
$layer->save("frame-$i.png");
$i++;
}
给一个gif文件每一层添加文本
$image = $imagine->open('cats.gif');
$i = 0;
foreach ($image->layers() as $layer) {
$layer->draw()
->text($i, new Font('coolfont.ttf', 12, $image->palette()->color('white')), new Point(10, 10));
$i++;
}
// save modified animation
$image->save('cats-modified.gif', array('flatten' => 'false'));
Imagine还提供功能齐全的特效API。要使用api,您需要使用ImageInterface::effects()方法从当前图像实例获取效果实例。
我们先来一个最简单的例子
$imagine = new Imagine();
$image = $imagine->open(Yii::getAlias("@webroot")."/images/qrcode.jpeg");
$image->effects()
->grayscale();
套路都是一样的,通过$image->effects()获得Effects类对象,然后执行一些列特效方法,而无论是GD、Imagick还是Gmagick库的Effects类都是对 Imagine/Effects/EffectsInterface.php 接口的实现。
支持的特效
Imagine支持5中图片效果,我们一个一个说。
gamma
gamma在平时是不常用的,只有在专业的图像领域才会使用,可以理解为色阶,是灰阶亮度值与灰阶等级之间的数学关系。
这里的Gamma功能是校正图像色阶,使得图像看起来颜色更加正确。数字值取值范围只有最小值没有最大值只要 >=1.0都可以。
$image = $imagine->open(Yii::getAlias("@webroot")."/images/qrcode.jpeg");
$image->effects()
->gamma(2.0);
negative
在数码相机时代之前,占统治地位的是胶卷相机,胶卷底片与洗出来的相片相比,底片的RGB值就是相片的RGB值取反,即:底片的红色=255-相片的红色,底片的绿色=255-相片的绿色,底片的蓝色=255-相片的蓝色。
$image = $imagine->open(Yii::getAlias("@webroot")."/images/qrcode.jpeg");
$image->effects()
->negative();
grayscale
使用Grayscale使图片所有的色彩丢弃,只保留黑白两种颜色,没有取值。
$image = $imagine->open(Yii::getAlias("@webroot")."/images/qrcode.jpeg");
$image->effects()
->grayscale();
colorize
使用colorize参数,调整图片的红绿蓝三个基础色来改变图片颜色。
此功能仅适用于Gd和Imagick驱动程序。
$imagine = new Imagine();
$p = new RGB();
$color = $p->color("#FF6900");
$image = $imagine->open(Yii::getAlias("@webroot")."/images/qrcode.jpeg");
$image->effects()
->colorize($color);
sharpen
图片锐化就是补偿图像的轮廓,增强图像的边缘及灰度跳变的部分,使图像变得清晰。
$image = $imagine->open(Yii::getAlias("@webroot")."/images/qrcode.jpeg");
$image->effects()
->sharpen();
blur
模糊化一张图片
$image = $imagine->open(Yii::getAlias("@webroot")."/images/qrcode.jpeg");
$image->effects()
->blur(3);
注意
请注意,很多方法有库的差别,请小心,另外以上特效方法可以组合使用。
共同学习,写下你的评论
评论加载中...
作者其他优质文章