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初接触之缩略图的主要内容,如果未能解决你的问题,请参考以下文章