PHP-GD的性能
在写这章之前,先运行一段PHP脚本。如下:
$src = "test.jpg"; // 图像优化里用到的图片 $dst = "upload/gray.jpg"; // 保存的结果 $totalTime = 0; $testCount = 32; // 只能用这么小的值,否则运行超过30秒 $count = 0; // 尝试使用PHP-GD for($i = 0; $i < $testCount; $i++) { $start = getNanos(); $im = imagecreatefromjpeg($src); imagefilter($im, IMG_FILTER_GRAYSCALE); imagegd($im, $dst); imagedestroy($im); $stop = getNanos(); $time = (max($start, $stop) - min($start, $stop)) / (1000 * 1000); if ($time > 500.0) { //continue; } else { $count++; $totalTime += $time; } } if ($count == 0) $count = 1; echo "Perf:" . $totalTime / $count . "ms<br />";
先不要管getNano(),这个在后面会给出实现。这段程序运行的结果表明,对于test.jpg这样图片处理,GD需要差不多半秒。这个性能不能说很差,毕竟对大图的直接操作很少见。但想想《图像处理的简单优化》中得出的结果,GD还是很不给力。所以,就需要将快速的处理引入到PHP中,也就需要用到swig了。
编写PHP的扩展,提升性能
毫无疑问,这个扩展要命名为igame。
仿照GD的函数,简单定义了swig的接口文件,如下所示:
%module igame %include <const.i> %include <std_string.i> %{ #include "igame.h" #include "image.h" unsigned int getNanos(); int grayscaleJpeg(char* src, char* dst); Image* createImageFromJpeg(const std::string& filename); Image* createImageJpeg(unsigned int width, unsigned int height); int applyImageEffect(Image* img); int imageSaveAsJpeg(Image* img, const std::string& filename); void destroyImage(Image* img); %} extern unsigned int getNanos(); extern int grayscaleJpeg(char* src, char* dst); class Image { public: Image(); Image(unsigned int width, unsigned int height); Image(const std::string& filename); virtual ~Image(); public: virtual bool create(unsigned int width, unsigned int height); virtual bool save(const std::string& filename) = 0; virtual bool load(const std::string& filename) = 0; virtual bool close(); virtual bool available(); virtual unsigned int width(); virtual unsigned int height(); virtual unsigned int stride(); virtual unsigned int bytesPerPixel(); virtual bool applyEffect(Effect* effect); }; // class extern Image* createImageFromJpeg(const std::string& filename); extern Image* createImageJpeg(unsigned int width, unsigned int height); extern int applyImageEffect(Image* img); extern int imageSaveAsJpeg(Image* img, const std::string& filename); extern void destroyImage(Image* img);
注意,这里的Image类导出有问题,无法调用类的方法。后续再处理吧,现在用做容器还是可以的。
实现文件如下:
igame.h
#ifndef IGAME_H #define IGAME_H #include "image.h" unsigned int getNanos(); int grayscaleJpeg(char* src, char* dst); Image* createImageFromJpeg(const std::string& filename); Image* createImageJpeg(unsigned int width, unsigned int height); int applyImageEffect(Image* img); int imageSaveAsJpeg(Image* img, const std::string& filename); void destroyImage(Image* img); #endifigame.cpp
#include "igame.h" #include "jpeg.h" #include "grayscale.h" #include <time.h> unsigned int getNanos() { struct timespec time; clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &time); return time.tv_sec * 1000 * 1000 + time.tv_nsec; } int grayscaleJpeg(char* src, char* dst) { Jpeg myjpg; if (myjpg.load(src)) { Grayscale grayscale; if (myjpg.applyEffect(&grayscale)) { if (myjpg.save(dst)) return true; } } return false; } Image* createImageFromJpeg(const std::string& filename) { return new Jpeg(filename); } Image* createImageJpeg(unsigned int width, unsigned int height) { return new Jpeg(width, height); } int applyImageEffect(Image* img) { Grayscale grayscale; return img->applyEffect(&grayscale); } int imageSaveAsJpeg(Image* img, const std::string& filename) { return img->save(filename); } void destroyImage(Image* img) { delete img; }
相较于GD的可怜性能,这才是自己开发扩展的用意。
完整的eclipse工程可以从这里下载。