Updating built in Io code to use += instead of x = x + y
[io/quag.git] / addons / Image / source / JPGImage.c
blob2ab982f8075c4f4dd4523164fe6b9e13cafc0bf1
1 /*
2 docCopyright("Steve Dekorte", 2002)
3 docLicense("BSD revised")
4 */
5 #include "JPGImage.h"
6 #include <jpeglib.h>
8 #include <stdio.h>
9 #include <stdlib.h>
11 #ifndef _WIN32
12 #include <unistd.h>
13 #endif
15 #include <string.h>
17 JPGImage *JPGImage_new(void)
19 JPGImage *self = (JPGImage *)calloc(1, sizeof(JPGImage));
20 JPGImage_path_(self, "");
21 JPGImage_error_(self, "");
22 self->byteArray = UArray_new();
23 self->ownsUArray = 1;
24 self->quality = 0.5; /* default to meduim quality */
25 self->decodingWidthHint = 0;
26 self->decodingHeightHint = 0;
27 return self;
30 JPGImage *JPGImage_newWithPath_(char *path)
32 JPGImage *self = JPGImage_new();
33 JPGImage_path_(self, path);
34 JPGImage_load(self);
35 return self;
38 void JPGImage_free(JPGImage *self)
40 if (self->ownsUArray) UArray_free(self->byteArray);
41 if (self->error) free(self->error);
42 free(self->path);
43 free(self);
46 void JPGImage_path_(JPGImage *self, const char *path)
48 self->path = strcpy((char *)realloc(self->path, strlen(path)+1), path);
51 char *JPGImage_path(JPGImage *self)
53 return self->path;
56 void JPGImage_quality_(JPGImage *self, float q)
58 if (q<0) q = 0;
59 if (q>1) q = 1;
60 self->quality = q;
63 float JPGImage_quality(JPGImage *self)
65 return self->quality;
68 void JPGImage_decodingWidthHint_(JPGImage *self, int w)
70 self->decodingWidthHint = w;
73 int JPGImage_decodingWidthHint(JPGImage *self)
75 return self->decodingWidthHint;
78 void JPGImage_decodingHeightHint_(JPGImage *self, int h)
80 self->decodingHeightHint = h;
83 int JPGImage_decodingHeightHint(JPGImage *self)
85 return self->decodingHeightHint;
88 void JPGImage_error_(JPGImage *self, const char *error)
90 self->error = strcpy((char *)realloc(self->error, strlen(error)+1), error);
91 /*if (strlen(self->error)) printf("JPGImage error: %s\n", self->error);*/
94 char *JPGImage_error(JPGImage *self)
96 return self->error;
99 char JPGImage_isProgressive(JPGImage *self)
101 FILE *infile;
102 struct jpeg_decompress_struct cinfo;
103 struct jpeg_error_mgr jerr;
105 cinfo.err = jpeg_std_error(&jerr);
106 jpeg_create_decompress(&cinfo);
108 if ((infile = fopen(self->path, "rb")) == NULL)
110 JPGImage_error_(self, "can't open file");
111 return 0;
114 jpeg_stdio_src(&cinfo, infile);
116 //jpeg_read_header(&cinfo, TRUE); // this causes an exit on a bad image
117 jpeg_read_header(&cinfo, FALSE);
118 return jpeg_has_multiple_scans(&cinfo);
121 void JPGImage_readScanLines(JPGImage *self, struct jpeg_decompress_struct *cinfo);
124 struct MY_jpeg_error_mgr *jpeg_std_error(struct jpeg_error_mgr * err)
126 err->error_exit = error_exit;
127 err->emit_message = emit_message;
128 err->output_message = output_message;
129 err->format_message = format_message;
130 err->reset_error_mgr = reset_error_mgr;
132 err->trace_level = 0; // default = no tracing
133 err->num_warnings = 0; // no warnings emitted yet
134 err->msg_code = 0; // may be useful as a flag for "no error"
136 // Initialize message table pointers
137 err->jpeg_message_table = jpeg_std_message_table;
138 err->last_jpeg_message = (int) JMSG_LASTMSGCODE - 1;
140 err->addon_message_table = NULL;
141 err->first_addon_message = 0; // for safety
142 err->last_addon_message = 0;
144 return err;
148 #include <setjmp.h>
150 static jmp_buf env;
152 void MY_error_exit(j_common_ptr cinfo)
154 (*cinfo->err->output_message) (cinfo);
155 jpeg_destroy(cinfo);
156 //exit(EXIT_FAILURE);
157 printf("longjmp\n");
158 longjmp(env, 1);
161 void JPGImage_load(JPGImage *self)
163 FILE *infile;
165 /* 1. setup error structure */
166 struct jpeg_decompress_struct cinfo;
167 struct jpeg_error_mgr jerr;
169 if(setjmp(env) == 1)
171 printf("longjmped\n");
172 JPGImage_error_(self, "jpeg decoding error");
173 return;
177 cinfo.err = jpeg_std_error(&jerr);
178 jerr.error_exit = MY_error_exit;
180 jpeg_create_decompress(&cinfo);
183 /* 2. input file */
184 if ((infile = fopen(self->path, "r")) == NULL)
186 JPGImage_error_(self, "can't open file");
187 return;
190 jpeg_stdio_src(&cinfo, infile);
192 /* 3. Call jpeg_read_header() to obtain image info. */
193 //jpeg_read_header(&cinfo, TRUE); // this causes an exit on a bad image
194 jpeg_read_header(&cinfo, FALSE);
196 if (jpeg_has_multiple_scans(&cinfo) &&
197 (self->decodingWidthHint || self->decodingHeightHint) ) /* progressive thumbnail */
199 int wr = 0;
200 int hr = 0;
201 int s = 0;
202 if (self->decodingWidthHint) wr = cinfo.image_width/self->decodingWidthHint;
203 if (self->decodingHeightHint) hr = cinfo.image_height/self->decodingHeightHint;
204 if (wr && hr) { s = wr < hr ? wr : hr; } else /* take the small so no dimension is smaller than the min */
205 if (wr) { s = wr; } else if (hr) { s = hr; }
206 /* valid scales are 1/1 1/2 1/4 and 1/8 */
207 if (s <= 1) { s = 1; } else
208 if (s <= 2) { s = 2; } else
209 if (s <= 4) { s = 4; } else { s = 8; }
211 cinfo.scale_num = 1;
212 cinfo.scale_denom = s;
214 /*printf("JPEG is Progressive\n");*/
215 cinfo.buffered_image = TRUE; /* select buffered-image mode so we can handle progressive jpegs */
216 jpeg_start_decompress(&cinfo);
217 while (!jpeg_input_complete(&cinfo))
219 /*printf("reading progressive pass %i\n", cinfo.input_scan_number); */
220 /* adjust output decompression parameters if required */
221 cinfo.do_block_smoothing = 0;
222 jpeg_start_output(&cinfo, cinfo.input_scan_number);
223 JPGImage_readScanLines(self, &cinfo);
224 /* display scanlines */
225 jpeg_finish_output(&cinfo); /* terminate output pass */
226 if (cinfo.scale_denom != 1) break; /* hack - just break since we don't know the pass resolution */
229 else /* non-progressive */
231 jpeg_start_decompress(&cinfo);
232 /*printf("JPEG is NOT progressive\n");*/
233 JPGImage_readScanLines(self, &cinfo);
236 /* Finish decompression and release memory.
237 * I must do it in this order because output module has allocated memory
238 * of lifespan JPOOL_IMAGE; it needs to finish before releasing memory.
240 jpeg_finish_decompress(&cinfo);
241 jpeg_destroy_decompress(&cinfo);
243 /* Close files, if we opened them */
244 if (infile != stdin) fclose(infile);
247 void JPGImage_readScanLines(JPGImage *self, struct jpeg_decompress_struct *cinfo)
249 self->width = cinfo->output_width;
250 self->height = cinfo->output_height;
251 self->components = cinfo->out_color_components;
252 /*printf("JPGImage_readScanLines %i x %i x %i\n", self->width, self->height, self->components);*/
255 int numbytes = cinfo->output_height * cinfo->output_width * cinfo->out_color_components;
256 UArray_setSize_(self->byteArray, numbytes);
259 /* 6. while (scan lines remain to be read) */
261 unsigned char **rows = malloc(cinfo->output_height * sizeof(unsigned char *));
262 int r;
263 for (r=0; r < (int)cinfo->output_height; r++)
265 rows[r] = (uint8_t *)UArray_bytes(self->byteArray) + (r * cinfo->output_width * cinfo->out_color_components);
268 while (cinfo->output_scanline < cinfo->output_height)
270 jpeg_read_scanlines(cinfo, rows + cinfo->output_scanline, cinfo->output_height);
273 free(rows);
277 void JPGImage_save(JPGImage *self)
279 struct jpeg_compress_struct cinfo;
280 struct jpeg_error_mgr jerr;
282 FILE *outfile; /* target file */
283 JSAMPROW row_pointer[1]; /* pointer to JSAMPLE row[s] */
284 int row_stride; /* physical row width in image buffer */
286 /* Step 1: allocate and initialize JPEG compression object */
288 cinfo.err = jpeg_std_error(&jerr);
289 jpeg_create_compress(&cinfo);
291 /* Step 2: specify data destination (eg, a file) */
292 /* Note: steps 2 and 3 can be done in either order. */
294 /* Here we use the library-supplied code to send compressed data to a
295 * stdio stream. You can also write your own code to do something else.
296 * VERY IMPORTANT: use "b" option to fopen() if you are on a machine that
297 * requires it in order to write binary files.
299 if ((outfile = fopen(self->path, "wb")) == NULL)
301 JPGImage_error_(self, "can't open output file");
302 return;
304 jpeg_stdio_dest(&cinfo, outfile);
306 /* Step 3: set parameters for compression */
308 /* First we supply a description of the input image.
309 * Four fields of the cinfo struct must be filled in:
311 cinfo.image_width = self->width; /* image width and height, in pixels */
312 cinfo.image_height = self->height;
313 cinfo.input_components = self->components; /* # of color components per pixel */
314 cinfo.in_color_space = JCS_RGB; /* colorspace of input image */
315 /* Now use the library's routine to set default compression parameters.
316 * (You must set at least cinfo.in_color_space before calling this,
317 * since the defaults depend on the source color space.)
321 jpeg_set_defaults(&cinfo);
322 /* Now you can set any non-default parameters you wish to.
323 * Here we just illustrate the use of quality (quantization table) scaling:
326 jpeg_simple_progression(&cinfo); /* is this the right spot for this? */
329 jpeg_set_quality(&cinfo, JPGImage_quality(self)*100, TRUE); /* limit to baseline-JPEG values */
331 /* Step 4: Start compressor */
333 /* TRUE ensures that we will write a complete interchange-JPEG file.
334 * Pass TRUE unless you are very sure of what you're doing.
336 jpeg_start_compress(&cinfo, TRUE);
338 /* Step 5: while (scan lines remain to be written) */
339 /* jpeg_write_scanlines(...); */
341 /* Here we use the library's state variable cinfo.next_scanline as the
342 * loop counter, so that we don't have to keep track ourselves.
343 * To keep things simple, we pass one scanline per call; you can pass
344 * more if you wish, though.
346 row_stride = self->width * 3; /* JSAMPLEs per row in image_buffer */
348 while (cinfo.next_scanline < cinfo.image_height) {
349 /* jpeg_write_scanlines expects an array of pointers to scanlines.
350 * Here the array is only one element long, but you could pass
351 * more than one scanline at a time if that's more convenient.
353 row_pointer[0] = ((uint8_t *)UArray_bytes(self->byteArray) + (cinfo.next_scanline * row_stride));
354 (void) jpeg_write_scanlines(&cinfo, row_pointer, 1);
357 /* Step 6: Finish compression */
359 jpeg_finish_compress(&cinfo);
360 /* After finish_compress, we can close the output file. */
361 fclose(outfile);
363 /* Step 7: release JPEG compression object */
365 /* This is an important step since it will release a good deal of memory. */
366 jpeg_destroy_compress(&cinfo);
370 void JPGImage_setBuffer_length_(JPGImage *self, void *data, int size)
371 { self->data = png_create( self->width, self->height, self->format); }
374 int JPGImage_width(JPGImage *self)
376 return self->width;
379 int JPGImage_height(JPGImage *self)
381 return self->height;
384 void JPGImage_width_(JPGImage *self, int w)
386 self->width = w;
389 void JPGImage_height_(JPGImage *self, int h)
391 self->height = h;
394 void JPGImage_components_(JPGImage *self, int c)
396 self->components = c;
399 unsigned char JPGImage_isL8(JPGImage *self)
401 return (self->components == 1); /* LUMINANCE */
404 unsigned char JPGImage_isLA8(JPGImage *self)
406 return (self->components == 2); /* LUMINANCE, ALPHA */
409 unsigned char JPGImage_isRGB8(JPGImage *self)
411 return (self->components == 3); /* RGB */
414 unsigned char JPGImage_isRGBA8(JPGImage *self)
416 return (self->components == 4); /* RGBA */
419 int JPGImage_components(JPGImage *self)
421 return self->components;
424 int JPGImage_sizeInBytes(JPGImage *self)
426 return self->height * self->width * self->components;
429 void *JPGImage_data(JPGImage *self)
431 return (uint8_t *)UArray_bytes(self->byteArray);
434 UArray *JPGImage_byteArray(JPGImage *self)
436 return self->byteArray;
439 void JPGImage_setExternalUArray_(JPGImage *self, UArray *ba)
441 if (self->ownsUArray)
443 UArray_free(self->byteArray);
445 self->byteArray = ba;
446 self->ownsUArray = 0;