找回密码
 立即注册→加入我们

QQ登录

只需一步,快速开始

搜索
热搜: 下载 VB C 实现 编写
查看: 8341|回复: 0

【C】libjpeg的使用方法

[复制链接]
发表于 2015-4-8 17:45:51 | 显示全部楼层 |阅读模式

欢迎访问技术宅的结界,请注册或者登录吧。

您需要 登录 才可以下载或查看,没有账号?立即注册→加入我们

×
libjpeg是一个用于压缩、解压jpg格式图像的库。这个库在1998年后就不再更新了。但是jpeg的压缩格式却一直使用至今。简直是C语言中的战斗机。
libjpeg的使用方法很简单。首先借助makefile编译官方的源码取得libjpeg.lib然后设置自己的工程引用这个库就行了,我们稍后再讲怎么编译。

首先是头文件的包含。
#include"jpeglib.h"

然后就是接下来的两个部分:如何压缩,如何解压。

先说如何解压。
解压就是,你用fopen打开一个jpg文件(第二个参数是"rb"),分配内存用于存储解压后的位图,设置好你要接收的格式是什么类型,然后使用jpg的库完成解压。
首先你需要这样两个结构体:
  1. struct jpeg_decompress_struct cinfo;
  2. struct jpeg_error_mgr jem={0};
复制代码
其中jpeg_decompress_struct是装解压信息的结构体,jpeg_error_mgr是错误管理器,它里面有一系列的函数指针,你可以设置自己的错误回调函数。也可以不设置。如果你不设置,它遇到错误就执行exit(1),直接干掉你的程序。因此这也是一种很直观的调试方式——我的程序被干掉了就说明有错。

然后就对JPG文件进行读取。
  1. //打开文件
  2. fp=fopen(szFileName,"rb");
  3. if(!fp)
  4.         return;

  5. //设置错误处理
  6. cinfo.err=jpeg_std_error(&jem);

  7. //创建解压结构
  8. jpeg_create_decompress(&cinfo);

  9. //设置stdio读取来源
  10. jpeg_stdio_src(&cinfo,fp);

  11. //读取文件头
  12. jpeg_read_header(&cinfo,TRUE);
复制代码
之后用户需要自己根据需求分配一下内存,用于存储位图。搞定以后,运行如下的代码。
  1. //计算每行字节数的宏
  2. #define CalcPitch(b,w) ((((b)*(w)-1)/32+1)*4)

  3. //行指针
  4. JSAMPROW row_pointer[1];

  5. //每行字节数
  6. size_t cbPitch=CalcPitch(24,宽度);

  7. //设置输出的颜色类型
  8. cinfo.out_color_space=JCS_RGB;
  9. jpeg_calc_output_dimensions(&cinfo);

  10. //开始解压
  11. jpeg_start_decompress(&cinfo);

  12. //指向自己分配好的图像内存
  13. row_pointer[0]=(uint8_t*)g_pBits;

  14. //一行一行读取
  15. while(cinfo.output_scanline<cinfo.output_height)
  16. {
  17.         jpeg_read_scanlines(&cinfo,row_pointer,1);
  18.         row_pointer[0]+=cbPitch;//转到下一行。
  19. }

  20. //读取结束
  21. jpeg_finish_decompress(&cinfo);

  22. //释放资源
  23. jpeg_destroy_decompress(&cinfo);

  24. //关闭文件
  25. fclose(fp);
复制代码
然后你的图像就已经读取到g_pBits中了!

压缩,就是你提供一个位图(比如RGB像素阵列或者YUV阵列等,可以选择的),然后提供一个打开了写入文件的FILE*,设置好参数,就可以进行压缩了。
压缩要用到的结构体是:
  1. struct jpeg_compress_struct jcs;
  2. struct jpeg_error_mgr jem={0};
复制代码
同样的错误处理方式。
然后我们就可以打开文件进行写入操作了。
  1. //打开文件进行写入
  2. fp=fopen(szFileName,"wb");
  3. if(!fp)
  4.         return;

  5. //设置错误处理
  6. jcs.err=jpeg_std_error(&jem);

  7. //创建压缩结构
  8. jpeg_create_compress(&jcs);

  9. //设置stdio写入位置
  10. jpeg_stdio_dest(&jcs,fp);

  11. //设置写入参数
  12. jcs.image_width=宽度;//为图的宽和高,单位为像素
  13. jcs.image_height=高度;
  14. jcs.input_components=3;//图像源有红绿蓝三个组分
  15. jcs.in_color_space=JCS_RGB;//格式是红绿蓝真彩色
  16. jpeg_set_defaults(&jcs);//填写其它默认数值

  17. //设置图像品质
  18. //值的取值范围是[0,100],0表示渣画质,100表示满画质。
  19. jpeg_set_quality(&jcs,0/*渣画质*/,TRUE);

  20. //计算每行字节数
  21. cbPitch=CalcPitch(24,宽度);

  22. //开始压缩
  23. jpeg_start_compress(&jcs,TRUE);

  24. //指向要存储的位图。
  25. row_pointer[0]=(uint8_t*)g_pBits;

  26. //一行一行写入
  27. while(jcs.next_scanline<jcs.image_height)
  28. {
  29.         jpeg_write_scanlines(&jcs,row_pointer,1);
  30.         row_pointer[0]+=cbPitch;//转到下一行
  31. }

  32. //读取结束
  33. jpeg_finish_compress(&jcs);

  34. //释放资源
  35. jpeg_destroy_compress(&jcs);

  36. //关闭文件
  37. fclose(fp);
复制代码
接下来就是完整的工程的代码了。
这个工程演示了如何读取jpg、写入jpg的方法。
它会加载工程文件夹中的test.jpg,然后以渣画质方式输出到out.jpg。最后创建一个窗口用于显示加载的jpg图像。
(PS.为什么要用渣画质输出?因为这样能明显看到它有效地设置了画质然后输出了文件。)
  1. #include<tchar.h>
  2. #include<stdio.h>
  3. #include<Windows.h>

  4. #include<memory.h>
  5. #include<stdint.h>

  6. #undef FAR
  7. #define XMD_H
  8. #include"jpeglib.h"

  9. uint32_t        g_uWidth;
  10. uint32_t        g_uHeight;
  11. void                *g_pBits=NULL;
  12. HDC                        g_hDCJpeg=NULL;
  13. HBITMAP                g_hBMPJpeg=NULL;

  14. #define CalcPitch(b,w) ((((b)*(w)-1)/32+1)*4)

  15. //=============================================================================
  16. //函数:BuildBitmap
  17. //描述:建立位图用于绘图
  18. //-----------------------------------------------------------------------------
  19. void BuildBitmap(uint32_t uWidth,uint32_t uHeight)
  20. {
  21.         BITMAPINFOHEADER BMIF=
  22.         {
  23.                 sizeof(BITMAPINFOHEADER),
  24.                 (LONG)uWidth,
  25.                 -(LONG)uHeight,
  26.                 1,
  27.                 24,
  28.                 BI_RGB,
  29.                 0,
  30.                 0,
  31.                 0,
  32.                 0,
  33.                 0
  34.         };
  35.         g_uWidth=uWidth;
  36.         g_uHeight=uHeight;
  37.         if(g_hBMPJpeg)
  38.                 DeleteObject(&g_hBMPJpeg);
  39.         if(g_hDCJpeg)
  40.                 DeleteDC(g_hDCJpeg);
  41.         g_hDCJpeg=CreateCompatibleDC(NULL);
  42.         if(!g_hDCJpeg)
  43.                 return;
  44.         g_hBMPJpeg=CreateDIBSection(g_hDCJpeg,(BITMAPINFO*)&BMIF,DIB_PAL_COLORS,&g_pBits,NULL,0);
  45.         if(!g_hBMPJpeg)
  46.                 return;
  47.         SelectObject(g_hDCJpeg,g_hBMPJpeg);
  48. }

  49. //=============================================================================
  50. //函数:LoadJPG
  51. //描述:从文件中加载
  52. //-----------------------------------------------------------------------------
  53. void LoadJPG(char*szFileName)
  54. {
  55.         struct jpeg_decompress_struct cinfo;
  56.         struct jpeg_error_mgr jem={0};
  57.         FILE*fp=NULL;
  58.         JSAMPROW row_pointer[1];
  59.         size_t cbPitch;

  60.         fp=fopen(szFileName,"rb");
  61.         if(!fp)
  62.                 return;

  63.         //设置错误处理
  64.         cinfo.err=jpeg_std_error(&jem);

  65.         //创建解压结构
  66.         jpeg_create_decompress(&cinfo);

  67.         //设置stdio读取来源
  68.         jpeg_stdio_src(&cinfo,fp);

  69.         //读取文件头
  70.         jpeg_read_header(&cinfo,TRUE);

  71.         //分配内存,构建位图
  72.         BuildBitmap(cinfo.image_width,cinfo.image_height);
  73.         cbPitch=CalcPitch(24,g_uWidth);

  74.         //设置输出的颜色类型
  75.         cinfo.out_color_space=JCS_RGB;
  76.         jpeg_calc_output_dimensions(&cinfo);

  77.         //开始解压
  78.         jpeg_start_decompress(&cinfo);

  79.         row_pointer[0]=(uint8_t*)g_pBits;

  80.         //一行一行读取
  81.         while(cinfo.output_scanline<cinfo.output_height)
  82.         {
  83.                 jpeg_read_scanlines(&cinfo,row_pointer,1);
  84.                 row_pointer[0]+=cbPitch;
  85.         }

  86.         //读取结束
  87.         jpeg_finish_decompress(&cinfo);

  88.         //释放资源
  89.         jpeg_destroy_decompress(&cinfo);

  90.         //关闭文件
  91.         fclose(fp);
  92. }

  93. //=============================================================================
  94. //函数:SaveJPG
  95. //描述:保存到文件
  96. //-----------------------------------------------------------------------------
  97. void SaveJPG(char*szFileName)
  98. {
  99.         struct jpeg_compress_struct jcs;
  100.         struct jpeg_error_mgr jem={0};
  101.         FILE*fp=NULL;
  102.         JSAMPROW row_pointer[1];
  103.         size_t cbPitch;

  104.         //打开文件进行写入
  105.         fp=fopen(szFileName,"wb");
  106.         if(!fp)
  107.                 return;

  108.         //设置错误处理
  109.         jcs.err=jpeg_std_error(&jem);

  110.         //创建压缩结构
  111.         jpeg_create_compress(&jcs);

  112.         //设置stdio写入位置
  113.         jpeg_stdio_dest(&jcs,fp);

  114.         //设置写入参数
  115.         jcs.image_width=g_uWidth;//为图的宽和高,单位为像素
  116.         jcs.image_height=g_uHeight;
  117.         jcs.input_components=3;//图像源有红绿蓝三个组分
  118.         jcs.in_color_space=JCS_RGB;//格式是红绿蓝真彩色
  119.         jpeg_set_defaults(&jcs);

  120.         //设置图像品质
  121.         jpeg_set_quality(&jcs,0/*渣画质*/,TRUE);

  122.         cbPitch=CalcPitch(24,g_uWidth);

  123.         //开始压缩
  124.         jpeg_start_compress(&jcs,TRUE);

  125.         row_pointer[0]=(uint8_t*)g_pBits;

  126.         //一行一行写入
  127.         while(jcs.next_scanline<jcs.image_height)
  128.         {
  129.                 jpeg_write_scanlines(&jcs,row_pointer,1);
  130.                 row_pointer[0]+=cbPitch;
  131.         }

  132.         //读取结束
  133.         jpeg_finish_compress(&jcs);

  134.         //释放资源
  135.         jpeg_destroy_compress(&jcs);

  136.         //关闭文件
  137.         fclose(fp);
  138. }

  139. //=============================================================================
  140. //函数:SwapRGB
  141. //描述:将颜色从BGR到RGB之间进行转换
  142. //-----------------------------------------------------------------------------
  143. void SwapRGB()
  144. {
  145.         uint8_t*pLinePtr;
  146.         uint32_t x,y;
  147.         size_t cbPitch;
  148.         pLinePtr=(uint8_t*)g_pBits;
  149.         cbPitch=CalcPitch(24,g_uWidth);
  150.         for(y=0;y<g_uHeight;y++)
  151.         {
  152.                 for(x=0;x<g_uWidth;x++)
  153.                 {
  154.                         uint8_t t=pLinePtr[x*3];
  155.                         pLinePtr[x*3]=pLinePtr[x*3+2];
  156.                         pLinePtr[x*3+2]=t;
  157.                 }
  158.                 pLinePtr+=cbPitch;
  159.         }
  160. }

  161. LRESULT CALLBACK WndProc(HWND hWnd,UINT Msg,WPARAM wp,LPARAM lp);

  162. int APIENTRY _tWinMain
  163. (
  164.         HINSTANCE hInst,
  165.         HINSTANCE hPrevInst,
  166.         LPTSTR lpCmdLine,
  167.         int nShow
  168. )
  169. {
  170.         MSG msg;

  171.         WNDCLASSEX WCEx=
  172.         {
  173.                 sizeof(WNDCLASSEX),
  174.                 0,
  175.                 WndProc,
  176.                 0,
  177.                 0,
  178.                 hInst,
  179.                 LoadIcon(NULL,MAKEINTRESOURCE(IDI_APPLICATION)),
  180.                 LoadCursor(NULL,MAKEINTRESOURCE(IDC_ARROW)),
  181.                 (HBRUSH)(COLOR_BTNFACE+1),
  182.                 NULL,
  183.                 TEXT("Jpeg_Demo_Window"),
  184.                 LoadIcon(NULL,MAKEINTRESOURCE(IDI_APPLICATION))
  185.         };

  186.         HWND hWnd=CreateWindowEx(0,MAKEINTATOM(RegisterClassEx(&WCEx)),TEXT("JPG"),
  187.                 WS_OVERLAPPEDWINDOW,CW_USEDEFAULT,CW_USEDEFAULT,
  188.                 CW_USEDEFAULT,CW_USEDEFAULT,
  189.                 NULL,NULL,hInst,NULL);

  190.         ShowWindow(hWnd,nShow);
  191.         UpdateWindow(hWnd);

  192.         while(GetMessage(&msg,NULL,0,0))
  193.         {
  194.                 TranslateMessage(&msg);
  195.                 DispatchMessage(&msg);
  196.         }
  197.         return msg.wParam;
  198. }

  199. LRESULT CALLBACK WndProc(HWND hWnd,UINT Msg,WPARAM wp,LPARAM lp)
  200. {
  201.         switch(Msg)
  202.         {
  203.         case WM_CREATE:
  204.                 LoadJPG("test.jpg");
  205.                 SaveJPG("out.jpg");
  206.                 SwapRGB();
  207.                 break;
  208.         case WM_PAINT:
  209.                 {
  210.                         RECT rc;
  211.                         PAINTSTRUCT ps;
  212.                         HDC hDC=BeginPaint(hWnd,&ps);
  213.                         uint32_t TargW,TargH;

  214.                         SetStretchBltMode(hDC,HALFTONE);

  215.                         GetClientRect(hWnd,&rc);
  216.                         TargW=rc.right-rc.left;
  217.                         TargH=rc.bottom-rc.top;

  218.                         //如果需要缩小
  219.                         if(TargW<g_uWidth||TargH<g_uHeight)
  220.                         {
  221.                                 uint32_t DstW,DstH;
  222.                                 //首先宽度固定,计算高度
  223.                                 DstW=TargW;
  224.                                 DstH=DstW*g_uHeight/g_uWidth;
  225.                                 //如果高度超过目标,则高度固定,计算宽度
  226.                                 if(DstH>TargH)
  227.                                 {
  228.                                         DstH=TargH;
  229.                                         DstW=DstH*g_uWidth/g_uHeight;
  230.                                 }
  231.                                 StretchBlt(hDC,rc.left,rc.top,DstW,DstH,g_hDCJpeg,0,0,g_uWidth,g_uHeight,SRCCOPY);
  232.                         }
  233.                         else
  234.                                 BitBlt(hDC,rc.left,rc.top,g_uWidth,g_uHeight,g_hDCJpeg,0,0,SRCCOPY);
  235.                         EndPaint(hWnd,&ps);
  236.                 }
  237.                 break;
  238.         case WM_SIZING:
  239.         case WM_SIZE:
  240.                 {
  241.                         RECT rc;
  242.                         GetClientRect(hWnd,&rc);
  243.                         InvalidateRect(hWnd,&rc,TRUE);
  244.                 }
  245.                 break;
  246.         case WM_DESTROY:
  247.                 if(g_hBMPJpeg)
  248.                         DeleteObject(&g_hBMPJpeg);
  249.                 if(g_hDCJpeg)
  250.                         DeleteDC(g_hDCJpeg);
  251.                 PostQuitMessage(0);
  252.                 break;
  253.         }
  254.         return DefWindowProc(hWnd,Msg,wp,lp);
  255. }
复制代码
原图: 48042573_p0_master1200.jpg

图像来源:http://www.pixiv.net/member_illu ... ;illust_id=48042573
作者:稀泥m
途中的角色:時崎 狂三

程序窗口图:
20150408173812.png
BIN: jpeg.exe (114.09 KB, 下载次数: 9)
SRC: jpeg.7z (255.78 KB, 下载次数: 28)

接下来说到另一个问题——怎么取得libjpeg.lib?其实我觉得你既然能得到官方的源码了你就能自己编译。你可以用makefile编译,也可以自己建立一个工程来编译。那就像我上传的源码那样,直接把libjpeg中的源码加入到工程中参与编译就行了。
你只需要将以下的这些文件加入到自己的工程中,然后编译为静态库就行了。这样你还能借助VS的IDE设置自己的优化方式呢。
jcapimin.c,jcapistd.c,jccoefct.c,jccolor.c,jcdctmgr.c,jchuff.c,jchuff.h,jcinit.c,jcmainct.c,jcmarker.c,jcmaster.c,jcomapi.c,jconfig.h,jcparam.c,jcphuff.c,jcprepct.c,jcsample.c,jctrans.c,jdapimin.c,jdapistd.c,jdatadst.c,jdatasrc.c,jdcoefct.c,jdcolor.c,jdct.h,jddctmgr.c,jdhuff.c,jdhuff.h,jdinput.c,jdmainct.c,jdmarker.c,jdmaster.c,jdmerge.c,jdphuff.c,jdpostct.c,jdsample.c,jdtrans.c,jerror.c,jerror.h,jfdctflt.c,jfdctfst.c,jfdctint.c,jidctflt.c,jidctfst.c,jidctint.c,jidctred.c,jinclude.h,jmemmgr.c,jmemnobs.c,jmemsys.h,jmorecfg.h,jpegint.h,jpeglib.h,jquant1.c,jquant2.c,jutils.c,jversion.h然后你自己的工程只需要包含jpeglib.h就行了。其中jconfig.h是我从ijg的开源库中jconfig.vs改过来的。内存管理的源码用的是jmemnobs.c。对于Mac OS X遗迹其它系统,应该使用其它的内存管理源码。

本帖被以下淘专辑推荐:

回复

使用道具 举报

本版积分规则

QQ|Archiver|小黑屋|技术宅的结界 ( 滇ICP备16008837号 )|网站地图

GMT+8, 2024-11-22 02:40 , Processed in 0.033446 second(s), 28 queries , Gzip On.

Powered by Discuz! X3.5

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表