summaryrefslogtreecommitdiff
path: root/source
diff options
context:
space:
mode:
authorSebastian Rasmussen <sebras@gmail.com>2016-03-28 12:58:43 +0200
committerRobin Watts <robin.watts@artifex.com>2016-03-29 13:06:27 +0100
commit79959f7bcc6b3c8a6bea2e310fc076600de8d256 (patch)
tree0fcdc4ede83fee3dfa943806e7c2ad0e41229534 /source
parent02883863ef37e81087b08949cf7ef6de53591100 (diff)
downloadmupdf-79959f7bcc6b3c8a6bea2e310fc076600de8d256.tar.xz
bmp: Add support for embedded JPEG images.
Reintroduce fz_load_jpeg() (previously removed in 12c1466) improved with: * application agnostic memory handler support from 6a8abce * colorspace context from 93bd1ff * resolution detection from 4dc6cbe
Diffstat (limited to 'source')
-rw-r--r--source/fitz/load-bmp.c18
-rw-r--r--source/fitz/load-jpeg.c113
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)
{