PHP-GD的效能
在寫這章之前,先運行一段PHP指令碼。如下:
$src = "test.jpg"; // 映像最佳化裡用到的圖片$dst = "upload/gray.jpg"; // 儲存的結果$totalTime = 0;$testCount = 32; // 只能用這麼小的值,否則運行超過30秒$count = 0;// 嘗試使用PHP-GDfor($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);}; // classextern 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);#endif
igame.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;}
修改PHP.INI,使之能夠使用擴充包。再編寫相同的測試頁面,最後得出結果:136.494ms。大致是GD的3倍多。
相較於GD的可憐效能,這才是自己開發擴充的用意。
完整的eclipse工程可以從這裡下載。