2018年12月份课程免费领取报名开始啦,点击进入。

Imagine图片库简明文档

Imagine是PHP上一个非常稳定强大的图片处理库,支持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库
  • 使用 $imagine 的open方法打开本地的一张jpg图片,并且返回一个图片对象$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($ratio)- 返回BoxInterface每个边乘以的新实例$ratio
  • increase($size)- 返回一个新的BoxInterface,并$size添加给每一方
  • contains(BoxInterface $box, PointInterface $start = null)-检查给定$box包含在该当前内部BoxInterface在$start位置。如果没有$start给出位置,则假定为(0,0)
  • square()- 返回整数的当前平方,例如BoxInterface,用于确定框中像素的总数
  • __toString()- 返回当前的字符串表示BoxInterface,例如100×100 px
  • widen($width) – 将框调整为给定宽度,约束比例并返回新框
  • heighten($height) – 将框调整到给定高度,约束比例并返回新框

场景

PointInterface 和 BoxInterface 经常用到其他方法或新建一个图像并绘制的场景,关于这些场景我们会在接下来的章节中逐渐涉及。


绘制

Imagine提供了比较强大的绘制能力,我们可以通过Imagine新建一个模板,然后绘制图形。在这一篇里你也能更加熟练的使用上一篇的坐标相关接口。

做一个图

我们现在实现一个需求,很简单,一张橙色背景400×300的图像,然后画一个线,开始啦

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的途径,建议你多画一画。

另外text方法我们需要注意一下,你是不是想到了文字水印,我们把text方法单独说说。


颜色

一般来说,当我们使用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);

左图为原图,有图是效果图。

注意

请注意,很多方法有库的差别,请小心,另外以上特效方法可以组合使用。


参考文章

发表评论

电子邮件地址不会被公开。 必填项已用*标注

防止广告,需审核后显示