2 docCopyright("Steve Dekorte", 2002)
3 docLicense("BSD revised")
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();
24 self
->quality
= 0.5; /* default to meduim quality */
25 self
->decodingWidthHint
= 0;
26 self
->decodingHeightHint
= 0;
30 JPGImage
*JPGImage_newWithPath_(char *path
)
32 JPGImage
*self
= JPGImage_new();
33 JPGImage_path_(self
, path
);
38 void JPGImage_free(JPGImage
*self
)
40 if (self
->ownsUArray
) UArray_free(self
->byteArray
);
41 if (self
->error
) free(self
->error
);
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
)
56 void JPGImage_quality_(JPGImage
*self
, float q
)
63 float JPGImage_quality(JPGImage
*self
)
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
)
99 char JPGImage_isProgressive(JPGImage
*self
)
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");
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;
152 void MY_error_exit(j_common_ptr cinfo
)
154 (*cinfo
->err
->output_message
) (cinfo
);
156 //exit(EXIT_FAILURE);
161 void JPGImage_load(JPGImage
*self
)
165 /* 1. setup error structure */
166 struct jpeg_decompress_struct cinfo
;
167 struct jpeg_error_mgr jerr
;
171 printf("longjmped\n");
172 JPGImage_error_(self
, "jpeg decoding error");
177 cinfo
.err
= jpeg_std_error(&jerr
);
178 jerr
.error_exit
= MY_error_exit
;
180 jpeg_create_decompress(&cinfo
);
184 if ((infile
= fopen(self
->path
, "r")) == NULL
)
186 JPGImage_error_(self
, "can't open file");
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 */
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; }
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 *));
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
);
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");
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. */
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
)
379 int JPGImage_height(JPGImage
*self
)
384 void JPGImage_width_(JPGImage
*self
, int w
)
389 void JPGImage_height_(JPGImage
*self
, int 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;