Coin Logo Coin3D is Free Software,
published under the BSD 3-clause license.
https://coin3d.github.io
https://www.kongsberg.com/en/kogt/
simage_jpeg.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) Kongsberg Oil & Gas Technologies
3  *
4  * Permission to use, copy, modify, and distribute this software for any
5  * purpose with or without fee is hereby granted, provided that the above
6  * copyright notice and this permission notice appear in all copies.
7  *
8  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15  */
16 
17 /*
18  * Based on example code found in the libjpeg archive
19  *
20  */
21 
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif /* HAVE_CONFIG_H */
25 
26 #ifdef HAVE_JPEGLIB
27 
28 #include <stdio.h>
29 #include <setjmp.h>
30 #include <string.h>
31 #include <stdlib.h>
32 
33 /* This define is also used in the public jpeglib headers. Ugh.*/
34 #undef HAVE_STDLIB_H
35 
36 
37 /* The geniuses that made the libjpeg forgot to add this wrapper
38  around the header file. */
39 #ifdef __cplusplus
40 extern "C" {
41 #endif /* __cplusplus */
42 #include <jpeglib.h>
43 #ifdef __cplusplus
44 }
45 #endif
46 
47 #include "simage_jpeg_reader.icc"
48 #include "simage_jpeg_writer.icc"
49 
50 
51 #define ERR_NO_ERROR 0
52 #define ERR_OPEN 1
53 #define ERR_MEM 2
54 #define ERR_JPEGLIB 3
55 #define ERR_OPEN_WRITE 4
56 #define ERR_JPEGLIB_WRITE 5
57 
58 static int jpegerror = ERR_NO_ERROR;
59 
60 int
61 simage_jpeg_error(char * buffer, int buflen)
62 {
63  switch (jpegerror) {
64  case ERR_OPEN:
65  strncpy(buffer, "JPEG loader: Error opening file", buflen);
66  break;
67  case ERR_MEM:
68  strncpy(buffer, "JPEG loader: Out of memory error", buflen);
69  break;
70  case ERR_JPEGLIB:
71  strncpy(buffer, "JPEG loader: Illegal jpeg file", buflen);
72  break;
73  case ERR_OPEN_WRITE:
74  strncpy(buffer, "JPEG saver: Error opening file", buflen);
75  break;
76  case ERR_JPEGLIB_WRITE:
77  strncpy(buffer, "JPEG saver: Internal libjpeg error", buflen);
78  break;
79  }
80  return jpegerror;
81 }
82 
83 struct my_error_mgr {
84  struct jpeg_error_mgr pub; /* "public" fields */
85 
86  jmp_buf setjmp_buffer; /* for return to caller */
87 };
88 
89 
90 typedef struct my_error_mgr * my_error_ptr;
91 
92 static void
93 my_error_exit (j_common_ptr cinfo)
94 {
95  /* cinfo->err really points to a my_error_mgr struct, so coerce pointer */
96  my_error_ptr myerr = (my_error_ptr) cinfo->err;
97 
98  /* Always display the message. */
99  /* We could postpone this until after returning, if we chose. */
100  /*(*cinfo->err->output_message) (cinfo);*/
101 
102  /* FIXME: get error messahe from jpeglib */
103 
104  /* Return control to the setjmp point */
105  longjmp(myerr->setjmp_buffer, 1);
106 }
107 
108 int
109 simage_jpeg_identify(const char * ptr,
110  const unsigned char *header,
111  int headerlen)
112 {
113  static unsigned char jpgcmp[] = {'J', 'F', 'I', 'F' };
114  static unsigned char jpgcmp2[] = {'E', 'x', 'i', 'f' };
115  if (headerlen < 10) return 0;
116  if (memcmp((const void*)&header[6],
117  (const void*)jpgcmp, 4) == 0) return 1;
118  if (memcmp((const void*)&header[6],
119  (const void*)jpgcmp2, 4) == 0) return 1;
120  return 0;
121 }
122 
123 
124 static unsigned char*
125 copyScanline(unsigned char *currPtr, unsigned char *from, int cnt)
126 {
127  memcpy((void*)currPtr, (void*)from, cnt);
128  currPtr -= cnt;
129  return currPtr;
130 }
131 
132 unsigned char *
133 simage_jpeg_load(const char *filename,
134  int *width_ret,
135  int *height_ret,
136  int *numComponents_ret)
137 {
138  int width;
139  int height;
140  unsigned char *currPtr;
141  int format;
142  unsigned char *buffer;
143  /* This struct contains the JPEG decompression parameters and pointers to
144  * working space (which is allocated as needed by the JPEG library).
145  */
146  struct jpeg_decompress_struct cinfo;
147  /* We use our private extension JPEG error handler.
148  * Note that this struct must live as long as the main JPEG parameter
149  * struct, to avoid dangling-pointer problems.
150  */
151  struct my_error_mgr jerr;
152  /* More stuff */
153  FILE * infile; /* source file */
154  JSAMPARRAY rowbuffer; /* Output row buffer */
155  int row_stride; /* physical row width in output buffer */
156 
157  jpegerror = ERR_NO_ERROR;
158 
159  /* In this example we want to open the input file before doing anything else,
160  * so that the setjmp() error recovery below can assume the file is open.
161  * VERY IMPORTANT: use "b" option to fopen() if you are on a machine that
162  * requires it in order to read binary files.
163  */
164 
165  if ((infile = fopen(filename, "rb")) == NULL) {
166  jpegerror = ERR_OPEN;
167  return NULL;
168  }
169 
170  /* Step 1: allocate and initialize JPEG decompression object */
171 
172  buffer = NULL;
173 
174  /* We set up the normal JPEG error routines, then override error_exit. */
175  cinfo.err = jpeg_std_error(&jerr.pub);
176  jerr.pub.error_exit = my_error_exit;
177  /* Establish the setjmp return context for my_error_exit to use. */
178  if (setjmp(jerr.setjmp_buffer)) {
179  /* If we get here, the JPEG code has signaled an error.
180  * We need to clean up the JPEG object, close the input file, and return.
181  */
182  jpegerror = ERR_JPEGLIB;
183  jpeg_destroy_decompress(&cinfo);
184  fclose(infile);
185  if (buffer) free(buffer);
186  return NULL;
187  }
188  /* Now we can initialize the JPEG decompression object. */
189  jpeg_create_decompress(&cinfo);
190 
191  /* Step 2: specify data source */
192 
193  simage_jpeg_src_init(&cinfo, infile);
194 
195  /* Step 3: read file parameters with jpeg_read_header() */
196 
197  (void) jpeg_read_header(&cinfo, TRUE);
198  /* We can ignore the return value from jpeg_read_header since
199  * (a) suspension is not possible with the stdio data source, and
200  * (b) we passed TRUE to reject a tables-only JPEG file as an error.
201  * See libjpeg.doc for more info.
202  */
203 
204  /* Step 4: set parameters for decompression */
205  /* In this example, we don't need to change any of the defaults set by
206  * jpeg_read_header(), so we do nothing here.
207  */
208 
209  /* Step 5: Start decompressor */
210  if (cinfo.jpeg_color_space == JCS_GRAYSCALE) {
211  format = 1;
212  cinfo.out_color_space = JCS_GRAYSCALE;
213  }
214  else { /* use rgb */
215  format = 3;
216  cinfo.out_color_space = JCS_RGB;
217  }
218 
219  (void) jpeg_start_decompress(&cinfo);
220  /* We can ignore the return value since suspension is not possible
221  * with the stdio data source.
222  */
223 
224  /* We may need to do some setup of our own at this point before reading
225  * the data. After jpeg_start_decompress() we have the correct scaled
226  * output image dimensions available, as well as the output colormap
227  * if we asked for color quantization.
228  * In this example, we need to make an output work buffer of the right size.
229  */
230  /* JSAMPLEs per row in output buffer */
231  row_stride = cinfo.output_width * cinfo.output_components;
232  /* Make a one-row-high sample array that will go away when done with image */
233  rowbuffer = (*cinfo.mem->alloc_sarray)
234  ((j_common_ptr) &cinfo, JPOOL_IMAGE, row_stride, 1);
235  width = cinfo.output_width;
236  height = cinfo.output_height;
237  buffer = currPtr = (unsigned char*)
238  malloc((size_t)width*height*cinfo.output_components);
239 
240  /* Step 6: while (scan lines remain to be read) */
241  /* jpeg_read_scanlines(...); */
242 
243  /* Here we use the library's state variable cinfo.output_scanline as the
244  * loop counter, so that we don't have to keep track ourselves.
245  */
246 
247  /* flip image upside down */
248  if (buffer) {
249  currPtr = buffer + row_stride * (cinfo.output_height-1);
250 
251  while (cinfo.output_scanline < cinfo.output_height) {
252  /* jpeg_read_scanlines expects an array of pointers to scanlines.
253  * Here the array is only one element long, but you could ask for
254  * more than one scanline at a time if that's more convenient.
255  */
256  (void) jpeg_read_scanlines(&cinfo, rowbuffer, 1);
257  /* Assume put_scanline_someplace wants a pointer and sample count. */
258  currPtr = copyScanline(currPtr, rowbuffer[0], row_stride);
259  }
260  }
261  /* Step 7: Finish decompression */
262 
263  (void) jpeg_finish_decompress(&cinfo);
264  /* We can ignore the return value since suspension is not possible
265  * with the stdio data source.
266  */
267 
268  /* Step 8: Release JPEG decompression object */
269 
270  /* This is an important step since it will release a good deal of memory. */
271  jpeg_destroy_decompress(&cinfo);
272 
273  /* After finish_decompress, we can close the input file.
274  * Here we postpone it until after no more JPEG errors are possible,
275  * so as to simplify the setjmp error logic above. (Actually, I don't
276  * think that jpeg_destroy can do an error exit, but why assume anything...)
277  */
278  fclose(infile);
279 
280  /* At this point you may want to check to see whether any corrupt-data
281  * warnings occurred (test whether jerr.pub.num_warnings is nonzero).
282  */
283 
284  /* And we're done! */
285  if (buffer) {
286  *width_ret = width;
287  *height_ret = height;
288  *numComponents_ret = format;
289  }
290  else {
291  jpegerror = ERR_MEM;
292  }
293  return buffer;
294 }
295 
296 int
297 simage_jpeg_save(const char * filename,
298  const unsigned char * bytes,
299  int width,
300  int height,
301  int numcomponents)
302 {
303  /* This struct contains the JPEG compression parameters and pointers to
304  * working space (which is allocated as needed by the JPEG library).
305  * It is possible to have several such structures, representing multiple
306  * compression/decompression processes, in existence at once. We refer
307  * to any one struct (and its associated working data) as a "JPEG object".
308  */
309  struct jpeg_compress_struct cinfo;
310 
311  /* We use our private extension JPEG error handler.
312  * Note that this struct must live as long as the main JPEG parameter
313  * struct, to avoid dangling-pointer problems.
314  */
315  struct my_error_mgr jerr;
316 
317  /* More stuff */
318  FILE * outfile; /* target file */
319  JSAMPROW row_pointer[1]; /* pointer to JSAMPLE row[s] */
320 
321  int quality;
322  unsigned char * tmpbytes;
323  int bytesperrow;
324 
325  quality = 90;
326  tmpbytes = NULL;
327 
328  /* Step 1: allocate and initialize JPEG compression object */
329 
330  /* We have to set up the error handler first, in case the initialization
331  * step fails. (Unlikely, but it could happen if you are out of memory.)
332  * This routine fills in the contents of struct jerr, and returns jerr's
333  * address which we place into the link field in cinfo.
334  */
335  cinfo.err = jpeg_std_error(&jerr.pub);
336  /* Now we can initialize the JPEG compression object. */
337  jpeg_create_compress(&cinfo);
338 
339  /* Step 2: specify data destination (eg, a file) */
340  /* Note: steps 2 and 3 can be done in either order. */
341 
342  /* Here we use the library-supplied code to send compressed data to a
343  * stdio stream. You can also write your own code to do something else.
344  * VERY IMPORTANT: use "b" option to fopen() if you are on a machine that
345  * requires it in order to write binary files.
346  */
347 
348  if ((outfile = fopen(filename, "wb")) == NULL) {
349  /* FIXME: should store error message somewhere for the client app
350  to read. 20020820 mortene. */
351  /*fprintf(stderr, "can't open %s for writing\n", filename);*/
352  jpeg_destroy_compress(&cinfo);
353  jpegerror = ERR_OPEN_WRITE;
354  return 0;
355  }
356 
357  /* We set up the normal JPEG error routines, then override error_exit. */
358  cinfo.err = jpeg_std_error(&jerr.pub);
359  jerr.pub.error_exit = my_error_exit;
360  /* Establish the setjmp return context for my_error_exit to use. */
361  if (setjmp(jerr.setjmp_buffer)) {
362  /* If we get here, the JPEG code has signaled an error.
363  * We need to clean up the JPEG object, close the input file, and return.
364  */
365  jpeg_destroy_compress(&cinfo);
366  fclose(outfile);
367  if (tmpbytes) free(tmpbytes);
368  jpegerror = ERR_JPEGLIB_WRITE;
369  return 0;
370  }
371 
372  simage_jpeg_dest_init(&cinfo, outfile);
373 
374 
375  /*
376  * alpha channel is not supported for jpeg. strip it.
377  */
378 
379  if (numcomponents == 4) {
380  unsigned char * dst;
381  const unsigned char * src;
382  int i, n = width * height;
383  dst = tmpbytes = (unsigned char *) malloc(n*3);
384  src = bytes;
385  for (i = 0; i < n; i++) {
386  *dst++ = *src++;
387  *dst++ = *src++;
388  *dst++ = *src++;
389  src++;
390  }
391  numcomponents = 3;
392  }
393  else if (numcomponents == 2) {
394  unsigned char * dst;
395  const unsigned char * src;
396  int i, n = width * height;
397  dst = tmpbytes = (unsigned char *) malloc(n*3);
398  src = bytes;
399  for (i = 0; i < n; i++) {
400  *dst++ = *src++;
401  src++;
402  }
403  numcomponents = 1;
404  }
405 
406  /* Step 3: set parameters for compression */
407 
408  /* First we supply a description of the input image.
409  * Four fields of the cinfo struct must be filled in:
410  */
411 
412  cinfo.image_width = width; /* image width and height, in pixels */
413  cinfo.image_height = height;
414  cinfo.input_components = numcomponents; /* # of color components per pixel */
415  cinfo.in_color_space = numcomponents == 3 ? JCS_RGB : JCS_GRAYSCALE; /* colorspace of input image */
416  /* Now use the library's routine to set default compression parameters.
417  * (You must set at least cinfo.in_color_space before calling this,
418  * since the defaults depend on the source color space.)
419  */
420  jpeg_set_defaults(&cinfo);
421  /* Now you can set any non-default parameters you wish to.
422  * Here we just illustrate the use of quality (quantization table) scaling:
423  */
424  jpeg_set_quality(&cinfo, quality, TRUE /* limit to baseline-JPEG values */);
425 
426  /* Step 4: Start compressor */
427 
428  /* TRUE ensures that we will write a complete interchange-JPEG file.
429  * Pass TRUE unless you are very sure of what you're doing.
430  */
431  jpeg_start_compress(&cinfo, TRUE);
432 
433  /* Step 5: while (scan lines remain to be written) */
434  /* jpeg_write_scanlines(...); */
435 
436  /* Here we use the library's state variable cinfo.next_scanline as the
437  * loop counter, so that we don't have to keep track ourselves.
438  * To keep things simple, we pass one scanline per call; you can pass
439  * more if you wish, though.
440  */
441 
442  bytesperrow = width * numcomponents;
443  if (tmpbytes) bytes = tmpbytes; /* more convenient */
444 
445  while (cinfo.next_scanline < cinfo.image_height) {
446  /* jpeg_write_scanlines expects an array of pointers to scanlines.
447  * Here the array is only one element long, but you could pass
448  * more than one scanline at a time if that's more convenient.
449  */
450  row_pointer[0] = (JSAMPROW) bytes + bytesperrow * (height-cinfo.next_scanline-1);
451  (void) jpeg_write_scanlines(&cinfo, row_pointer, 1);
452  }
453  if (tmpbytes) free(tmpbytes);
454 
455  /* Step 6: Finish compression */
456 
457  jpeg_finish_compress(&cinfo);
458 
459  /* Step 7: release JPEG compression object */
460 
461  /* This is an important step since it will release a good deal of memory. */
462  jpeg_destroy_compress(&cinfo);
463 
464  /* After finish_compress, we can close the output file. */
465  fclose(outfile);
466 
467  /* And we're done! */
468  return 1;
469 }
470 
471 #endif /* HAVE_JPEGLIB */
int simage_jpeg_identify(const char *filename, const unsigned char *header, int headerlen)
#define ERR_OPEN
#define ERR_MEM
#define ERR_NO_ERROR
int simage_jpeg_save(const char *filename, const unsigned char *bytes, int width, int height, int numcomponents)
int simage_jpeg_error(char *textbuffer, int buffersize)
unsigned char * simage_jpeg_load(const char *filename, int *width, int *height, int *numcomponents)