libJPEG库是用于编码数据为JPEG格式或者解码JPEG格式图片的常用库,OpenCV读取图像底层实现就是利用libJPEG库,而libJPEG-turbo则效率更高。
具体怎么编译编译libJPEG库源码得到lib库的方法很容易搜到,不多做介绍。
下面的代码包含了该库中常用的API用法,包括读取一幅JPEG图片并解码到内存、编码内存中的数据为JPEG图片写入本地等。
1 #include <iostream>
2 #include <stdio.h>
3 #include <setjmp.h>
4 #include <string.h>
5 #include <stdlib.h>
6 #include <jpeglib.h>
7 #include <opencv2/opencv.hpp>
8
9 using namespace std;
10
11 int read_JPEG_file(string strImageName)
12 {
13 /* This struct contains the JPEG decompression parameters and pointers to
14 * working space (which is allocated as needed by the JPEG library).
15 */
16 struct jpeg_decompress_struct cinfo;
17 /* We use our private extension JPEG error handler.
18 * Note that this struct must live as long as the main JPEG parameter
19 * struct, to avoid dangling-pointer problems.
20 */
21 struct jpeg_error_mgr jerr;
22 /* More stuff */
23 FILE * infile;/* source file */
24 JSAMPARRAY buffer;/* Output row buffer */
25 int row_stride;/* physical row width in output buffer */
26
27 /* In this example we want to open the input file before doing anything else,
28 * so that the setjmp() error recovery below can assume the file is open.
29 * VERY IMPORTANT: use "b" option to fopen() if you are on a machine that
30 * requires it in order to read binary files.
31 */
32 if ((infile = fopen(strImageName.c_str(), "rb")) == NULL) {
33 fprintf(stderr, "can't open %s\n", strImageName);
34 return -1;
35 }
36
37 /* Step 1: allocate and initialize JPEG decompression object */
38 /* We set up the normal JPEG error routines, then override error_exit. */
39 cinfo.err = jpeg_std_error(&jerr);
40 /* Establish the setjmp return context for my_error_exit to use. */
41 //if (setjmp(jerr.setjmp_buffer)) {
42 /* If we get here, the JPEG code has signaled an error.
43 * We need to clean up the JPEG object, close the input file, and return.
44 */
45 //jpeg_destroy_decompress(&cinfo);
46 //fclose(infile);
47 //return -1;
48 //}
49
50 /* Now we can initialize the JPEG decompression object. */
51 jpeg_create_decompress(&cinfo);
52
53 /* Step 2: specify data source (eg, a file) */
54 jpeg_stdio_src(&cinfo, infile);
55
56 /* Step 3: read file parameters with jpeg_read_header() */
57 jpeg_read_header(&cinfo, TRUE);
58 /* We can ignore the return value from jpeg_read_header since
59 * (a) suspension is not possible with the stdio data source, and
60 * (b) we passed TRUE to reject a tables-only JPEG file as an error.
61 * See libjpeg.txt for more info.
62 */
63 printf("image_width = %d\n", cinfo.image_width);
64 printf("image_height = %d\n", cinfo.image_height);
65 printf("num_components = %d\n", cinfo.num_components);
66
67 /* Step 4: set parameters for decompression */
68 /* In this example, we don't need to change any of the defaults set by
69 * jpeg_read_header(), so we do nothing here.
70 */
71 printf("enter scale M/N:\n");
72 //scanf("%d/%d", &cinfo.scale_num, &cinfo.scale_denom);
73 cinfo.scale_num = 1;
74 cinfo.scale_denom = 1;
75 printf("scale to : %d/%d\n", cinfo.scale_num, cinfo.scale_denom);
76
77 /* Step 5: Start decompressor */
78 jpeg_start_decompress(&cinfo);
79 /* We can ignore the return value since suspension is not possible
80 * with the stdio data source.
81 */
82
83 //输出的图象的信息
84 printf("output_width = %d\n", cinfo.output_width);
85 printf("output_height = %d\n", cinfo.output_height);
86 printf("output_components = %d\n", cinfo.output_components);
87
88 /* We may need to do some setup of our own at this point before reading
89 * the data. After jpeg_start_decompress() we have the correct scaled
90 * output image dimensions available, as well as the output colormap
91 * if we asked for color quantization.
92 * In this example, we need to make an output work buffer of the right size.
93 */
94 /* JSAMPLEs per row in output buffer */
95 row_stride = cinfo.output_width * cinfo.output_components;
96 /* Make a one-row-high sample array that will go away when done with image */
97 buffer = (*cinfo.mem->alloc_sarray)((j_common_ptr)&cinfo, JPOOL_IMAGE, row_stride, 1);
98
99 /* Step 6: while (scan lines remain to be read) */
100 /* jpeg_read_scanlines(...); */
101 /* Here we use the library's state variable cinfo.output_scanline as the
102 * loop counter, so that we don't have to keep track ourselves.
103 */
104 while (cinfo.output_scanline < cinfo.output_height) {
105 /* jpeg_read_scanlines expects an array of pointers to scanlines.
106 * Here the array is only one element long, but you could ask for
107 * more than one scanline at a time if that's more convenient.
108 */
109 jpeg_read_scanlines(&cinfo, buffer, 1);
110 /* Assume put_scanline_someplace wants a pointer and sample count. */
111 //put_scanline_someplace(buffer[0], row_stride);
112 }
113
114 /* Step 7: Finish decompression */
115 jpeg_finish_decompress(&cinfo);
116 /* We can ignore the return value since suspension is not possible
117 * with the stdio data source.
118 */
119
120 /* Step 8: Release JPEG decompression object */
121 /* This is an important step since it will release a good deal of memory. */
122 jpeg_destroy_decompress(&cinfo);
123
124 /* After finish_decompress, we can close the input file.
125 * Here we postpone it until after no more JPEG errors are possible,
126 * so as to simplify the setjmp error logic above. (Actually, I don't
127 * think that jpeg_destroy can do an error exit, but why assume anything...)
128 */
129 fclose(infile);
130
131 /* At this point you may want to check to see whether any corrupt-data
132 * warnings occurred (test whether jerr.pub.num_warnings is nonzero).
133 */
134
135 return 0;
136 }
137
138 int write_JPEG_file(string strImageName, int quality)
139 {
140 unsigned char* image_buffer; /* Points to large array of R,G,B-order data */
141 int image_height = 780; /* Number of rows in image */
142 int image_width = 1040; /* Number of columns in image */
143
144 /* This struct contains the JPEG compression parameters and pointers to
145 * working space (which is allocated as needed by the JPEG library).
146 * It is possible to have several such structures, representing multiple
147 * compression/decompression processes, in existence at once. We refer
148 * to any one struct (and its associated working data) as a "JPEG object".
149 */
150 struct jpeg_compress_struct cinfo;
151
152 /* This struct represents a JPEG error handler. It is declared separately
153 * because applications often want to supply a specialized error handler
154 * (see the second half of this file for an example). But here we just
155 * take the easy way out and use the standard error handler, which will
156 * print a message on stderr and call exit() if compression fails.
157 * Note that this struct must live as long as the main JPEG parameter
158 * struct, to avoid dangling-pointer problems.
159 */
160 struct jpeg_error_mgr jerr;
161 /* More stuff */
162 FILE * outfile; /* target file */
163 JSAMPROW row_pointer[1]; /* pointer to JSAMPLE row[s] */
164 int row_stride; /* physical row width in image buffer */
165
166 /* Step 1: allocate and initialize JPEG compression object */
167
168 /* We have to set up the error handler first, in case the initialization
169 * step fails. (Unlikely, but it could happen if you are out of memory.)
170 * This routine fills in the contents of struct jerr, and returns jerr's
171 * address which we place into the link field in cinfo.
172 */
173 cinfo.err = jpeg_std_error(&jerr);
174 /* Now we can initialize the JPEG compression object. */
175 jpeg_create_compress(&cinfo);
176
177 /* Step 2: specify data destination (eg, a file) */
178 /* Note: steps 2 and 3 can be done in either order. */
179
180 /* Here we use the library-supplied code to send compressed data to a
181 * stdio stream. You can also write your own code to do something else.
182 * VERY IMPORTANT: use "b" option to fopen() if you are on a machine that
183 * requires it in order to write binary files.
184 */
185 if ((outfile = fopen(strImageName.c_str(), "wb")) == NULL) {
186 fprintf(stderr, "can't open %s\n", strImageName);
187 //exit(1);
188 return -1;
189 }
190 jpeg_stdio_dest(&cinfo, outfile);
191
192 /* Step 3: set parameters for compression */
193 /* First we supply a description of the input image.
194 * Four fields of the cinfo struct must be filled in:
195 */
196 cinfo.image_width = image_width; /* image width and height, in pixels */
197 cinfo.image_height = image_height;
198 cinfo.input_components = 3; /* # of color components per pixel */
199 cinfo.in_color_space = JCS_RGB; /* colorspace of input image */
200 /* Now use the library's routine to set default compression parameters.
201 * (You must set at least cinfo.in_color_space before calling this,
202 * since the defaults depend on the source color space.)
203 */
204 jpeg_set_defaults(&cinfo);
205 /* Now you can set any non-default parameters you wish to.
206 * Here we just illustrate the use of quality (quantization table) scaling:
207 */
208 jpeg_set_quality(&cinfo, quality, TRUE /* limit to baseline-JPEG values */);
209
210 /* Step 4: Start compressor */
211 /* TRUE ensures that we will write a complete interchange-JPEG file.
212 * Pass TRUE unless you are very sure of what you're doing.
213 */
214 jpeg_start_compress(&cinfo, TRUE);
215
216 /* Step 5: while (scan lines remain to be written) */
217 /* jpeg_write_scanlines(...); */
218 /* Here we use the library's state variable cinfo.next_scanline as the
219 * loop counter, so that we don't have to keep track ourselves.
220 * To keep things simple, we pass one scanline per call; you can pass
221 * more if you wish, though.
222 */
223 row_stride = image_width * 3; /* JSAMPLEs per row in image_buffer */
224
225 image_buffer = new unsigned char[row_stride * cinfo.image_height];
226 memset(image_buffer, 0xff, row_stride * cinfo.image_height);
227
228 int line = 0;
229 //while (cinfo.next_scanline < cinfo.image_height) {
230 while (line < cinfo.image_height) {
231 /* jpeg_write_scanlines expects an array of pointers to scanlines.
232 * Here the array is only one element long, but you could pass
233 * more than one scanline at a time if that's more convenient.
234 */
235 //row_pointer[0] = &image_buffer[cinfo.next_scanline * row_stride];
236 row_pointer[0] = &image_buffer[line * row_stride];
237 jpeg_write_scanlines(&cinfo, row_pointer, 1);
238
239 line++;
240 }
241
242 delete image_buffer;
243
244 /* Step 6: Finish compression */
245 jpeg_finish_compress(&cinfo);
246 /* After finish_compress, we can close the output file. */
247 fclose(outfile);
248
249 /* Step 7: release JPEG compression object */
250 /* This is an important step since it will release a good deal of memory. */
251 jpeg_destroy_compress(&cinfo);
252
253 return 0;
254 }
255
256 struct Image
257 {
258 int bpp;
259 int width;
260 int height;
261 unsigned char* data;
262 };
263
264 struct jerror_mgr
265 {
266 jpeg_error_mgr base;
267 jmp_buf jmp;
268 };
269
270 METHODDEF(void) jerror_exit(j_common_ptr jinfo)
271 {
272 jerror_mgr* err = (jerror_mgr*)jinfo->err;
273 longjmp(err->jmp, 1);
274 }
275
276 METHODDEF(void) joutput_message(j_common_ptr)
277 {
278 }
279
280 bool Image_LoadJpeg(Image* image, unsigned char* img_data, unsigned int img_size)
281 {
282 jpeg_decompress_struct jinfo;
283 jerror_mgr jerr;
284
285 jinfo.err = jpeg_std_error(&jerr.base);
286 jerr.base.error_exit = jerror_exit;
287 jerr.base.output_message = joutput_message;
288 jpeg_create_decompress(&jinfo);
289
290 image->data = NULL;
291
292 if (setjmp(jerr.jmp)) goto bail;
293
294 jpeg_mem_src(&jinfo, img_data, img_size);
295
296 if (jpeg_read_header(&jinfo, TRUE) != JPEG_HEADER_OK) goto bail;
297
298 jinfo.dct_method = JDCT_FLOAT; // change this to JDCT_ISLOW on Android/iOS
299
300 if (!jpeg_start_decompress(&jinfo)) goto bail;
301
302 if (jinfo.num_components != 1 && jinfo.num_components != 3) goto bail;
303
304 image->data = new (std::nothrow) unsigned char[jinfo.output_width * jinfo.output_height * jinfo.output_components];
305 if (!image->data) goto bail;
306
307 {
308 JSAMPROW ptr = image->data;
309 while (jinfo.output_scanline < jinfo.output_height)
310 {
311 if (jpeg_read_scanlines(&jinfo, &ptr, 1) != 1) goto bail;
312
313 ptr += jinfo.output_width * jinfo.output_components;
314 }
315 }
316
317 if (!jpeg_finish_decompress(&jinfo)) goto bail;
318
319 image->bpp = jinfo.output_components;
320 image->width = jinfo.output_width;
321 image->height = jinfo.output_height;
322
323 jpeg_destroy_decompress(&jinfo);
324
325 return true;
326
327 bail:
328 jpeg_destroy_decompress(&jinfo);
329 if (image->data) delete[] image->data;
330
331 return false;
332 }
333
334 struct ImageData {
335 unsigned char *pixels;
336 long width;
337 long height;
338 };
339
340 int TestImage(string strSrcImageName, string strDstImageName)
341 {
342 //read
343 struct jpeg_decompress_struct cinfo_decompress;
344 FILE* infile;
345 int row_stride;
346 struct jpeg_error_mgr jerr;
347
348 if ((infile = fopen(strSrcImageName.c_str(), "rb")) == NULL) {
349 fprintf(stderr, "can't open %s\n", strSrcImageName);
350 return -1;
351 }
352
353 cinfo_decompress.err = jpeg_std_error(&jerr);
354 jpeg_create_decompress(&cinfo_decompress);
355 jpeg_stdio_src(&cinfo_decompress, infile);
356 int ret = jpeg_read_header(&cinfo_decompress, TRUE);
357 if (ret != JPEG_HEADER_OK) return -1;
358 jpeg_start_decompress(&cinfo_decompress);
359 row_stride = cinfo_decompress.output_width * cinfo_decompress.output_components;
360 int buffer_height = 1;
361 JSAMPARRAY buffer = (JSAMPARRAY)malloc(sizeof(JSAMPROW) * buffer_height);
362 buffer[0] = (JSAMPROW)malloc(sizeof(JSAMPLE) * row_stride);
363 //JSAMPARRAY buffer = (*cinfo_decompress.mem->alloc_sarray)((j_common_ptr)&cinfo_decompress, JPOOL_IMAGE, row_stride, 1);
364 ImageData *imageData;
365 imageData = new ImageData;
366 imageData->width = cinfo_decompress.output_width;
367 imageData->height = cinfo_decompress.output_height;
368
369 imageData->pixels = new unsigned char[cinfo_decompress.output_width * cinfo_decompress.output_height * cinfo_decompress.output_components];
370 long counter = 0;
371
372 while (cinfo_decompress.output_scanline < cinfo_decompress.output_height) {
373 jpeg_read_scanlines(&cinfo_decompress, buffer, 1);
374 memcpy(imageData->pixels + counter, buffer[0], row_stride);
375 counter += row_stride;
376 }
377
378 jpeg_finish_decompress(&cinfo_decompress);
379 jpeg_destroy_decompress(&cinfo_decompress);
380
381 fclose(infile);
382
383 //write
384 unsigned char* image_buffer;
385 int image_height = cinfo_decompress.output_height;
386 int image_width = cinfo_decompress.output_width;
387 FILE * outfile;
388 JSAMPROW row_pointer[1];
389 int row_stride_dst;
390 struct jpeg_compress_struct cinfo_compress;
391 cinfo_compress.err = jpeg_std_error(&jerr);
392 jpeg_create_compress(&cinfo_compress);
393
394 if ((outfile = fopen(strDstImageName.c_str(), "wb")) == NULL) {
395 fprintf(stderr, "can't open %s\n", strDstImageName);
396 //exit(1);
397 return -1;
398 }
399
400 jpeg_stdio_dest(&cinfo_compress, outfile);
401
402 cinfo_compress.image_width = image_width;
403 cinfo_compress.image_height = image_height;
404 cinfo_compress.input_components = 3;
405 cinfo_compress.in_color_space = JCS_EXT_RGB;
406
407 int quality = 70;
408 jpeg_set_defaults(&cinfo_compress);
409 jpeg_set_quality(&cinfo_compress, quality, TRUE);
410 jpeg_start_compress(&cinfo_compress, TRUE);
411
412 row_stride_dst = image_width * 3;
413
414 image_buffer = new unsigned char[row_stride_dst * cinfo_compress.image_height];
415 memcpy(image_buffer, imageData->pixels, row_stride_dst * cinfo_compress.image_height);
416
417 while (cinfo_compress.next_scanline < cinfo_compress.image_height) {
418 row_pointer[0] = &image_buffer[cinfo_compress.next_scanline * row_stride_dst];
419 jpeg_write_scanlines(&cinfo_compress, row_pointer, 1);
420 }
421
422 jpeg_finish_compress(&cinfo_compress);
423 fclose(outfile);
424 jpeg_destroy_compress(&cinfo_compress);
425
426 if (imageData) {
427 delete imageData;
428 imageData = NULL;
429 }
430
431 if (image_buffer)
432 delete[] image_buffer;
433
434 return 0;
435 }
436
437 int main(int argc, char* argv[])
438 {
439 string strImageName = "data/srcImg/moon.jpg";
440 int flag1 = read_JPEG_file(strImageName);
441 if (flag1 == 0) cout << "read ok!" << endl;
442 else cout << "read error!" << endl;
443
444 strImageName = "2.bmp";
445 int flag2 = write_JPEG_file(strImageName, 80);
446 if (flag2 == 0) cout << "write ok!" << endl;
447 else cout << "write error!" << endl;
448
449 string strSrcImageName = "data/srcImg/moon.jpg";
450 string strDstImageName = "b.jpg";
451 int flag3 = TestImage(strSrcImageName, strDstImageName);
452 if (flag3 == 0) cout << "test ok!" << endl;
453 else cout << "test error!" << endl;
454
455 return 0;
456 }