Go初接触之缩略图

Posted torrance

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Go初接触之缩略图相关的知识,希望对你有一定的参考价值。

  leader说要升级服务器上的缩略图服务,要用libjpeg-turbo库来写,前几天写的demo发现确实效率高了不少,所以用cgo把C的代码封装成库,已经基本完成。当成是一个对go、cgo的学习和对C的一些复习吧。

 1 #ifndef CompressImage_C
 2 #define CompressImage_C
 3 
 4 #include <stdio.h>
 5 #include <math.h>
 6 #include <string.h>
 7 #include "/opt/libjpeg-turbo/include/jpeglib.h"
 8 #include <stdlib.h>
 9 
10 typedef struct JPEGHEAD {
11     unsigned int height;
12     unsigned int width;
13     unsigned int isRBG;
14     unsigned char* msg;
15 }JPEGINFO;
16 
17 /**
18 * Paramater: image file name, a struct JPEGINFO to save information as the return value, the height of new image
19 */
20 int ReadJPEGImage(char* fileName, void* ret, int height);
21 
22 /**
23 * Paramater: new image file name, a struct JPEGINFO to save information, the quality of new image
24 */
25 int WriteJPEGImage(char* fileName, void* jpeginfo, int quality);
26 
27 /**
28 * Paramater: image file name, new image file name, the height of new image, the quality of new image
29 */
30 int CompressImageByName(char* fileNameSrc, char* fileNameDst, int height, int quality);
31 
32 void initStructInfo(void** ppret, void* msg, int height, int width, int isRGB);
33 
34 void freeStructInfo(void* pret);
35 
36 #endif
  1 #include <stdio.h>
  2 #include <math.h>
  3 #include <string.h>
  4 #include "CompressImage_C.h"
  5 #include "/opt/libjpeg-turbo/include/jpeglib.h"
  6 
  7 
  8 int ReadJPEGImage(char* fileName, void* jpeginfo, int height) {
  9     JPEGINFO* ret = (JPEGINFO*)jpeginfo;
 10     //定义变量
 11     struct jpeg_decompress_struct info;
 12     struct jpeg_error_mgr err;
 13     FILE* infile;
 14     JSAMPARRAY buffer;
 15     int rowStride, nowLine = 0;
 16     double standardProportion[4] = {0.125, 0.25, 0.5, 1.0};
 17 
 18     //初始化对象
 19     jpeg_create_decompress(&info);
 20 
 21     //绑定错误结构
 22     info.err = jpeg_std_error(&err);
 23 
 24     //打开图片并填入info对象
 25     if((infile = fopen(fileName, "rb")) == NULL) {
 26         fprintf(stderr, "can‘t open %s\n", fileName);
 27         return 1;
 28     }
 29     jpeg_stdio_src(&info, infile);
 30     //读取文件信息
 31     jpeg_read_header(&info, TRUE);
 32 
 33     //设定压缩比例
 34     //这里找的是比当前比例小的最大比例
 35     info.scale_num = 1;
 36     info.scale_denom = 1;
 37     double proportion = (double)(height) / (double)(info.image_height);
 38     for(int i = 0; i < 4; i ++) {
 39         if(proportion > standardProportion[i]) {
 40             if(i == 0) {
 41                 info.scale_denom = 8;
 42                 break;
 43             }
 44             else {
 45                 info.scale_denom = (int)(pow(2, i - 1));
 46                 break;
 47             }
 48         }
 49     }
 50 
 51     //开始解压缩
 52     jpeg_start_decompress(&info);
 53 
 54     //存入图片信息
 55     ret->height = info.output_height;
 56     ret->width = info.output_width;
 57     ret->isRBG = (info.output_components == 3) ? 1 : 0;
 58     rowStride = info.output_width * info.output_components;
 59     buffer = (*info.mem -> alloc_sarray)((j_common_ptr)&info, JPOOL_IMAGE, rowStride, 1);
 60     ret->msg = (unsigned char*)malloc(rowStride * ret->height + 1);
 61     nowLine = 0;
 62     while(info.output_scanline < info.output_height) {
 63         //从in中读取数据并写入out中
 64         jpeg_read_scanlines(&info, buffer, 1);
 65         memcpy(ret->msg + (nowLine * (ret->width) * 3), buffer[0], rowStride);
 66         nowLine ++;
 67         //for(int i = 0; i < rowStride; i ++) {
 68         //    ret->msg[nowLine * ret->width * 3 + i] = buffer[0][i];
 69         //}
 70     }
 71 
 72     //释放资源
 73     jpeg_finish_decompress(&info);
 74     jpeg_destroy_decompress(&info);
 75     fclose(infile);
 76     return 0;
 77 }
 78 
 79 int WriteJPEGImage(char* fileName, void* jpeginfo, int quality) {
 80     JPEGINFO* ret = (JPEGINFO*)jpeginfo;
 81     //定义变量
 82     struct jpeg_error_mgr err;
 83     struct jpeg_compress_struct info;
 84     FILE* outfile;
 85     int rowStride;
 86 
 87     //初始化对象
 88     jpeg_create_compress(&info);
 89 
 90     //绑定错误结构
 91     info.err = jpeg_std_error(&err);
 92 
 93     //打开图片并填入info对象
 94     if((outfile = fopen(fileName, "wb")) == NULL) {
 95         fprintf(stderr, "can‘t open %s\n", fileName);
 96         return 1;
 97     }
 98     jpeg_stdio_dest(&info, outfile);
 99 
100     //设定图片参数s
101     info.image_width = ret->width;
102     info.image_height = ret->height;
103     info.in_color_space = (ret->isRBG == 1) ? JCS_RGB : JCS_GRAYSCALE;
104     info.input_components = (ret->isRBG == 1) ? 3 : 1;
105     jpeg_set_defaults(&info);
106     jpeg_set_quality(&info, quality, TRUE);
107 
108     //开始压缩
109     jpeg_start_compress(&info, TRUE);
110 
111     //写入图片
112     rowStride = info.image_width * info.num_components;
113     unsigned char* now = ret->msg;
114     while(info.next_scanline < info.image_height) {
115         jpeg_write_scanlines(&info, &now, 1);
116         now += rowStride;
117     }
118 
119     //释放资源
120     jpeg_finish_compress(&info);
121     jpeg_destroy_compress(&info);
122     fclose(outfile);
123 
124     return 0;
125 }
126 
127 int CompressImageByName(char* fileNameSrc, char* fileNameDst, int height, int quality) {
128     JPEGINFO* jpeginfo;
129     int ret = 0;
130     jpeginfo = (JPEGINFO*)malloc(sizeof(JPEGINFO));
131     if((ret = ReadJPEGImage(fileNameSrc, (void*)jpeginfo, height)) == 1) {
132         free(jpeginfo);
133         return 1;
134     }
135     if((ret = WriteJPEGImage(fileNameDst, (void*)jpeginfo, quality)) == 1) {
136         free(jpeginfo);
137         return 1;
138     }
139     free(jpeginfo);
140     return 0;
141 }
142 
143 void initStructInfo(void** ppret, void* msg, int height, int width, int isRGB) {
144     unsigned char* imgMsg = (unsigned char*)msg;
145     FILE* tt;
146     JPEGINFO* pJPEGINFO = (JPEGINFO*)malloc(sizeof(JPEGINFO));
147     memset(pJPEGINFO, 0, sizeof(JPEGINFO));
148     pJPEGINFO->height = height;
149     pJPEGINFO->width = width;
150     pJPEGINFO->msg = imgMsg;
151     if(isRGB) pJPEGINFO->isRBG = 1;
152     else pJPEGINFO->isRBG = 0;
153     *ppret = pJPEGINFO;
154 }
155 
156 void freeStructInfo(void* pret) {
157     free((JPEGINFO*)pret);
158 }
 1 package Function
 2 
 3 /*
 4 #cgo LDFLAGS: -L /opt/libjpeg-turbo/lib64 -ljpeg
 5 #cgo LDFLAGS: -L ../Clib -lcompress
 6 #include "../Clib/CompressImage_C.h"
 7 */
 8 import "C"
 9 import (
10     "unsafe"
11 )
12 
13 func CompressImageByName(fileNameSrc, fileNameDst string, height, quality int) int {
14     fileNameSrcTmp := C.CString(fileNameSrc)
15     fileNameDstTmp := C.CString(fileNameDst)
16     heightTmp := C.int(height)
17     qualityTmp := C.int(quality)
18     ret := C.CompressImageByName(fileNameSrcTmp, fileNameDstTmp, heightTmp, qualityTmp)
19     C.free(unsafe.Pointer(fileNameDstTmp))
20     C.free(unsafe.Pointer(fileNameSrcTmp))
21     if ret == 0 {
22         return 0
23     } else {
24         return 1
25     }
26 }
27 
28 func CompressImageByByte(fileNameDst string, imgMsg *byte, height, width, quality int, isRGB bool) int {
29     fileNameDstTmp := C.CString(fileNameDst)
30     var ptr unsafe.Pointer
31     heightTmp, widthTmp, qualityTmp := C.int(height), C.int(width), C.int(quality)
32     msg := unsafe.Pointer(imgMsg)
33     inColor := 0
34     if isRGB == true {
35         inColor = 1
36     }
37     C.initStructInfo(&ptr, msg, heightTmp, widthTmp, C.int(inColor))
38     ret := C.WriteJPEGImage(fileNameDstTmp, ptr, qualityTmp)
39     C.freeStructInfo(ptr)
40     if ret == 0 {
41         return 0
42     } else {
43         return 1
44     }
45     return 0
46 }

  对于Go提供了两个接口,一个是给定文件名进行压缩,另一个是以byte[]方式给定数据,并给出图片的宽,高和质量以及是否是RGB图像,由于libjpeg-turbo只能支持1/1,1/2,1/4,1/8的压缩比例,所以代码里我选择的是不大于当前给定的高与原图的高的比值的那个最大比例。
  有几个需要注意的点,不要忘记先把.c文件用gcc -c和ar -crv命令编译成静态链接库,再用CGO LDFLAGS指明静态库位置后再操作。再就是CGO和C中的各种指针的转换比较麻烦,细心点就好了。

以上是关于Go初接触之缩略图的主要内容,如果未能解决你的问题,请参考以下文章

Go初接触之imagick

Go初接触之归并排序

Go初接触之image

Go+之环境安装与程序初体验

Android得到视频缩略图

我的Go+语言初体验——用Go+写个爬虫并进行数据处理