diff options
Diffstat (limited to 'source/fitz')
-rw-r--r-- | source/fitz/load-bmp.c | 18 | ||||
-rw-r--r-- | source/fitz/load-jpeg.c | 113 |
2 files changed, 128 insertions, 3 deletions
diff --git a/source/fitz/load-bmp.c b/source/fitz/load-bmp.c index e3ba67f5..cb314587 100644 --- a/source/fitz/load-bmp.c +++ b/source/fitz/load-bmp.c @@ -67,6 +67,7 @@ enum { BI_RLE8 = 1, BI_RLE4 = 2, BI_BITFIELDS = 3, + BI_JPEG = 4, }; struct info @@ -725,7 +726,8 @@ bmp_read_image(fz_context *ctx, struct info *info, unsigned char *p, int total, fz_throw(ctx, FZ_ERROR_GENERIC, "dimensions (%d x %d) out of range in bmp image", info->width, info->height); if (info->compression != BI_RGB && info->compression != BI_RLE8 && - info->compression != BI_RLE4 && info->compression != BI_BITFIELDS) + info->compression != BI_RLE4 && info->compression != BI_BITFIELDS && + info->compression != BI_JPEG) fz_throw(ctx, FZ_ERROR_GENERIC, "unsupported compression method (%d) in bmp image", info->compression); if ((info->compression == BI_RGB && info->bitcount != 1 && info->bitcount != 2 && info->bitcount != 4 && @@ -733,7 +735,8 @@ bmp_read_image(fz_context *ctx, struct info *info, unsigned char *p, int total, info->bitcount != 24 && info->bitcount != 32) || (info->compression == BI_RLE8 && info->bitcount != 8) || (info->compression == BI_RLE4 && info->bitcount != 4) || - (info->compression == BI_BITFIELDS && info->bitcount != 16 && info->bitcount != 32)) + (info->compression == BI_BITFIELDS && info->bitcount != 16 && info->bitcount != 32) || + (info->compression == BI_JPEG && info->bitcount != 0)) fz_throw(ctx, FZ_ERROR_GENERIC, "invalid bits per pixel (%d) for compression (%d) in bmp image", info->bitcount, info->compression); if (info->rbits > 0 && info->rbits != 4 && info->rbits != 5 && info->rbits != 8) @@ -743,7 +746,16 @@ bmp_read_image(fz_context *ctx, struct info *info, unsigned char *p, int total, if (info->bbits > 0 && info->bbits != 4 && info->bbits != 5 && info->bbits != 8) fz_throw(ctx, FZ_ERROR_GENERIC, "unsupported %d bit blue mask in bmp image", info->bbits); - if (!only_metadata) + if (only_metadata) + return NULL; + + if (info->compression == BI_JPEG) + { + if (p - begin < info->offset) + p = begin + info->offset; + return fz_load_jpeg(ctx, p, end - p); + } + else { p = bmp_read_color_table(ctx, info, p, begin + info->offset); if (p - begin < info->offset) diff --git a/source/fitz/load-jpeg.c b/source/fitz/load-jpeg.c index 2640a8a4..29db9bcf 100644 --- a/source/fitz/load-jpeg.c +++ b/source/fitz/load-jpeg.c @@ -214,6 +214,119 @@ static int extract_app13_resolution(jpeg_saved_marker_ptr marker, int *xres, int return 0; } +fz_pixmap * +fz_load_jpeg(fz_context *ctx, unsigned char *rbuf, int rlen) +{ + struct jpeg_decompress_struct cinfo; + struct jpeg_error_mgr 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); + fz_var(row); + + row[0] = NULL; + + 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); + + jpeg_start_decompress(&cinfo); + + if (cinfo.output_components == 1) + colorspace = fz_device_gray(ctx); + else if (cinfo.output_components == 3) + colorspace = fz_device_rgb(ctx); + else if (cinfo.output_components == 4) + colorspace = fz_device_cmyk(ctx); + else + fz_throw(ctx, FZ_ERROR_GENERIC, "bad number of components in jpeg: %d", cinfo.num_components); + + image = fz_new_pixmap(ctx, colorspace, cinfo.output_width, cinfo.output_height); + + if (extract_exif_resolution(cinfo.marker_list, &image->xres, &image->yres)) + /* XPS prefers EXIF resolution to JFIF density */; + else if (extract_app13_resolution(cinfo.marker_list, &image->xres, &image->yres)) + /* XPS prefers APP13 resolution to JFIF density */; + else 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; + } + + if (image->xres <= 0) image->xres = 96; + if (image->yres <= 0) image->yres = 96; + + 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_always(ctx) + { + fz_free(ctx, row[0]); + row[0] = NULL; + fz_try(ctx) + { + /* Annoyingly, jpeg_finish_decompress can throw */ + jpeg_finish_decompress(&cinfo); + } + fz_catch(ctx) + { + /* Ignore any errors here */ + } + jpeg_destroy_decompress(&cinfo); + fz_jpg_mem_term(&cinfo); + } + fz_catch(ctx) + { + fz_drop_pixmap(ctx, image); + fz_rethrow(ctx); + } + + 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) { |