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 缩略图生成代码:
#include "stdio.h"
#include "stdlib.h"
#include "unistd.h"
#include <sys/time.h>
#include <sys/stat.h>
#include "FreeImage.h" #ifdef _DEBUG
#pragma comment(lib, "FreeImaged.lib")
#else
#pragma comment(lib, "FreeImage.lib")
#endif #define THUM_TYPE_SMALL 1
#define THUM_TYPE_MID 2 const float IMAGE_NEED_CROP_RATIO = 3.0;
const float IMAGE_CROP_RATIO = 1.76;
const int MID_IMAGE_LIMIT_SIZE = **; struct ImageSize{
int width;
int height;
}; inline void print_size(ImageSize img_size, const char* str)
{
printf("%s : %d %d\n", str, img_size.width, img_size.height);
} inline bool is_long_image(ImageSize img_size)
{ if(float(img_size.height) / img_size.width > IMAGE_NEED_CROP_RATIO)
return true;
else
return false;
} inline bool is_panorama_image(ImageSize img_size)
{ if(float(img_size.width) / img_size.height > IMAGE_NEED_CROP_RATIO)
return true;
else
return false;
} inline bool is_need_crop(ImageSize img_size)
{
if(is_long_image(img_size))
return true; if(is_panorama_image(img_size))
return true; return false;
} inline bool is_need_resize(ImageSize img_size, ImageSize des_img_size)
{
int width = img_size.width;
int height = img_size.height;
int des_width = des_img_size.width;
int des_height = des_img_size.height;
if((width < des_width) && (height < des_height))
return false;
else
return true;
} inline ImageSize get_crop_size(ImageSize img_size)
{
if(is_long_image(img_size))
img_size.height = img_size.width * IMAGE_CROP_RATIO;
else if(is_panorama_image(img_size))
img_size.width = img_size.height * IMAGE_CROP_RATIO; return img_size;
} inline ImageSize get_resize_size(ImageSize img_size, ImageSize des_img_size)
{
int width = img_size.width;
int height = img_size.height;
int des_width = des_img_size.width;
int des_height = des_img_size.height; float ratio = 1.0;
if(height > width)
ratio = float(des_height) / height;
else
ratio = float(des_width) / width; img_size.width = width * ratio;
img_size.height = height * ratio; return img_size;
} inline FIBITMAP * get_crop_picture(FIBITMAP *sourcePic)
{ int src_width, src_height; //获取图片大小
src_width = FreeImage_GetWidth(sourcePic);
src_height = FreeImage_GetHeight(sourcePic); struct ImageSize src_size = {src_width, src_height}; if(!is_need_crop(src_size))
return sourcePic; struct ImageSize crop_size = get_crop_size(src_size);
//print_size(crop_size, "crop_size"); FIBITMAP * cropPic = FreeImage_Copy(sourcePic, , , crop_size.width, crop_size.height); FreeImage_Unload(sourcePic);
sourcePic = NULL; return cropPic; } inline FIBITMAP * get_resize_picture(FIBITMAP *sourcePic, ImageSize des_size)
{ int src_width, src_height; //获取图片大小
src_width = FreeImage_GetWidth(sourcePic);
src_height = FreeImage_GetHeight(sourcePic); struct ImageSize src_size = {src_width, src_height}; if(!is_need_resize(src_size, des_size))
return sourcePic; struct ImageSize resize_size = get_resize_size(src_size, des_size);
//print_size(resize_size, "resize_size"); FIBITMAP * resizePic = FreeImage_Rescale(sourcePic, resize_size.width, resize_size.height, FILTER_BOX); FreeImage_Unload(sourcePic);
sourcePic = NULL; return resizePic; } int get_file_size1(const char * src_pic_path)
{
struct stat stat_buf;
stat(src_pic_path, &stat_buf);
int file_size = stat_buf.st_size; return file_size;
} int get_file_size2(const char * src_pic_path)
{
FILE * fp = fopen(src_pic_path, "rb");
if(fp == NULL)
return ; fseek (fp, , SEEK_END);
int src_file_size = ftell(fp);
fclose(fp); return src_file_size;
} int gen_symbolic_link(const char *src_pic_path, const char *des_pic_path)
{
char cmd[];
sprintf(cmd, "ln -s %s %s", src_pic_path, des_pic_path);
int sh_ret = system(cmd); return sh_ret;
} int gen_small_thumbnail(const char *src_pic_path, const char *des_pic_path, int des_width, int des_height)
{
//printf("gen_small_thumbnail:%s --> %s w:%d, h:%d\n", src_pic_path, des_pic_path, des_width, des_height); struct ImageSize des_size = {des_width, des_height}; FIBITMAP *sourcePic = NULL, *finalPic = NULL;
FreeImage_Initialise();
FREE_IMAGE_FORMAT pic_type = FIF_UNKNOWN; //获取图片格式
pic_type = FreeImage_GetFileType (src_pic_path, );
//printf("xxxxxxx:%d %d \n", pic_type, FIT_BITMAP);
//是否支持该格式类型
if(!FreeImage_FIFSupportsReading(pic_type))
return ; //载入图片
sourcePic = FreeImage_Load(pic_type, src_pic_path, ); //剪切图片
sourcePic = get_crop_picture(sourcePic);
if(!sourcePic)
return ; //缩略图片
sourcePic = get_resize_picture(sourcePic, des_size);
if(!sourcePic)
return ; int returnValue = ; //位图转换
finalPic = FreeImage_ConvertTo24Bits(sourcePic); //保存图片
if(!FreeImage_Save(FIF_JPEG, finalPic, des_pic_path, JPEG_DEFAULT))
returnValue = ; //释放资源
FreeImage_Unload(sourcePic);
FreeImage_Unload(finalPic);
sourcePic = NULL;
finalPic = NULL;
FreeImage_DeInitialise(); return returnValue;
} int gen_mid_thumbnail(const char *src_pic_path, const char *des_pic_path, int des_width, int des_height)
{
//printf("gen_mid_thumbnail:%s --> %s w:%d, h:%d\n", src_pic_path, des_pic_path, des_width, des_height);
struct ImageSize des_size = {des_width, des_height}; FIBITMAP *sourcePic = NULL, *finalPic = NULL;
FreeImage_Initialise();
FREE_IMAGE_FORMAT pic_type = FIF_UNKNOWN; //获取图片格式
pic_type = FreeImage_GetFileType (src_pic_path, );
//printf("xxxxxxx:%d %d \n", pic_type, FIT_BITMAP);
//是否支持该格式类型
if(!FreeImage_FIFSupportsReading(pic_type))
return ; //载入图片
sourcePic = FreeImage_Load(pic_type, src_pic_path, ); struct ImageSize src_size = {FreeImage_GetWidth(sourcePic), FreeImage_GetHeight(sourcePic)}; //缩略图片
int returnValue = ; sourcePic = get_resize_picture(sourcePic, des_size);
if(!sourcePic)
return ; //int src_file_size = get_file_size2(src_pic_path);
int file_size = get_file_size1(src_pic_path); if(is_need_resize(src_size, des_size) || file_size > MID_IMAGE_LIMIT_SIZE){
//位图转换
finalPic = FreeImage_ConvertTo24Bits(sourcePic); //保存图片
if(!FreeImage_Save(FIF_JPEG, finalPic, des_pic_path, JPEG_DEFAULT))
returnValue = ;
}else{
int sh_ret = gen_symbolic_link(src_pic_path, des_pic_path);
//if(src_file_size > MID_IMAGE_LIMIT_SIZE)
//printf("src_file_size:%d file_size:%d sh:%d\n", src_file_size, file_size, sh_ret);
} //释放资源
FreeImage_Unload(sourcePic);
FreeImage_Unload(finalPic);
sourcePic = NULL;
finalPic = NULL;
FreeImage_DeInitialise(); return returnValue;
} /* usage: ./cpp_gen_thum src_pic_path des_pic_path height width type 源文件地址 生成文件地址 目标高 目标宽 类型 */ int main(int argc, char* argv[])
{ struct timeval t1,t2;
double timeuse;
gettimeofday(&t1,NULL); int height = atoi(argv[]);
int width = atoi(argv[]);
int thum_type = atoi(argv[]);
int result = ; if(thum_type == THUM_TYPE_SMALL){
result = gen_small_thumbnail(argv[], argv[], height, width);
}else if(thum_type == THUM_TYPE_MID){
result = gen_mid_thumbnail(argv[], argv[], height, width);
} printf("%d", result); // int small_res = gen_small_thumbnail(argv[1], argv[2], 120, 120);
// int mid_res = gen_mid_thumbnail(argv[1], argv[3], 640, 640);
//
// gettimeofday(&t2,NULL);
// timeuse = t2.tv_sec - t1.tv_sec + (t2.tv_usec - t1.tv_usec)/1000000.0;
// printf("Use Time:%f small_res:%d filename:%s\n\t\t mid_res:%d filename:%s\n",
// timeuse, small_res, argv[2], mid_res, argv[3]);
return ;
}
CPP 替代 PIL 图片处理(缩略图生成)的更多相关文章
- C#图片切割、图片压缩、缩略图生成
C#图片切割.图片压缩.缩略图生成的实现代码 /// 图片切割函数 /// </summary> /// <param name="sourceFile"&g ...
- golang图片裁剪和缩略图生成
直接贴代码了 package main import ( "errors" "fmt" "image" "image/gif&qu ...
- ThinkPHP5.0图片上传生成缩略图实例代码
很多朋友遇到这样一个问题,图片上传生成缩略图,很多人在本机(win)测试成功,上传到linux 服务器后错误. 我也遇到同样的问题.网上一查,有无数的人说是服务器临时文件目录权限问题. 几经思考后,发 ...
- thinkphp图片上传+validate表单验证+图片木马检测+缩略图生成
目录 1.案例 1.1图片上传 1.2进行图片木马检测 1.3缩略图生成 1.4控制器中调用缩略图生成方法 1.案例 前言:在thinkphp框架的Thinkphp/Library/Thin ...
- python随机图片验证码的生成
Python生成随机验证码,需要使用PIL模块. 安装: 1 pip3 install pillow 基本使用 1. 创建图片 1 2 3 4 5 6 7 8 9 from PIL import Im ...
- python 将png图片格式转换生成gif动画
先看知乎上面的一个连接 用Python写过哪些[脑洞大开]的小工具? https://www.zhihu.com/question/33646570/answer/157806339 这个哥们通过爬气 ...
- android实现视频图片取缩略图
取缩略图不等同于缩放图片. 缩放图片是保持不失真的情况下缩放处理,并进行平滑处理. 缩略图则不然,允许失真,目的只是取出图片的轮廓. 保存Bitmap图片 private void saveBitma ...
- Java乔晓松-android中获取图片的缩略图(解决OutOfMemoryError)内存溢出的Bug
由于android获取图片过大是会出现内存溢出的Bug 07-02 05:10:13.792: E/AndroidRuntime(6016): java.lang.OutOfMemoryError 解 ...
- 织梦DEDECMS更换目录后页面内的图片和缩略图无法显示解决方法
http://www.win8f.com/seoyouhua/6609.html 很多人碰到织梦更换目录后内容图片和缩略图无法显示的问题,在此,慧鸿网络特地搜集整理了一篇关于织梦出现缩略图和内容无法显 ...
随机推荐
- uber司机 如何提高评分、接单率、成单率?
接单率/成单率的解释 接单率计算方法为:成功接单的订单数 除以 系统派单的订单数. 成单率计算方法为:成功完成的订单数 除以 系统派单的订单数. 滴滴快车单单2.5倍,注册地址:http://www. ...
- html模板 练习(仿照抽屉网)
1.页面布局 <!DOCTYPE html> <html lang="en"> <head> <meta charset="UT ...
- C++ OI图论 学习笔记(初步完结)
矩阵图 使用矩阵图来存储有向图和无向图的信息,用无穷大表示两点之间不连通,用两点之间的距离来表示连通.无向图的矩阵图是关于主对角线对称的. 如图所示: 使用dfs和bfs对矩阵图进行遍历 多源最短路径 ...
- [SDOI2010]地精部落 DP
LG传送门 DP好题 题意很简单,就是求1-n的排列,满足一个数两边的数要么都比它大要么都比它小,求这样的排列个数对\(p\)取膜的值(为了表述简单,我们称这样的排列为波动序列). 这个题我第一眼看到 ...
- Drupal7 针对特定条件才显示区块
当D7中开启PHP filter模块. Text format就会多出“PHP Code”选项. 而且,新建block时也会多出"Pages on which PHP code return ...
- Matplotlib API汉化
Pyplot API 示例汇总:https://matplotlib.org/gallery/index.html#api-examples 该matplotlib.pyplot模块包含的功能允许您快 ...
- 求两个字符串的最长公共子串——Java实现
要求:求两个字符串的最长公共子串,如“abcdefg”和“adefgwgeweg”的最长公共子串为“defg”(子串必须是连续的) public class Main03{ // 求解两个字符号的最长 ...
- 排序(C语言实现)
读数据结构与算法分析 插入排序 核心:利用的是从位置0到位置P都是已排序的 所以从位置1开始排序,如果当前位置不对,则和前面元素反复交换重新排序 实现 void InsertionSort(Eleme ...
- python sys.argv是什么?
1.sys.argv 是获取运行python文件的时候命令行参数,且以list形式存储参数 2.sys.argv[0] 代表当前module的名字 下面的代码文件是a.py,当我不用IDE工具,只用命 ...
- Phonegap 环境配置
目前要开发 Web App 还是有比较多的选择的 如 Phonegap.MUI.AppCan,接下来以 Web前端开发工程师 的角度来一个 Phonegap 的 First Blood 一.开发环境: ...