fz_pixmap * fz_load_jpeg(fz_context *ctx, unsigned char *rbuf, int rlen) { struct jpeg_decompress_struct cinfo; struct jpeg_error_mgr_jmp err; struct jpeg_source_mgr src; unsigned char *row[1], *sp, *dp; fz_colorspace *colorspace; unsigned int x; int k; fz_pixmap *image = NULL; fz_var(image); if (setjmp(err.env)) { /* SumatraPDF: prevent memory leak */ if (image) { fz_drop_pixmap(ctx, image); image = NULL; jpeg_finish_decompress(&cinfo); } jpeg_destroy_decompress(&cinfo); fz_throw(ctx, "jpeg error: %s", err.msg); } cinfo.err = jpeg_std_error(&err.super); err.super.error_exit = error_exit; jpeg_create_decompress(&cinfo); cinfo.src = &src; src.init_source = init_source; src.fill_input_buffer = fill_input_buffer; src.skip_input_data = skip_input_data; src.resync_to_restart = jpeg_resync_to_restart; src.term_source = term_source; src.next_input_byte = rbuf; src.bytes_in_buffer = rlen; jpeg_read_header(&cinfo, 1); jpeg_start_decompress(&cinfo); if (cinfo.output_components == 1) colorspace = fz_device_gray; else if (cinfo.output_components == 3) colorspace = fz_device_rgb; else if (cinfo.output_components == 4) colorspace = fz_device_cmyk; else { /* SumatraPDF: prevent memory leak */ jpeg_finish_decompress(&cinfo); jpeg_destroy_decompress(&cinfo); fz_throw(ctx, "bad number of components in jpeg: %d", cinfo.output_components); } fz_try(ctx) { image = fz_new_pixmap(ctx, colorspace, cinfo.output_width, cinfo.output_height); } fz_catch(ctx) { jpeg_finish_decompress(&cinfo); jpeg_destroy_decompress(&cinfo); fz_throw(ctx, "out of memory"); } if (cinfo.density_unit == 1) { image->xres = cinfo.X_density; image->yres = cinfo.Y_density; } else if (cinfo.density_unit == 2) { image->xres = cinfo.X_density * 254 / 100; image->yres = cinfo.Y_density * 254 / 100; } /* cf. http://code.google.com/p/sumatrapdf/issues/detail?id=1963 */ else if (cinfo.density_unit == 0) { extract_exif_resolution(rbuf, rlen, &image->xres, &image->yres); } if (image->xres <= 0) image->xres = 72; if (image->yres <= 0) image->yres = 72; fz_clear_pixmap(ctx, image); row[0] = fz_malloc(ctx, cinfo.output_components * cinfo.output_width); dp = image->samples; while (cinfo.output_scanline < cinfo.output_height) { jpeg_read_scanlines(&cinfo, row, 1); sp = row[0]; for (x = 0; x < cinfo.output_width; x++) { for (k = 0; k < cinfo.output_components; k++) *dp++ = *sp++; *dp++ = 255; } } fz_free(ctx, row[0]); jpeg_finish_decompress(&cinfo); jpeg_destroy_decompress(&cinfo); image->has_alpha = 0; /* SumatraPDF: allow optimizing non-alpha pixmaps */ return image; }
void fz_load_jpeg_info(fz_context *ctx, unsigned char *rbuf, int rlen, int *xp, int *yp, int *xresp, int *yresp, fz_colorspace **cspacep) { struct jpeg_decompress_struct cinfo; struct jpeg_error_mgr err; struct jpeg_source_mgr src; fz_try(ctx) { cinfo.client_data = ctx; cinfo.err = jpeg_std_error(&err); err.error_exit = error_exit; fz_jpg_mem_init(ctx, &cinfo); jpeg_create_decompress(&cinfo); cinfo.src = &src; src.init_source = init_source; src.fill_input_buffer = fill_input_buffer; src.skip_input_data = skip_input_data; src.resync_to_restart = jpeg_resync_to_restart; src.term_source = term_source; src.next_input_byte = rbuf; src.bytes_in_buffer = rlen; jpeg_save_markers(&cinfo, JPEG_APP0+1, 0xffff); jpeg_save_markers(&cinfo, JPEG_APP0+13, 0xffff); jpeg_read_header(&cinfo, 1); if (cinfo.num_components == 1) *cspacep = fz_device_gray(ctx); else if (cinfo.num_components == 3) *cspacep = fz_device_rgb(ctx); else if (cinfo.num_components == 4) *cspacep = fz_device_cmyk(ctx); else fz_throw(ctx, FZ_ERROR_GENERIC, "bad number of components in jpeg: %d", cinfo.num_components); *xp = cinfo.image_width; *yp = cinfo.image_height; if (extract_exif_resolution(cinfo.marker_list, xresp, yresp)) /* XPS prefers EXIF resolution to JFIF density */; else if (extract_app13_resolution(cinfo.marker_list, xresp, yresp)) /* XPS prefers APP13 resolution to JFIF density */; else if (cinfo.density_unit == 1) { *xresp = cinfo.X_density; *yresp = cinfo.Y_density; } else if (cinfo.density_unit == 2) { *xresp = cinfo.X_density * 254 / 100; *yresp = cinfo.Y_density * 254 / 100; } else { *xresp = 0; *yresp = 0; } if (*xresp <= 0) *xresp = 96; if (*yresp <= 0) *yresp = 96; } fz_always(ctx) { jpeg_destroy_decompress(&cinfo); fz_jpg_mem_term(&cinfo); } fz_catch(ctx) { fz_rethrow(ctx); } }