安装
首先,安装imageMagick与Perl Imager
# yum install ImageMagick ImageMagick-perl perl-YAML # yum install giflib-devel libjpeg-devel libtiff-devel libpng-devel freetype-devel # cpan -i Imager
安装nginx时需添加 perl支持
# ./configure --with-http_perl_module --with-pcre # make && make install
nginx配置
在http中加入以下配置:
perl_modules perl/lib;#perl/lib代表放置的perl脚本相对于nginx根目录的路径 perl_require xxx.pl;#xxx.pl代表所用到的脚本名称
在 请求的server中配置图片请求转发到perl处理 以equipone 测试服务器为例,在static配置的server中加入以下
location ~ \.pl$ { perl pkg_name::process; }
注:~ \.pl$表示以.pl结尾的图片请求转发到perl/lib 下的xxx.pl package为pkg_name名为process的方法处理
perl脚本的配置编写
下面编写perl脚本位置为nginx安装目录/usr/local/nginx +perl_modules配置目录 perl/lib 即:/usr/local/nginx/perl/lib/xxx.pl 编写pl需要引入模块(当然要求以安装的模块)以下面脚本为例
package showimg; use nginx; use Image::Magick;
use nginx 引入nginx模块就可以使用nginx中提供的perl语言接口, nginx 在perl中可以使用一下方法
$r->args – 请求的参数 . $r->discard_request_body – 这个参数是让 Nginx 放弃 request 的 body 的内容. $r->filename – 返回合适的请求文件的名字 $r->has_request_body(function) – 如果没有请求主体,返回0,但是如果请求主体存在,那么建立传递的函数并返回1,在程序的最后,nginx将调用指定的处理器. $r->header_in(header) – 查找请求头的信息 $r->header_only – 如果我们只要返回一个响应的头 $r->header_out(header, value) – 设置响应的头 $r->internal_redirect(uri) – 使内部重定向到指定的URI,重定向仅在完成perl脚本后发生.可以使用 header_out(Location….的方法来让浏览器自己重定向 $r->print(args, …) – 发送数据给客户端 $r->request_body – 得到客户端提交过来的内容 (body 的参数,可能需要修改 nginx 的 client_body_buffer_size. ) $r->request_body_file —给客户的 body 存成文件,并返回文件名 $r->request_method — 得到请求 HTTP method. $r->remote_addr – 得到客户端的 IP 地址. $r->rflush – 立即传送数据给客户端 $r->sendfile(file [, displacement [, length ] ) – 传送给客户端指定文件的内容,可选的参数表明只传送数据的偏移量与长度,精确的传递仅在perl脚本执行完毕后生效.这可是所谓的高级功能啊 $r->send_http_header(type) – 添加一个回应的 http 头的信息 $r->sleep(milliseconds, handler) – 设置为请求在指定的时间使用指定的处理方法和停止处理,在此期间nginx将继续处理其他的请求,超过指定的时间后,nginx将运行安装的处理方法,注意你需要为处理方法通过一个reference,在处理器间转发数据你可以使用$r->variable(). $r->status(code) – 设置 http 的响应码 $r->unescape(text) – 使用 http 方法加密内容如 %XX $r->uri – 得到请求的 URL. $r->variable(name[, value]) – 设置变量的值
而imagemagick的perl接口可以到这里看 http://www.imagemagick.org/script/perl-magick.php 下面是imagemagick的一个简单的实现
$image= new Image::Magick; $image->Read($real_file_path); $image->Scale($size); $image->Write($dest_file); #$real_file_path指的是原始图片的路径如"/var/www/upload/client_static/logo.gif" #$size指的是需要剪裁的长宽如"200x100" #$dest_file指的是新生成图片的路径,如:"/var/www/upload/client_static/logo_200x100.gif",需路径目录需存在 否则会报错
脚本编写思路
完整的脚本编写思路为:
首先从nginx请求中获取索取参数 1,图片路径 2,剪裁大小;
然后利用imagemagick完成图片的剪裁;
最后将剪裁完成的文件流写入nginx的返回文件流中;
注:nginx中定义变量
可以在package中定义 our $xxx;表示package 下都可以使用
也可以在方法中定义 my $xxx;表示在此方法中使用
perl中join方法
join("aaa", "bbb", "ccc");
表示在bbb和ccc中加入aaa得到bbbaaaccc
附:完整的脚本代码
package showimg; use nginx; use Image::Magick; our $image; sub process { my $r = shift; $r->send_http_header('Content-Type', 'image/gif'); my $params = $r->args; if (!$params || ($params eq "")) { } @pairs = split(/&/, $params); foreach $pair (@pairs) { ($name, $value) = split(/=/, $pair); $FORM{$name} = $value if ($name); } my $docroot = "/var/www/upload/client_static"; my $url = $FORM{"url"}; my $size = $FORM{"size"}; my $real_file_path = join "", $docroot, $url; my @filename_tokens=split('\.', $url); my $ext=pop @filename_tokens; my $ini_file_name=pop @filename_tokens; my $dest_file=join("_resize_$size.", $ini_file_name, $ext); $dest_file=join "", $docroot, $dest_file; $image= new Image::Magick; $url_error = $image->Read($real_file_path); if ($url_error) { $dest_file=join("_resize_$size.", "/logo", "gif"); $dest_file=join "", $docroot, $dest_file; $image->Read("$docroot/logo.gif"); } $image->Scale($size); $image->Write($dest_file); $r->sendfile($dest_file); return OK; } 1; __END__
版本1.2
说明:1,修改剪裁后图片文件的路径:/var/www/tmp ,其他存放路径与图片真实路径一致;
如:原图路径为:/var/www/upload/client_static/2014/2014_01/2014_01_07/3/1/4/imageFile/1389075917555_A1.jpg 请求尺寸为155x159
那么请求时会创建一个新的图片存放为:/var/www/tmp/2014/2014_01/2014_01_07/3/1/4/imageFile/1389075917555_A1_resize_155x159.jpg
2,优化图片读取,当请求的图片以存在时直接读取,不再进行剪裁操作;
package showimg; use nginx; use Image::Magick; our $image; use File::Path; sub process { my $r = shift; $r->send_http_header('Content-Type', 'image/gif'); #$r->send_http_header('text/html; charset=utf-8'); my $params = $r->args; if (!$params || ($params eq "")) { } @pairs = split(/&/, $params); foreach $pair (@pairs) { ($name, $value) = split(/=/, $pair); $FORM{$name} = $value if ($name); } my $docroot = "/var/www/upload/client_static"; my $url = $FORM{"url"}; my $size = $FORM{"size"}; my $real_file_path = join "", $docroot, $url; ## my $resizeRoot = "/var/www/tmp"; my $pathIndex = rindex($url, "/"); #my $ini_img_name = substr($url,$pathIndex+1); my $ini_img_path = substr($url,0,$pathIndex); my $comPath = join "", $resizeRoot, $ini_img_path; my @filename_tokens=split('\.', $url); my $ext=pop @filename_tokens; my $ini_file_name=pop @filename_tokens; my $dest_file=join("_resize_$size.", $ini_file_name, $ext); $dest_file=join "", $resizeRoot, $dest_file; $image= new Image::Magick; my $resurl_error = $image->Read($dest_file); if($resurl_error){ my $url_error = $image->Read($real_file_path); if ($url_error) { $dest_file=join("_resize_$size.", "/logo", "gif"); $dest_file=join "", $resizeRoot, $dest_file; $image->Read("$docroot/logo.gif"); } if (-e $comPath){ }else{ eval{mkpath($comPath,0,0777)}; } $image->Scale($size); $image->Write($dest_file); } $r->sendfile($dest_file); return OK; } 1; __END__
功能实现:通过nginx将图片请求转发到perl脚本交由imageMagic完成剪裁后返回数据流。
请求链接实例如下: static.alloysuppliers.info/content/ff808081163c05b001169d6655243ae9/thumbimages/pulpfiction24X36.jpg_size_100x100.resize
部署步骤:
1.测试服务器中安装nginx 与imageMagic nginx 需添加--with-http_perl_module --with-pcre模块 apt-get方式安装nginx可手动下载源码编译。
2.perl脚本添加:在nginx安装路径下/etc/nginx添加perl/lib文件夹加入showimg.pl脚本,代码下面展示;
3,nginx 配置文件中添加如下配置,将图片请求转发脚本处理。
注:生成的临时目录是:/var/www/tmp
location ~ \.resize$ { root /var/www/root; perl showimg::process; expires 1h; }
pl中获取图片地址与剪裁大小,处理生成符合大小的图片,并返回;showimg.pl代码如下:
package showimg; use nginx; use Image::Magick; our $image; use File::Path; sub process { my $r = shift; $r->send_http_header('Content-Type', 'image/gif'); #$r->send_http_header('text/html; charset=utf-8'); my $uri=$r->uri; my $url; my $sizeB; ($url, $sizeB) = split(/_size_/, $uri); my $sizeIndex = rindex($sizeB, "."); my $size = substr($sizeB,0,$sizeIndex); my $docroot = "/var/www/root"; my $real_file_path = join "", $docroot, $url; ## my $resizeRoot = "/var/www/tmp"; my $pathIndex = rindex($url, "/"); #my $ini_img_name = substr($url,$pathIndex+1); my $ini_img_path = substr($url,0,$pathIndex); my $comPath = join "", $resizeRoot, $ini_img_path; my @filename_tokens=split('\.', $url); my $ext=pop @filename_tokens; my $ini_file_name=pop @filename_tokens; my $dest_file=join("_resize_$size.", $ini_file_name, $ext); $dest_file=join "", $resizeRoot, $dest_file; $image= new Image::Magick; my $resurl_error = $image->Read($dest_file); if($resurl_error){ my $url_error = $image->Read($real_file_path); if ($url_error) { $dest_file=join("_resize_$size.", "/logo", "gif"); $dest_file=join "", $resizeRoot, $dest_file; $image->Read("$docroot/logo.gif"); } if (-e $comPath){ }else{ eval{mkpath($comPath,0,0777)}; } $image->Scale($size); $image->Write($dest_file); } $r->sendfile($dest_file); return OK; } 1; __END__