CPP 替代 PIL 图片处理(缩略图生成)

Posted heaventouch

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了CPP 替代 PIL 图片处理(缩略图生成)相关的知识,希望对你有一定的参考价值。

 

python中使用PIL(Pyhton Image Library)进行图片处理,好处就是编写简单方便,但是不能很好利用机器多核的特点,于是在项目中决定使用cpp来实现图片处理。

项目中的图片处理主要是生成缩略图。网上收集了一些cpp图片处理库,并进行了对比:

 

在项目中需要对jpg、png、gif格式的图片进行处理,可行的cpp库有Img、FreeImage、GD,而安装使用后进行效率对比,决定使用FreeImage。

 

折腾了一个星期,把可用程序完成,并和PIL进行对比(这里是使用python commands库运行上传图片demo,上传时使用threading多进行并发):

 

注意:

1、测试时上传多张大图片时内存很快用完,所以要测试要排除内存用完的影响,内存耗尽会影响测试。(上传数量控制一下)

2、linux机器上传时,记得ulimit -n 调大文件句柄打开数,以免影响测试。

 

测试结果还是挺理想,准备正式推广。

FreeImage cpp 缩略图生成代码:

  1 #include "stdio.h"
  2 #include "stdlib.h"
  3 #include "unistd.h"
  4 #include <sys/time.h>
  5 #include <sys/stat.h>  
  6 #include "FreeImage.h"
  7 
  8 #ifdef _DEBUG
  9 #pragma comment(lib, "FreeImaged.lib")
 10 #else
 11 #pragma comment(lib, "FreeImage.lib")
 12 #endif
 13 
 14 #define THUM_TYPE_SMALL 1
 15 #define THUM_TYPE_MID 2
 16 
 17 const float IMAGE_NEED_CROP_RATIO = 3.0;
 18 const float IMAGE_CROP_RATIO = 1.76;
 19 const int MID_IMAGE_LIMIT_SIZE = 3*1024*1024;
 20 
 21 struct ImageSize{
 22     int width;
 23     int height;
 24 };
 25 
 26 inline void print_size(ImageSize img_size, const char* str)
 27 {
 28     printf("%s : %d %d\\n", str, img_size.width, img_size.height);
 29 }
 30 
 31 inline bool is_long_image(ImageSize img_size)
 32 {
 33 
 34     if(float(img_size.height) / img_size.width > IMAGE_NEED_CROP_RATIO)
 35         return true;    
 36     else
 37         return false;
 38 }
 39 
 40 inline bool is_panorama_image(ImageSize img_size)
 41 {
 42     
 43     if(float(img_size.width) / img_size.height > IMAGE_NEED_CROP_RATIO)
 44         return true;
 45     else
 46         return false;
 47 }
 48 
 49 inline bool is_need_crop(ImageSize img_size)
 50 {
 51     if(is_long_image(img_size))
 52         return true;
 53     
 54     if(is_panorama_image(img_size))
 55         return true;
 56     
 57     return false;
 58 }
 59 
 60 inline bool is_need_resize(ImageSize img_size, ImageSize des_img_size)
 61 {
 62     int width = img_size.width;
 63     int height = img_size.height;
 64     int des_width = des_img_size.width;
 65     int des_height = des_img_size.height;    
 66     if((width < des_width) && (height < des_height))
 67         return false;
 68     else
 69         return true;
 70 }
 71 
 72 inline ImageSize get_crop_size(ImageSize img_size)
 73 {
 74     if(is_long_image(img_size))
 75         img_size.height = img_size.width * IMAGE_CROP_RATIO;
 76     else if(is_panorama_image(img_size))
 77         img_size.width = img_size.height * IMAGE_CROP_RATIO;
 78     
 79     return img_size;
 80 }
 81 
 82 inline ImageSize get_resize_size(ImageSize img_size, ImageSize des_img_size)
 83 {
 84     int width = img_size.width;
 85     int height = img_size.height;
 86     int des_width = des_img_size.width;
 87     int des_height = des_img_size.height;    
 88             
 89     float ratio = 1.0;
 90     if(height > width)
 91         ratio = float(des_height) / height;
 92     else
 93         ratio = float(des_width) / width;
 94     
 95     img_size.width = width * ratio;
 96     img_size.height = height * ratio;
 97 
 98     return img_size;
 99 }
100 
101 
102 inline FIBITMAP * get_crop_picture(FIBITMAP *sourcePic)
103 {
104     
105     int src_width, src_height;
106     
107     //获取图片大小 
108     src_width  = FreeImage_GetWidth(sourcePic);
109     src_height = FreeImage_GetHeight(sourcePic);        
110     
111     struct ImageSize src_size = {src_width, src_height};
112     
113     if(!is_need_crop(src_size))
114         return sourcePic;
115         
116     struct ImageSize crop_size = get_crop_size(src_size);
117     //print_size(crop_size, "crop_size");
118     
119     FIBITMAP * cropPic = FreeImage_Copy(sourcePic, 0, 0, crop_size.width, crop_size.height);
120     
121     FreeImage_Unload(sourcePic);
122     sourcePic = NULL;
123     
124     return cropPic;
125     
126 }
127 
128 inline FIBITMAP * get_resize_picture(FIBITMAP *sourcePic, ImageSize des_size)
129 {
130     
131     int src_width, src_height;
132     
133     //获取图片大小 
134     src_width  = FreeImage_GetWidth(sourcePic);
135     src_height = FreeImage_GetHeight(sourcePic);        
136     
137     struct ImageSize src_size = {src_width, src_height};
138     
139     if(!is_need_resize(src_size, des_size))
140         return sourcePic;
141         
142     struct ImageSize resize_size = get_resize_size(src_size, des_size);
143     //print_size(resize_size, "resize_size");
144 
145     FIBITMAP * resizePic = FreeImage_Rescale(sourcePic, resize_size.width, resize_size.height, FILTER_BOX);    
146     
147     FreeImage_Unload(sourcePic);
148     sourcePic = NULL;
149     
150     return resizePic;
151 
152 }
153 
154 int get_file_size1(const char * src_pic_path)
155 {
156     struct stat stat_buf;
157     stat(src_pic_path, &stat_buf);
158     int file_size =  stat_buf.st_size;
159     
160     return file_size;
161 }
162 
163 int get_file_size2(const char * src_pic_path)
164 {
165     FILE * fp = fopen(src_pic_path, "rb");
166     if(fp == NULL)
167         return 0;
168     
169     fseek (fp, 0, SEEK_END); 
170     int src_file_size = ftell(fp);
171     fclose(fp);    
172     
173     return src_file_size;
174 }
175 
176 int gen_symbolic_link(const char *src_pic_path, const char *des_pic_path)
177 {
178     char cmd[200];
179     sprintf(cmd, "ln -s %s %s", src_pic_path, des_pic_path);
180     int sh_ret = system(cmd);
181     
182     return sh_ret;
183 }
184 
185 int gen_small_thumbnail(const char *src_pic_path, const char *des_pic_path, int des_width, int des_height)
186 {
187     //printf("gen_small_thumbnail:%s --> %s w:%d, h:%d\\n", src_pic_path, des_pic_path, des_width, des_height);
188         
189     struct ImageSize des_size = {des_width, des_height};
190     
191     FIBITMAP *sourcePic = NULL, *finalPic = NULL;
192     FreeImage_Initialise();
193     FREE_IMAGE_FORMAT pic_type = FIF_UNKNOWN;
194     
195     //获取图片格式 
196     pic_type = FreeImage_GetFileType (src_pic_path, 0);
197     //printf("xxxxxxx:%d %d \\n", pic_type, FIT_BITMAP);
198     //是否支持该格式类型 
199     if(!FreeImage_FIFSupportsReading(pic_type))
200         return 480;
201         
202     //载入图片 
203     sourcePic = FreeImage_Load(pic_type, src_pic_path, 0);
204     
205     //剪切图片 
206     sourcePic = get_crop_picture(sourcePic);
207     if(!sourcePic)
208         return 481;
209     
210     //缩略图片 
211     sourcePic = get_resize_picture(sourcePic, des_size);
212     if(!sourcePic)
213         return 482;
214     
215     int returnValue = 0;
216     
217     //位图转换 
218     finalPic = FreeImage_ConvertTo24Bits(sourcePic); 
219     
220     //保存图片 
221     if(!FreeImage_Save(FIF_JPEG, finalPic, des_pic_path, JPEG_DEFAULT))
222         returnValue = 499;
223     
224     //释放资源 
225     FreeImage_Unload(sourcePic);
226     FreeImage_Unload(finalPic);
227     sourcePic = NULL;
228     finalPic = NULL;
229     FreeImage_DeInitialise();
230     
231     return returnValue;
232 }
233 
234 int gen_mid_thumbnail(const char *src_pic_path, const char *des_pic_path, int des_width, int des_height)
235 {
236     //printf("gen_mid_thumbnail:%s --> %s w:%d, h:%d\\n", src_pic_path, des_pic_path, des_width, des_height);
237     struct ImageSize des_size = {des_width, des_height};
238     
239     FIBITMAP *sourcePic = NULL, *finalPic = NULL;
240     FreeImage_Initialise();
241     FREE_IMAGE_FORMAT pic_type = FIF_UNKNOWN;
242     
243     //获取图片格式 
244     pic_type = FreeImage_GetFileType (src_pic_path, 0);
245     //printf("xxxxxxx:%d %d \\n", pic_type, FIT_BITMAP);
246     //是否支持该格式类型 
247     if(!FreeImage_FIFSupportsReading(pic_type))
248         return 480;
249         
250     //载入图片 
251     sourcePic = FreeImage_Load(pic_type, src_pic_path, 0);
252     
253     struct ImageSize src_size = {FreeImage_GetWidth(sourcePic), FreeImage_GetHeight(sourcePic)}; 
254     
255     //缩略图片 
256     int returnValue = 0;
257         
258     sourcePic = get_resize_picture(sourcePic, des_size);
259     if(!sourcePic)
260         return 482;    
261 
262     //int src_file_size = get_file_size2(src_pic_path);
263     int file_size = get_file_size1(src_pic_path);
264     
265     if(is_need_resize(src_size, des_size) || file_size > MID_IMAGE_LIMIT_SIZE){
266         //位图转换 
267         finalPic = FreeImage_ConvertTo24Bits(sourcePic); 
268     
269         //保存图片 
270         if(!FreeImage_Save(FIF_JPEG, finalPic, des_pic_path, JPEG_DEFAULT))
271             returnValue = 499;
272     }else{
273         int sh_ret = gen_symbolic_link(src_pic_path, des_pic_path);
274         //if(src_file_size > MID_IMAGE_LIMIT_SIZE)
275         //printf("src_file_size:%d file_size:%d sh:%d\\n", src_file_size, file_size, sh_ret);    
276     }
277     
278     //释放资源 
279     FreeImage_Unload(sourcePic);
280     FreeImage_Unload(finalPic);
281     sourcePic = NULL;
282     finalPic = NULL;
283     FreeImage_DeInitialise();
284     
285     return returnValue;
286 }
287 
288 /*
289 
290 usage:
291 
292     ./cpp_gen_thum src_pic_path des_pic_path height width type
293     
294     源文件地址 生成文件地址 目标高 目标宽 类型 
295 
296 */ 
297 
298 int main(int argc, char* argv[])
299 {
300 
301     struct timeval t1,t2;
302     double timeuse;
303     gettimeofday(&t1,NULL);
304 
305     int height = atoi(argv[3]);
306     int width = atoi(argv[4]);
307     int thum_type = atoi(argv[5]);
308     int result = 1;
309     
310     if(thum_type == THUM_TYPE_SMALL){
311         result = gen_small_thumbnail(argv[1], argv[2], height, width);
312     }else if(thum_type == THUM_TYPE_MID){
313         result = gen_mid_thumbnail(argv[1], argv[2], height, width);
314     }
315     
316     printf("%d", result);
317     
318 //    int small_res = gen_small_thumbnail(argv[1], argv[2], 120, 120);
319 //    int mid_res = gen_mid_thumbnail(argv[1], argv[3], 640, 640);
320 //    
321 //    gettimeofday(&t2,NULL);
322 //    timeuse = t2.tv_sec - t1.tv_sec + (t2.tv_usec - t1.tv_usec)/1000000.0;
323 //    printf("Use Time:%f small_res:%d filename:%s\\n\\t\\t  mid_res:%d filename:%s\\n", 
324 //        timeuse, small_res, argv[2], mid_res, argv[3]);
325     return 0;
326 }
View Code

 

以上是关于CPP 替代 PIL 图片处理(缩略图生成)的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 PIL 生成圆形缩略图?

PIL 缩略图正在旋转我的图像?

Thumbnailator java 图片处理技术

有关Python的PIL库的学习体会和实例

图片处理类,实现图片处理,包括添加水印和生成缩略图

高并发图片(缩略图)处理中间层服务架构设计