最近在研究libjpeg库的使用,主要是实现bmp位图和jpg图之间的格式互相转换。系统是ubuntu10.04,v6b版本的jpeg库。下载地址:http://www.ijg.org/files/jpegsrc.v6b.tar.gz。代码已经成功移植到tq2440 arm-linux中,能够正常运行,移植方法看这里http://blog.chinaunix.net/uid-11765716-id-172491.html。
首先说说jpg转bmp,参考了http://blog.马开东/mcgrady_tracy/article/details/7439066,并做了修改与完善。代码如下:
1 #include <stdio.h> 2 #include <setjmp.h> 3 #include <string.h> 4 #include <stdlib.h> 5 #include <jpeglib.h> 6 7 //将value低8位写入array[offset],高8位写入array[offset+1] 8 #define put_2b(array,offset,value) 9 (array[offset] = (char) ((value) & 0xff), 10 array[offset+1] = (char) (((value) >> 8) & 0xff)) 11 #define put_4b(array,offset,value) 12 (array[offset] = (char) ((value) & 0xff), 13 array[offset+1] = (char) (((value) >> 8) & 0xff), 14 array[offset+2] = (char) (((value) >> 16) & 0xff), 15 array[offset+3] = (char) (((value) >> 24) & 0xff)) 16 //写文件头 17 void write_bmp_header(j_decompress_ptr cinfo, file *output_file) 18 { 19 char bmpfileheader[14]; 20 char bmpinfoheader[40]; 21 long headersize, bfsize; 22 int bits_per_pixel, cmap_entries; 23 24 struct colormap{ //颜色表结构 25 uint8 blue; 26 uint8 green; 27 uint8 red; 28 uint8 reserved; 29 }; 30 int step; 31 int i=0; 32 /* compute colormap size and total file size */ 33 if (cinfo->out_color_space == jcs_rgb) { 34 if (cinfo->quantize_colors) { 35 /* colormapped rgb */ 36 bits_per_pixel = 8; 37 cmap_entries = 256; 38 } else { 39 /* unquantized, full color rgb */ 40 bits_per_pixel = 24; 41 cmap_entries = 0; 42 } 43 } else { 44 /* grayscale output. we need to fake a 256-entry colormap. */ 45 bits_per_pixel = 8; 46 cmap_entries = 256; 47 } 48 49 step = cinfo->output_width * cinfo->output_components; 50 51 while ((step & 3) != 0) step++; 52 53 /* file size */ 54 headersize = 14 + 40 + cmap_entries * 4; /* header and colormap */ 55 56 bfsize = headersize + (long) step * (long) cinfo->output_height; 57 58 /* set unused fields of header to 0 */ 59 memset(bmpfileheader, 0, sizeof(bmpfileheader)); 60 memset(bmpinfoheader, 0 ,sizeof(bmpinfoheader)); 61 62 /* fill the file header */ 63 bmpfileheader[0] = 0x42;/* first 2 bytes are ascii 'b', 'm' */ 64 bmpfileheader[1] = 0x4d; 65 put_4b(bmpfileheader, 2, bfsize); /* bfsize */ 66 /* we leave bfreserved1 & bfreserved2 = 0 */ 67 put_4b(bmpfileheader, 10, headersize); /* bfoffbits */ 68 69 /* fill the info header (microsoft calls this a bitmapinfoheader) */ 70 put_2b(bmpinfoheader, 0, 40); /* bisize */ 71 put_4b(bmpinfoheader, 4, cinfo->output_width); /* biwidth */ 72 put_4b(bmpinfoheader, 8, cinfo->output_height); /* biheight */ 73 put_2b(bmpinfoheader, 12, 1); /* biplanes - must be 1 */ 74 put_2b(bmpinfoheader, 14, bits_per_pixel); /* bibitcount */ 75 /* we leave bicompression = 0, for none */ 76 /* we leave bisizeimage = 0; this is correct for uncompressed data */ 77 if (cinfo->density_unit == 2) { /* if have density in dots/cm, then */ 78 put_4b(bmpinfoheader, 24, (int32) (cinfo->x_density*100)); /* xpels/m */ 79 put_4b(bmpinfoheader, 28, (int32) (cinfo->y_density*100)); /* xpels/m */ 80 } 81 put_2b(bmpinfoheader, 32, cmap_entries); /* biclrused */ 82 /* we leave biclrimportant = 0 */ 83 //写入文件头 84 if (fwrite(bmpfileheader, 1, 14, output_file) != (size_t) 14) { 85 printf("write bmpfileheader error\n"); 86 } 87 //写入信息头 88 if (fwrite(bmpinfoheader, 1, 40, output_file) != (size_t) 40) { 89 printf("write bmpinfoheader error\n"); 90 } 91 //写入颜色表,灰度图 92 if (cmap_entries ==256) { 93 struct colormap rgb[256]; 94 for(i=0;i<256;i++) 95 { 96 rgb[i].blue=i; 97 rgb[i].green=i; 98 rgb[i].red=i; 99 rgb[i].reserved=0;100 }101 //写入颜色表102 if (fwrite(rgb, 1, sizeof(struct colormap)*256, output_file) <0) {103 printf("write color error\n");104 }105 }106 }107 //写入位图数据108 void write_pixel_data(j_decompress_ptr cinfo, unsigned char *output_buffer, file *output_file)109 {110 int rows, cols;111 int row_width;112 int step;113 unsigned char *tmp = null;114 115 unsigned char *pdata;116 117 row_width = cinfo->output_width * cinfo->output_components;118 step = row_width;119 while ((step & 3) != 0) step++;120 121 pdata = (unsigned char *)malloc(step);122 memset(pdata, 0, step);123 //每次写入一行,并且调整rgb顺序。windows位图存储顺序是bgr,而libjpeg库是rgb124 tmp = output_buffer + row_width * (cinfo->output_height - 1);125 if(cinfo->output_components==3){ //24bit真彩图126 for (rows = 0; rows < cinfo->output_height; rows++) {127 for (cols = 0; cols < row_width; cols += 3) {128 pdata[cols + 2] = tmp[cols + 0];129 pdata[cols + 1] = tmp[cols + 1];130 pdata[cols + 0] = tmp[cols + 2];131 }132 tmp -= row_width;133 fwrite(pdata, 1, step, output_file);134 }135 }136 else //cinfo->output_components==1,8bit灰度图137 {138 for (rows = 0; rows < cinfo->output_height; rows++) {139 for (cols = 0; cols < row_width; cols ++) {140 pdata[cols] = tmp[cols];141 }142 tmp -= row_width;143 fwrite(pdata, 1, step, output_file);144 }145 }146 147 free(pdata);148 }149 //参考了libjpeg库里的example.c150 int read_jpeg_file(const char *input_filename, const char *output_filename)151 {152 struct jpeg_decompress_struct cinfo;153 struct jpeg_error_mgr jerr;154 file *input_file;155 file *output_file;156 js amparray buffer;157 int row_width;158 159 unsigned char *output_buffer;160 unsigned char *tmp = null;161 162 cinfo.err = jpeg_std_error(&jerr);163 164 if ((input_file = fopen(input_filename, "rb")) == null) {165 fprintf(stderr, "can't open %s\n", input_filename);166 return -1;167 }168 169 if ((output_file = fopen(output_filename, "wb")) == null) {170 171 fprintf(stderr, "can't open %s\n", output_filename);172 return -1;173 }174 175 jpeg_create_decompress(&cinfo);176 177 /* specify data source for decompression */178 jpeg_stdio_src(&cinfo, input_file);179 180 /* read file header, set default decompression parameters */181 (void) jpeg_read_header(&cinfo, true);182 183 /* start decompressor */184 (void) jpeg_start_decompress(&cinfo);185 186 row_width = cinfo.output_width * cinfo.output_components;187 188 buffer = (*cinfo.mem->alloc_sarray)189 ((j_common_ptr) &cinfo, jpool_image, row_width, 1);190 //写bmp文件头191 write_bmp_header(&cinfo, output_file);192 //分配bmp缓冲区193 output_buffer = (unsigned char *)malloc(row_width * cinfo.output_height);194 memset(output_buffer, 0, row_width * cinfo.output_height);195 tmp = output_buffer;196 197 /* process data */198 while (cinfo.output_scanline < cinfo.output_height) {199 (void) jpeg_read_scanlines(&cinfo, buffer, 1);200 201 memcpy(tmp, *buffer, row_width);202 tmp += row_width;203 }204 //写bmp数据205 write_pixel_data(&cinfo, output_buffer, output_file);206 207 free(output_buffer);208 209 (void) jpeg_finish_decompress(&cinfo);210 211 jpeg_destroy_decompress(&cinfo);212 213 /* close files, if we opened them */214 fclose(input_file);215 fclose(output_file);216 return 0;217 }218 219 int main(int argc, char *argv[])220 {221 if (argc < 3) {222 //read_jpeg_file("tt.jpg", "tt.bmp");223 printf("use:appname inputfile outputfile!\n");224 } else {225 read_jpeg_file(argv[1], argv[2]);226 }227 return 0;228 }229
代码中已经加了注释,编译方法:gcc jpg2bmp.c -ljpeg -o jpg2bmp 。 交叉编译:arm-linux-gcc jpg2bmp.c -ljpeg -o jpg2bmp。其中libjpeg库的移植可以参考:http://blog.chinaunix.net/uid-11765716-id-172491.html。运行方法:
./jpg2bmp test.jpg test.bmp ,其中test.jpg是测试图像。
bmp转jpg代码可以参考:http://www.makaidong.com/tiandsp/archive/2012/11/30/2796758.html,我发现网上很多利用libjpeg实现jpg转bmp的代码都有些问题,不能直接使用。
此文来自: 马开东博客 转载请注明出处 网址: http://www.makaidong.com
我对代码经过修改整理后,能够编译通过并且正确实现压缩24bit真彩图或者8bit灰度图。代码如下:1 /* 2 * bmp2jpg.c 3 * 4 * created on: jun 16, 2013 5 * author: root 6 */ 7 #include <stdio.h> 8 #include <setjmp.h> 9 #include <string.h> 10 #include <stdlib.h> 11 #include <jpeglib.h> 12 13 file *bmpfile;//输入文件 14 int image_width,image_height,image_size,bits_per_pixel,headersize,depth; 15 unsigned char *src_data;//位图数据 16 17 int get_2b(unsigned char*a,int offset) 18 { 19 return a[offset+1]<<8|a[offset]; 20 } 21 int get_4b(unsigned char*a,int offset) 22 { 23 return (a[offset+3]<<24)|(a[offset+2]<<16)|(a[offset+1]<<8)|a[offset]; 24 } 25 //读取位图文件头和位图数据 26 void read_bmp_header(char *bmpfilename) 27 { 28 unsigned char bmpfileheader[14];//文件头 29 unsigned char bmpinfoheader[40];//信息头 30 bmpfile=fopen(bmpfilename,"r");// 31 if(bmpfile<0) 32 printf("open bmp file error!\n"); 33 printf("open bmp file success!\n"); 34 //读取bmp文件头 35 fread(bmpfileheader,14,1,bmpfile); 36 int type=get_2b(bmpfileheader,0); 37 printf("type=0x%x\n",type); 38 int filesize=get_4b(bmpfileheader,2); 39 printf("filesize=%d bytes\n",filesize); 40 headersize=get_4b(bmpfileheader,10); 41 printf("headersize=%d bytes\n",headersize); 42 if(headersize>54) 43 printf("colormap size=%d bytes\n",headersize-54); 44 //读取bmp信息头 45 fseek(bmpfile,14,seek_set); 46 fread(bmpinfoheader,40,1,bmpfile); 47 image_width=get_4b(bmpinfoheader,4); 48 /*图像的宽度必须被4整除,否则jpg图像会变形!!! 49 这个很多代码里都没有说明,我在压缩图片时发现有些图片能够正确压缩,有些图片压缩后变形 50 经过仔细研究发现是宽度有问题*/ 51 while (image_width%4!=0) 52 image_width++; 53 printf("weight=%d\n",image_width); 54 image_height=get_4b(bmpinfoheader,8); 55 printf("height=%d\n",image_height); 56 bits_per_pixel=get_2b(bmpinfoheader,14); 57 printf("bits_per_pixel=%d\n",bits_per_pixel); 58 depth=bits_per_pixel/8; 59 image_size=image_width*image_height*depth; 60 src_data=(unsigned char *)malloc(image_size); 61 fseek(bmpfile,headersize,seek_set); 62 fread(src_data,sizeof(unsigned char)*image_size,1,bmpfile); 63 fclose(bmpfile); 64 } 65 //参考了libjpeg库里的example.c 66 void write_jpeg_file (char * outfilename, unsigned char * buffer,int quality) 67 { 68 struct jpeg_compress_struct cinfo; 69 struct jpeg_error_mgr jerr; 70 file * outfile; 71 unsigned char *dst_data; 72 int i,j; 73 //char *point; 74 js amprow row_pointer[1]; 75 //js amparray buffer; 76 int row_stride; 77 cinfo.err = jpeg_std_error(&jerr); 78 jpeg_create_compress(&cinfo); 79 //打开输出jpg文件 80 if ((outfile = fopen(outfilename, "w+")) == null) { 81 fprintf(stderr, "can't open %s\n", outfilename); 82 exit(1); 83 } 84 85 jpeg_stdio_dest(&cinfo, outfile); 86 cinfo.image_width = image_width; /* image width and height, in pixels */ 87 cinfo.image_height = image_height; 88 cinfo.input_components = depth; /* # of color components per pixel */ 89 cinfo.in_color_space = (depth==3) ? jcs_rgb : jcs_grayscale; /* colorspace of input image */ 90 91 jpeg_set_defaults(&cinfo); 92 jpeg_set_quality(&cinfo, quality, true /* limit to baseline-jpeg values */); 93 dst_data=(unsigned char *)malloc(image_size*sizeof(unsigned char)); 94 //调整rgb顺序bgr->rgb 95 for(i=0;i<image_height;i++){ 96 for(j=0;j<image_width;j++) 97 { 98 if(depth==1)//灰度图 99 *(dst_data+i*image_width+j)=*(src_data+i*image_width+j);100 else //真彩图101 {102 *(dst_data+i*image_width*depth+j*3+0)=*(src_data+i*image_width*depth+j*3+2);103 *(dst_data+i*image_width*depth+j*3+1)=*(src_data+i*image_width*depth+j*3+1);104 *(dst_data+i*image_width*depth+j*3+2)=*(src_data+i*image_width*depth+j*3+0);105 }106 }107 }108 jpeg_start_compress(&cinfo, true);109 110 row_stride = image_width * cinfo.input_components; /* js amples per row in image_buffer */111 112 while (cinfo.next_scanline < cinfo.image_height) {113 row_pointer[0] = & dst_data[(cinfo.image_height - cinfo.next_scanline - 1) * row_stride];//cinfo.next_scanline * row_stride114 (void) jpeg_write_scanlines(&cinfo, row_pointer, 1);115 116 }117 118 jpeg_finish_compress(&cinfo);119 fclose(outfile);120 jpeg_destroy_compress(&cinfo);121 free(src_data);122 free(dst_data);123 }124 int main(int argc,char *argv[])125 {126 if(argc<4)127 printf("use:appname inputname outputname quality\n");128 else{129 read_bmp_header(argv[1]);130 write_jpeg_file(argv[2],src_data,atoi(argv[3]));131 }132 return 0;133 }
编译方法上面已经说了,都是相同的。编译后运行:./bmp2jpg test.bmp test.jpg 70 ,其中test.bmp是输入图像,70是jpg的压缩质量。
联系客服