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 很多人碰到织梦更换目录后内容图片和缩略图无法显示的问题,在此,慧鸿网络特地搜集整理了一篇关于织梦出现缩略图和内容无法显 ...
随机推荐
- Linux 下 的 Oracle,如何安装 tnsname
运行 netca 即可:
- RHSCA模拟考试
开始考试:桌面是个黑框子 点击reboot按钮,破解密码 开机成功,输入startx进入图形界面 不能复制,要在物理机用ssh root@172.25.0.11 远程连接,就可以复制粘贴了 * Hos ...
- [转]资深CTO:关于技术团队打造与管理的10问10答
一.你如何衡量软件工程师个人的工作表现?如何衡量整个工程师团队的工作表现? 主要从两方面: 这个员工做的工作是不是他同意做的或者应该做的?(What) 他们是如何完成自己的工作的?(How) 任何绩效 ...
- JavaWeb(十七)——JSP中的九个内置对象
一.JSP运行原理 每个JSP 页面在第一次被访问时,WEB容器都会把请求交给JSP引擎(即一个Java程序)去处理.JSP引擎先将JSP翻译成一个_jspServlet(实质上也是一个servlet ...
- MES与ERP的区别(转)
MES和ERP有很大的不同,主要体现在以下几个方面: 1.管理的目标不同 ERP的重点在于财务,也就是从财务的角度出发来对企业的资源进行计划,相关的模块也是以财务为核心的展开,最终的管理数据也是集中到 ...
- ubuntu18.04安装mongoDB 4.0
STEP 1: 在终端输入GPK码 $ sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv 9DA31620334B ...
- 用MYSQLworkbench导出数据excel
步骤: 1.先从数据库中将表导出,右键需要导出的表格——>Table Data Export Wizard 2.点击Next,选择你需要把数据存放的文件路径.导出的数据格式(表格的话就默认选择C ...
- Linux☞权限数字表示法
权限数字表示法: 1.Linux有三种访问权限: a.可读:r(Read) b.可写:w(Write) c.可执行:x(eXcute) 2.简单说说如何去看该文件的访问权限呢?一般我们执行命令,查看目 ...
- 第六篇 native 版本的Postman如何通过代理服务器录制Web及手机APP请求
第四篇主要介绍了chrome app版本的postman如何安装及如何录制Web脚本,比较简单. 但是chrome app 版本和native 版本相比,对应chrome app 版本官方已经放弃支持 ...
- MYSQL存储过程调试过程
mysql不像oracle有plsqldevelper工具用来调试存储过程,所以有几种简单的方式追踪执行过程: 1.用一张临时表,记录调试过程: 2.直接在存储过程中,增加select xxx,在控 ...