diff options
-rw-r--r-- | Build/source/texk/dvipdfm-x/ChangeLog | 4 | ||||
-rw-r--r-- | Build/source/texk/dvipdfm-x/jp2image.c | 100 | ||||
-rw-r--r-- | Build/source/texk/dvipdfm-x/jpegimage.c | 742 | ||||
-rw-r--r-- | Build/source/texk/dvipdfm-x/pdfcolor.c | 8 |
4 files changed, 487 insertions, 367 deletions
diff --git a/Build/source/texk/dvipdfm-x/ChangeLog b/Build/source/texk/dvipdfm-x/ChangeLog index 5bfe0d88a94..536367742cd 100644 --- a/Build/source/texk/dvipdfm-x/ChangeLog +++ b/Build/source/texk/dvipdfm-x/ChangeLog @@ -2,6 +2,10 @@ * pdfobj.c: Fix some problems in reading cross-reference streams. * pngimage.c: Support PNG gAMA chunk. + * jpegimage.c: Various fixes in handling JPEG Exif data + (possible overflow and buffer overrun), adjusting indent and spaces. + * jp2image.c: JPEG2000 opacity channel support. + * pdfcolor.c: Update for PDF 1.7 in pdfcolor.c. 2015-04-05 Shunsaku Hirata <shunsaku.hirata74@gmail.com> diff --git a/Build/source/texk/dvipdfm-x/jp2image.c b/Build/source/texk/dvipdfm-x/jp2image.c index aa601fabebd..09d3b227c25 100644 --- a/Build/source/texk/dvipdfm-x/jp2image.c +++ b/Build/source/texk/dvipdfm-x/jp2image.c @@ -25,7 +25,10 @@ #endif /* - * JP2 & JPX baseline SUPPORT: + * JP2 & JPX baseline support + * + * 20150412 Added opacity (transparency) support. + * TODO: XMP Metadata */ #include <math.h> @@ -69,11 +72,11 @@ read_box_hdr (FILE *fp, unsigned int *lbox, unsigned int *tbox) bytesread += 8; if (*lbox == 1) { if (get_unsigned_quad(fp) != 0) - ERROR("LBox value in JP2 file >32 bits.\nI can't handle this!"); + ERROR("JPEG2000: LBox value in JP2 file >32 bits.\nI can't handle this!"); *lbox = get_unsigned_quad(fp); bytesread += 8; } else if (*lbox > 1 && *lbox < 8) { - WARN("Unknown LBox value %lu in JP2 file!", lbox); + WARN("JPEG2000: Unknown LBox value %lu in JP2 file!", lbox); } return bytesread; @@ -121,7 +124,7 @@ check_ftyp_data (FILE *fp, unsigned int size) } break; default: - WARN("Unknown JPEG 2000 File Type box Brand field value."); + WARN("JPEG2000: Unknown JPEG 2000 File Type box Brand field value."); seek_relative(fp, size); size = 0; supported = 0; @@ -160,7 +163,7 @@ scan_res_ (ximage_info *info, FILE *fp, unsigned int size) while (size > 0) { len = read_box_hdr(fp, &lbox, &tbox); if (lbox == 0) { - WARN("Unexpected lbox value 0 in JP2 Resolution box."); + WARN("JPEG2000: Unexpected lbox value 0 in JP2 Resolution box."); break; } switch (tbox) { @@ -176,7 +179,7 @@ scan_res_ (ximage_info *info, FILE *fp, unsigned int size) have_resd = 1; break; default: - WARN("Unknown JPEG 2000 box type in Resolution box."); + WARN("JPEG2000: Unknown JPEG 2000 box type in Resolution box."); seek_relative(fp, lbox - len); } size -= lbox; @@ -185,8 +188,50 @@ scan_res_ (ximage_info *info, FILE *fp, unsigned int size) return size == 0 ? 0 : -1; } +/* Acrobat seems require Channel Definition box to be defined when image data + * contains opacity channel. However, OpenJPEG (and maybe most of JPEG 2000 coders?) + * does not write Channel Definition box so transparency will be ignored. + */ static int -scan_jp2h (ximage_info *info, FILE *fp, unsigned int size) +scan_cdef (ximage_info *info, int *smask, FILE *fp, unsigned int size) +{ + int opacity_channels = 0; + int have_type0 = 0; + unsigned int i, Cn, N, Typ, Asoc; + + *smask = 0; + + N = get_unsigned_pair(fp); + if (size < N * 6 + 2) { + WARN("JPEG2000: Inconsistent N value in Channel Definition box."); + return -1; + } + for (i = 0; i < N; i++) { + Cn = get_unsigned_pair(fp); /* Cn */ + Typ = get_unsigned_pair(fp); + Asoc = get_unsigned_pair(fp); /* must be 0 for SMask */ + if (Cn > N) + WARN("JPEG2000: Invalid Cn value in Channel Definition box."); + if (Typ == 1) { + if (Asoc == 0) + have_type0 = 1; + opacity_channels++; + } else if (Typ == 2) { + opacity_channels++; + } + } + + if (opacity_channels == 1) + *smask = have_type0 ? 1 : 0; + else if (opacity_channels > 1) { + WARN("JPEG2000: Unsupported transparency type. (ignored)"); + } + + return 0; +} + +static int +scan_jp2h (ximage_info *info, int *smask, FILE *fp, unsigned int size) { int error = 0, have_ihdr = 0; unsigned int len, lbox, tbox; @@ -194,7 +239,7 @@ scan_jp2h (ximage_info *info, FILE *fp, unsigned int size) while (size > 0 && !error) { len = read_box_hdr(fp, &lbox, &tbox); if (lbox == 0) { - WARN("Unexpected lbox value 0 in JP2 Header box..."); + WARN("JPEG2000: Unexpected lbox value 0 in JP2 Header box..."); error = -1; break; } @@ -212,13 +257,16 @@ scan_jp2h (ximage_info *info, FILE *fp, unsigned int size) case JP2_BOX_RES_: error = scan_res_(info, fp, lbox - len); break; + case JP2_BOX_CDEF: + error = scan_cdef(info, smask, fp, lbox - len); + break; case JP2_BOX_BPCC: case JP2_BOX_COLR: case JP2_BOX_PCLR: - case JP2_BOX_CMAP: case JP2_BOX_CDEF: + case JP2_BOX_CMAP: case JPX_BOX_LBL_: seek_relative(fp, lbox - len); break; default: - WARN("Unknown JPEG 2000 box in JP2 Header box."); + WARN("JPEG2000: Unknown JPEG 2000 box in JP2 Header box."); seek_relative(fp, lbox - len); error = -1; } @@ -226,12 +274,12 @@ scan_jp2h (ximage_info *info, FILE *fp, unsigned int size) } if (!have_ihdr) - WARN("Expecting JPEG 2000 Image Header box but could not find."); + WARN("JPEG2000: Expecting JPEG 2000 Image Header box but could not find."); return (!error && have_ihdr && size == 0) ? 0 : -1; } static int -scan_file (ximage_info *info, FILE *fp) +scan_file (ximage_info *info, int *smask, FILE *fp) { int error = 0, have_jp2h = 0; int size; @@ -260,13 +308,13 @@ scan_file (ximage_info *info, FILE *fp) lbox = size; switch (tbox) { case JP2_BOX_JP2H: - error = scan_jp2h(info, fp, lbox - len); + error = scan_jp2h(info, smask, fp, lbox - len); have_jp2h = 1; break; case JP2_BOX_JP2C: /* JP2 requires JP2H appears before JP2C. */ if (!have_jp2h) - WARN("JPEG 2000 Codestream box found before JP2 Header box."); + WARN("JPEG2000: JPEG 2000 Codestream box found before JP2 Header box."); seek_relative(fp, lbox - len); break; default: @@ -276,12 +324,12 @@ scan_file (ximage_info *info, FILE *fp) } /* From ISO/IEC 15444-2 M.9.2.7 - The JP2 Header box shall be found in the file before the first - Contiguous Codestream box, Fragment Table box, Media Data box, - Codestream Header box, and Compositing Layer Header box. ... - */ + * The JP2 Header box shall be found in the file before the first + * Contiguous Codestream box, Fragment Table box, Media Data box, + * Codestream Header box, and Compositing Layer Header box. ... + */ if (!have_jp2h && !error) { - WARN("No JP2 Header box found. Not a JP2/JPX baseline file?"); + WARN("JPEG2000: No JP2 Header box found. Not a JP2/JPX baseline file?"); error = -1; } return error; @@ -315,6 +363,7 @@ int jp2_include_image (pdf_ximage *ximage, FILE *fp) { unsigned pdf_version; + int smask = 0; pdf_obj *stream, *stream_dict; ximage_info info; @@ -328,15 +377,18 @@ jp2_include_image (pdf_ximage *ximage, FILE *fp) stream = stream_dict = NULL; rewind(fp); - if (scan_file(&info, fp) < 0) { - WARN("Reading JPEG 2000 file failed."); + if (scan_file(&info, &smask, fp) < 0) { + WARN("JPEG2000: Reading JPEG 2000 file failed."); return -1; } stream = pdf_new_stream(0); stream_dict = pdf_stream_dict(stream); pdf_add_dict(stream_dict, - pdf_new_name("Filter"), pdf_new_name("JPXDecode")); + pdf_new_name("Filter"), pdf_new_name("JPXDecode")); + if (smask) + pdf_add_dict(stream_dict, + pdf_new_name("SMaskInData"), pdf_new_number(1)); /* Read whole file */ { size_t nb_read; @@ -355,13 +407,13 @@ int jp2_get_bbox (FILE *fp, int *width, int *height, double *xdensity, double *ydensity) { - int r; + int r, smask = 0; ximage_info info; pdf_ximage_init_image_info(&info); rewind(fp); - r = scan_file(&info, fp); + r = scan_file(&info, &smask, fp); *width = info.width; *height = info.height; diff --git a/Build/source/texk/dvipdfm-x/jpegimage.c b/Build/source/texk/dvipdfm-x/jpegimage.c index f600b4538e3..19e7d0108d4 100644 --- a/Build/source/texk/dvipdfm-x/jpegimage.c +++ b/Build/source/texk/dvipdfm-x/jpegimage.c @@ -123,16 +123,17 @@ typedef enum { typedef enum { JS_APPn_JFIF, JS_APPn_ADOBE, - JS_APPn_ICC + JS_APPn_ICC, + JS_APPn_XMP } JPEG_APPn_sig; struct JPEG_APPn_JFIF /* APP0 */ { unsigned short version; unsigned char units; /* 0: only aspect ratio - * 1: dots per inch - * 2: dots per cm - */ + * 1: dots per inch + * 2: dots per cm + */ unsigned short Xdensity; unsigned short Ydensity; unsigned char Xthumbnail; @@ -158,6 +159,14 @@ struct JPEG_APPn_Adobe /* APP14 */ unsigned char transform; /* color transform code */ }; +struct JPEG_APPn_XMP /* APP1 */ +{ + unsigned char *packet; /* XMP packet */ + + /* Length of XMP packet data */ + unsigned short length; +}; + struct JPEG_ext { JPEG_marker marker; @@ -190,16 +199,16 @@ struct JPEG_info #define HAVE_APPn_ADOBE (1 << 1) #define HAVE_APPn_ICC (1 << 2) #define HAVE_APPn_Exif (1 << 3) +#define HAVE_APPn_XMP (1 << 4) static int JPEG_scan_file (struct JPEG_info *j_info, FILE *fp); -static int JPEG_copy_stream (struct JPEG_info *j_info, - pdf_obj *stream, FILE *fp); +static int JPEG_copy_stream (struct JPEG_info *j_info, pdf_obj *stream, FILE *fp); static void JPEG_info_init (struct JPEG_info *j_info); static void JPEG_info_clear (struct JPEG_info *j_info); +static pdf_obj *JPEG_get_XMP (struct JPEG_info *j_info); static pdf_obj *JPEG_get_iccp (struct JPEG_info *j_info); -static void jpeg_get_density (struct JPEG_info *j_info, - double *xdensity, double *ydensity); +static void jpeg_get_density (struct JPEG_info *j_info, double *xdensity, double *ydensity); int check_for_jpeg (FILE *fp) @@ -218,11 +227,11 @@ check_for_jpeg (FILE *fp) int jpeg_include_image (pdf_ximage *ximage, FILE *fp) { - pdf_obj *stream; - pdf_obj *stream_dict; - pdf_obj *colorspace; - int colortype; - ximage_info info; + pdf_obj *stream; + pdf_obj *stream_dict; + pdf_obj *colorspace; + int colortype; + ximage_info info; struct JPEG_info j_info; if (!check_for_jpeg(fp)) { @@ -253,8 +262,7 @@ jpeg_include_image (pdf_ximage *ximage, FILE *fp) colortype = PDF_COLORSPACE_TYPE_CMYK; break; default: - WARN("%s: Unknown color space (num components: %d)", - JPEG_DEBUG_STR, info.num_components); + WARN("%s: Unknown color space (num components: %d)", JPEG_DEBUG_STR, info.num_components); JPEG_info_clear(&j_info); return -1; } @@ -262,42 +270,50 @@ jpeg_include_image (pdf_ximage *ximage, FILE *fp) /* JPEG image use DCTDecode. */ stream = pdf_new_stream (0); stream_dict = pdf_stream_dict(stream); - pdf_add_dict(stream_dict, - pdf_new_name("Filter"), pdf_new_name("DCTDecode")); + pdf_add_dict(stream_dict, pdf_new_name("Filter"), pdf_new_name("DCTDecode")); + + /* XMP Metadata */ + if (pdf_get_version() >= 4) { + if (j_info.flags & HAVE_APPn_XMP) { + pdf_obj *XMP_stream; + + XMP_stream = JPEG_get_XMP(&j_info); + pdf_add_dict(stream_dict, + pdf_new_name("Metadata"), pdf_ref_obj(XMP_stream)); + pdf_release_obj(XMP_stream); + } + } + /* Check embedded ICC Profile */ colorspace = NULL; if (j_info.flags & HAVE_APPn_ICC) { pdf_obj *icc_stream, *intent; + int cspc_id; icc_stream = JPEG_get_iccp(&j_info); - if (!icc_stream) colorspace = NULL; else { - int cspc_id; - if (iccp_check_colorspace(colortype, - pdf_stream_dataptr(icc_stream), - pdf_stream_length (icc_stream)) < 0) - colorspace = NULL; + pdf_stream_dataptr(icc_stream), pdf_stream_length (icc_stream)) < 0) + colorspace = NULL; else { - cspc_id = iccp_load_profile(NULL, /* noname */ - pdf_stream_dataptr(icc_stream), - pdf_stream_length (icc_stream)); - if (cspc_id < 0) - colorspace = NULL; - else { - colorspace = pdf_get_colorspace_reference(cspc_id); - intent = iccp_get_rendering_intent(pdf_stream_dataptr(icc_stream), - pdf_stream_length (icc_stream)); - if (intent) - pdf_add_dict(stream_dict, pdf_new_name("Intent"), intent); - } + cspc_id = iccp_load_profile(NULL, /* noname */ + pdf_stream_dataptr(icc_stream), + pdf_stream_length (icc_stream)); + if (cspc_id < 0) + colorspace = NULL; + else { + colorspace = pdf_get_colorspace_reference(cspc_id); + intent = iccp_get_rendering_intent(pdf_stream_dataptr(icc_stream), + pdf_stream_length (icc_stream)); + if (intent) + pdf_add_dict(stream_dict, pdf_new_name("Intent"), intent); + } } pdf_release_obj(icc_stream); } } - /* No ICC or invalid ICC profile. */ if (!colorspace) { switch (colortype) { @@ -315,7 +331,6 @@ jpeg_include_image (pdf_ximage *ximage, FILE *fp) pdf_add_dict(stream_dict, pdf_new_name("ColorSpace"), colorspace); #define IS_ADOBE_CMYK(j) (((j).flags & HAVE_APPn_ADOBE) && (j).num_components == 4) - if (IS_ADOBE_CMYK(j_info)) { pdf_obj *decode; int i; @@ -346,8 +361,7 @@ jpeg_include_image (pdf_ximage *ximage, FILE *fp) } static void -jpeg_get_density (struct JPEG_info *j_info, - double *xdensity, double *ydensity) +jpeg_get_density (struct JPEG_info *j_info, double *xdensity, double *ydensity) { if (compat_mode) { *xdensity = *ydensity = 72.0 / 100.0; @@ -355,53 +369,26 @@ jpeg_get_density (struct JPEG_info *j_info, } /* - j_info->xdpi and j_info->ydpi are already determined - because jpeg_get_density() is always called after - JPEG_scan_file(). -*/ + * j_info->xdpi and j_info->ydpi are already determined + * because jpeg_get_density() is always called after + * JPEG_scan_file(). + */ *xdensity = 72.0 / j_info->xdpi; *ydensity = 72.0 / j_info->ydpi; - return; -#if 0 - *xdensity = *ydensity = 1.0; - if (j_info->flags & HAVE_APPn_JFIF) { - struct JPEG_APPn_JFIF *app_data; - int i; - for (i = 0; i < j_info->num_appn; i++) { - if (j_info->appn[i].marker == JM_APP0 && - j_info->appn[i].app_sig == JS_APPn_JFIF) - break; - } - if (i < j_info->num_appn) { - app_data = (struct JPEG_APPn_JFIF *)j_info->appn[i].app_data; - switch (app_data->units) { - case 1: /* pixels per inch */ - *xdensity = 72.0 / app_data->Xdensity; - *ydensity = 72.0 / app_data->Ydensity; - break; - case 2: /* pixels per centimeter */ - *xdensity = 72.0 / 2.54 / app_data->Xdensity; - *ydensity = 72.0 / 2.54 / app_data->Ydensity; - break; - default: - break; - } - } - } -#endif + return; } static void JPEG_info_init (struct JPEG_info *j_info) { - j_info->width = 0; - j_info->height = 0; + j_info->width = 0; + j_info->height = 0; j_info->bits_per_component = 0; - j_info->num_components = 0; + j_info->num_components = 0; - j_info->xdpi = 0.0; - j_info->ydpi = 0.0; + j_info->xdpi = 0.0; + j_info->ydpi = 0.0; j_info->flags = 0; j_info->num_appn = 0; @@ -424,8 +411,7 @@ JPEG_release_APPn_data (JPEG_marker marker, JPEG_APPn_sig app_sig, void *app_dat data->thumbnail = NULL; RELEASE(data); - } else if (marker == JM_APP2 && - app_sig == JS_APPn_ICC) { + } else if (marker == JM_APP2 && app_sig == JS_APPn_ICC) { struct JPEG_APPn_ICC *data; data = (struct JPEG_APPn_ICC *) app_data; @@ -434,13 +420,20 @@ JPEG_release_APPn_data (JPEG_marker marker, JPEG_APPn_sig app_sig, void *app_dat data->chunk = NULL; RELEASE(data); - } else if (marker == JM_APP14 && - app_sig == JS_APPn_ADOBE) { + } else if (marker == JM_APP14 && app_sig == JS_APPn_ADOBE) { struct JPEG_APPn_Adobe *data; data = (struct JPEG_APPn_Adobe *) app_data; RELEASE(data); + } else if (marker == JM_APP1 && app_sig == JS_APPn_XMP) { + struct JPEG_APPn_XMP *data; + + data = (struct JPEG_APPn_XMP *) app_data; + if (data->packet) + RELEASE(data->packet); + + RELEASE(data); } } @@ -453,7 +446,7 @@ JPEG_info_clear (struct JPEG_info *j_info) for (i = 0; i < j_info->num_appn; i++) JPEG_release_APPn_data(j_info->appn[i].marker, - j_info->appn[i].app_sig, j_info->appn[i].app_data); + j_info->appn[i].app_sig, j_info->appn[i].app_data); RELEASE(j_info->appn); } j_info->appn = NULL; @@ -465,36 +458,63 @@ JPEG_info_clear (struct JPEG_info *j_info) static pdf_obj * JPEG_get_iccp (struct JPEG_info *j_info) { - pdf_obj *icc_stream; + pdf_obj *icc_stream; struct JPEG_APPn_ICC *icc; - int i, prev_id = 0, num_icc_seg = -1; + int i, prev_id = 0, num_icc_seg = -1; icc_stream = pdf_new_stream(STREAM_COMPRESS); for (i = 0; i < j_info->num_appn; i++) { if (j_info->appn[i].marker != JM_APP2 || - j_info->appn[i].app_sig != JS_APPn_ICC) + j_info->appn[i].app_sig != JS_APPn_ICC) continue; icc = (struct JPEG_APPn_ICC *) j_info->appn[i].app_data; if (num_icc_seg < 0 && prev_id == 0) { num_icc_seg = icc->num_chunks; /* ICC chunks are sorted? */ } else if (icc->seq_id != prev_id + 1 || - num_icc_seg != icc->num_chunks || - icc->seq_id > icc->num_chunks) { - WARN("Invalid JPEG ICC chunk: %d (p:%d, n:%d)", - icc->seq_id, prev_id, icc->num_chunks); + num_icc_seg != icc->num_chunks || icc->seq_id > icc->num_chunks) { + WARN("Invalid JPEG ICC chunk: %d (p:%d, n:%d)", icc->seq_id, prev_id, icc->num_chunks); pdf_release_obj(icc_stream); icc_stream = NULL; break; } pdf_add_stream(icc_stream, icc->chunk, icc->length); - prev_id = icc->seq_id; + prev_id = icc->seq_id; num_icc_seg = icc->num_chunks; } return icc_stream; } +static pdf_obj * +JPEG_get_XMP (struct JPEG_info *j_info) +{ + pdf_obj *XMP_stream, *stream_dict; + struct JPEG_APPn_XMP *XMP; + int i, count = 0; + + /* I don't know if XMP Metadata should be compressed here.*/ + XMP_stream = pdf_new_stream(STREAM_COMPRESS); + stream_dict = pdf_stream_dict(XMP_stream); + pdf_add_dict(stream_dict, + pdf_new_name("Type"), pdf_new_name("Metadata")); + pdf_add_dict(stream_dict, + pdf_new_name("Subtype"), pdf_new_name("XML")); + for (i = 0; i < j_info->num_appn; i++) { + /* Not sure for the case of multiple segments */ + if (j_info->appn[i].marker != JM_APP1 || + j_info->appn[i].app_sig != JS_APPn_XMP) + continue; + XMP = (struct JPEG_APPn_XMP *) j_info->appn[i].app_data; + pdf_add_stream(XMP_stream, XMP->packet, XMP->length); + count++; + } + if (count > 1) + WARN("%s: Multiple XMP segments found in JPEG file. (untested)", JPEG_DEBUG_STR); + + return XMP_stream; +} + static JPEG_marker JPEG_get_marker (FILE *fp) { @@ -515,8 +535,7 @@ JPEG_get_marker (FILE *fp) } static int -add_APPn_marker (struct JPEG_info *j_info, - JPEG_marker marker, int app_sig, void *app_data) +add_APPn_marker (struct JPEG_info *j_info, JPEG_marker marker, int app_sig, void *app_data) { int n; @@ -551,131 +570,171 @@ read_APP14_Adobe (struct JPEG_info *j_info, FILE *fp) return 7; } -static unsigned int -read_exif_bytes(unsigned char **p, int n, int b) +#define JPEG_EXIF_BIGENDIAN 0 +#define JPEG_EXIF_LITTLEENDIAN 1 +static long +read_exif_bytes (unsigned char **pp, int n, int endian) { - unsigned int rval = 0; - unsigned char *pp = *p; - if (b) { - switch (n) { - case 4: - rval += *pp++; rval <<= 8; - rval += *pp++; rval <<= 8; - case 2: - rval += *pp++; rval <<= 8; - rval += *pp; - break; + long rval = 0; + unsigned char *p = *pp; + int i; + + switch (endian) { + case JPEG_EXIF_BIGENDIAN: + for (i = 0; i < n; i++) { + rval = (rval << 8) + p[i]; } - } - else { - pp += n; - switch (n) { - case 4: - rval += *--pp; rval <<= 8; - rval += *--pp; rval <<= 8; - case 2: - rval += *--pp; rval <<= 8; - rval += *--pp; - break; + break; + case JPEG_EXIF_LITTLEENDIAN: + for (i = n - 1; i >= 0; i--) { + rval = (rval << 8) + p[i]; } + break; } - *p += n; + + *pp += n; return rval; } +#define JPEG_EXIF_TYPE_BYTE 1 +#define JPEG_EXIF_TYPE_ASCII 2 +#define JPEG_EXIF_TYPE_SHORT 3 +#define JPEG_EXIF_TYPE_LONG 4 +#define JPEG_EXIF_TYPE_RATIONAL 5 +#define JPEG_EXIF_TYPE_UNDEFINED 7 +#define JPEG_EXIF_TYPE_SLONG 9 +#define JPEG_EXIF_TYPE_SRATIONAL 10 + +#define JPEG_EXIF_TAG_XRESOLUTION 282 +#define JPEG_EXIF_TAG_YRESOLUTION 283 +#define JPEG_EXIF_TAG_RESOLUTIONUNIT 296 static unsigned short read_APP1_Exif (struct JPEG_info *j_info, FILE *fp, unsigned short length) { /* this doesn't save the data, just reads the tags we need */ /* based on info from http://www.exif.org/Exif2-2.PDF */ unsigned char *buffer = NEW(length, unsigned char); - unsigned char *p, *rp; + unsigned char *p, *endptr; unsigned char *tiff_header; - char bigendian; - int i; - int num_fields, tag, type; - int value = 0, num = 0, den = 0; /* silence uninitialized warnings */ - double xres = 72.0; - double yres = 72.0; - double res_unit = 1.0; + int endian; + int num_fields; + long value = 0, offset; + double xres = 72.0, yres = 72.0; + double res_unit = 1.0; + fread(buffer, length, 1, fp); - p = buffer; - while ((p < buffer + length) && (*p == 0)) - ++p; + if (length < 10) + goto err; + + p = buffer; endptr = buffer + length; + while ((p < endptr) && (*p == 0)) + p++; + + /* TIFF header */ tiff_header = p; - if ((*p == 'M') && (*(p+1) == 'M')) - bigendian = 1; - else if ((*p == 'I') && (*(p+1) == 'I')) - bigendian = 0; - else + if ((p[0] == 'M') && (p[1] == 'M')) + endian = JPEG_EXIF_BIGENDIAN; + else if ((p[0] == 'I') && (p[1] == 'I')) + endian = JPEG_EXIF_LITTLEENDIAN; + else { + WARN("%s: Invalid value in Exif TIFF header.", JPEG_DEBUG_STR); goto err; - p += 2; - i = read_exif_bytes(&p, 2, bigendian); - if (i != 42) + } + p += 2; + value = read_exif_bytes(&p, 2, endian); + if (value != 42) { + WARN("%s: Invalid value in Exif TIFF header.", JPEG_DEBUG_STR); goto err; - i = read_exif_bytes(&p, 4, bigendian); - p = tiff_header + i; - num_fields = read_exif_bytes(&p, 2, bigendian); - while (num_fields-- > 0) { - tag = read_exif_bytes(&p, 2, bigendian); - type = read_exif_bytes(&p, 2, bigendian); - read_exif_bytes(&p, 4, bigendian); - switch (type) { - case 1: /* byte */ - value = *p++; - p += 3; - break; - case 3: /* short */ - value = read_exif_bytes(&p, 2, bigendian); - p += 2; - break; - case 4: /* long */ - case 9: /* slong */ - value = read_exif_bytes(&p, 4, bigendian); - break; - case 5: /* rational */ - case 10: /* srational */ - value = read_exif_bytes(&p, 4, bigendian); - rp = tiff_header + value; - num = read_exif_bytes(&rp, 4, bigendian); - den = read_exif_bytes(&rp, 4, bigendian); - break; - case 7: /* undefined */ - value = *p++; - p += 3; - break; - case 2: /* ascii */ - default: - p += 4; - break; + } + /* Offset to 0th IFD */ + offset = read_exif_bytes(&p, 4, endian); + + p = tiff_header + offset; + num_fields = read_exif_bytes(&p, 2, endian); + while (num_fields-- > 0 && p < endptr) { + int tag, type; + long count; + unsigned long den, num; + + if (p + 12 > endptr) { + WARN("%s: Truncated Exif data...", JPEG_DEBUG_STR); + goto err; } + tag = (int) read_exif_bytes(&p, 2, endian); + type = (int) read_exif_bytes(&p, 2, endian); + count = read_exif_bytes(&p, 4, endian); + /* Exif data is redundant... */ switch (tag) { - case 282: /* x res */ - if (den != 0) - xres = num / den; - break; - case 283: /* y res */ - if (den != 0) - yres = num / den; - break; - case 296: /* res unit */ - switch (value) { - case 2: - res_unit = 1.0; - break; - case 3: - res_unit = 2.54; - break; - } + case JPEG_EXIF_TAG_XRESOLUTION: + if (type != JPEG_EXIF_TYPE_RATIONAL || count != 1) { + WARN("%s: Invalid data for XResolution in Exif chunk.", JPEG_DEBUG_STR); + goto err; + } + offset = read_exif_bytes(&p, 4, endian); + if (tiff_header + offset + 8 > buffer + length) { + WARN("%s: Invalid offset value in Exif data.", JPEG_DEBUG_STR); + goto err; + } else { + unsigned char *vp = tiff_header + offset; + num = (unsigned long) read_exif_bytes(&vp, 4, endian); + den = (unsigned long) read_exif_bytes(&vp, 4, endian); + } + if (den > 0) + xres = (double) num / den; + break; + case JPEG_EXIF_TAG_YRESOLUTION: + if (type != JPEG_EXIF_TYPE_RATIONAL || count != 1) { + WARN("%s: Invalid data for XResolution in Exif chunk.", JPEG_DEBUG_STR); + goto err; + } + offset = read_exif_bytes(&p, 4, endian); + if (tiff_header + offset + 8 > buffer + length) { + WARN("%s: Invalid offset value in Exif data.", JPEG_DEBUG_STR); + goto err; + } else { + unsigned char *vp = tiff_header + offset; + num = (unsigned long) read_exif_bytes(&vp, 4, endian); + den = (unsigned long) read_exif_bytes(&vp, 4, endian); + } + if (den > 0) + yres = (double) num / den; + break; + case JPEG_EXIF_TAG_RESOLUTIONUNIT: + if (type != JPEG_EXIF_TYPE_SHORT || count != 1) { + WARN("%s: Invalid data for ResolutionUnit in Exif chunk.", JPEG_DEBUG_STR); + goto err; + } + value = read_exif_bytes(&p, 2, endian); + p += 2; + if (value == 2) + res_unit = 1.0 ; /* inch */ + else if (value == 3) + res_unit = 2.54; /* cm */ + break; + default: + /* 40901 ColorSpace and 42240 Gamma unsupported... */ + p += 4; + break; } } -/* - Do not overwrite if j_info->xdpi and j_info->ydpi are - already determined as JFIF -*/ + if (num_fields > 0) { + WARN("%s: Truncated Exif data...", JPEG_DEBUG_STR); + goto err; + } + +/* Do not overwrite j_info->xdpi and j_info->ydpi if they are + * already determined in JFIF. + */ if (j_info->xdpi < 0.1 && j_info->ydpi < 0.1) { j_info->xdpi = xres * res_unit; j_info->ydpi = yres * res_unit; + } else { + if (j_info->xdpi != xres * res_unit || + j_info->ydpi != yres * res_unit) { + WARN("%s: Inconsistent resolution may have " \ + "specified in Exif and JFIF: %gx%g - %gx%g", JPEG_DEBUG_STR, + xres * res_unit, yres * res_unit, j_info->xdpi, j_info->ydpi); + } } err: @@ -690,10 +749,10 @@ read_APP0_JFIF (struct JPEG_info *j_info, FILE *fp) unsigned short thumb_data_len; app_data = NEW(1, struct JPEG_APPn_JFIF); - app_data->version = get_unsigned_pair(fp); - app_data->units = get_unsigned_byte(fp); - app_data->Xdensity = get_unsigned_pair(fp); - app_data->Ydensity = get_unsigned_pair(fp); + app_data->version = get_unsigned_pair(fp); + app_data->units = get_unsigned_byte(fp); + app_data->Xdensity = get_unsigned_pair(fp); + app_data->Ydensity = get_unsigned_pair(fp); app_data->Xthumbnail = get_unsigned_byte(fp); app_data->Ythumbnail = get_unsigned_byte(fp); thumb_data_len = 3 * app_data->Xthumbnail * app_data->Ythumbnail; @@ -734,7 +793,7 @@ read_APP0_JFXX (FILE *fp, unsigned short length) * 0x11: Thumbnail stored using 1 byte/pixel * 0x13: Thumbnail stored using 3 bytes/pixel */ - seek_relative(fp, length-1); /* Thunbnail image */ + seek_relative(fp, length - 1); /* Thunbnail image */ /* Ignore */ @@ -742,6 +801,21 @@ read_APP0_JFXX (FILE *fp, unsigned short length) } static unsigned short +read_APP1_XMP (struct JPEG_info *j_info, FILE *fp, unsigned short length) +{ + struct JPEG_APPn_XMP *app_data; + + app_data = NEW(1, struct JPEG_APPn_XMP); + app_data->length = length; + app_data->packet = NEW(app_data->length, unsigned char); + fread(app_data->packet, 1, app_data->length, fp); + + add_APPn_marker(j_info, JM_APP1, JS_APPn_XMP, app_data); + + return length; +} + +static unsigned short read_APP2_ICC (struct JPEG_info *j_info, FILE *fp, unsigned short length) { struct JPEG_APPn_ICC *app_data; @@ -749,8 +823,8 @@ read_APP2_ICC (struct JPEG_info *j_info, FILE *fp, unsigned short length) app_data = NEW(1, struct JPEG_APPn_ICC); app_data->seq_id = get_unsigned_byte(fp); /* Starting at 1 */ app_data->num_chunks = get_unsigned_byte(fp); - app_data->length = length - 2; - app_data->chunk = NEW(app_data->length, unsigned char); + app_data->length = length - 2; + app_data->chunk = NEW(app_data->length, unsigned char); fread(app_data->chunk, 1, app_data->length, fp); add_APPn_marker(j_info, JM_APP2, JS_APPn_ICC, app_data); @@ -762,173 +836,162 @@ static int JPEG_copy_stream (struct JPEG_info *j_info, pdf_obj *stream, FILE *fp) { JPEG_marker marker; - int length, nb_read; - int found_SOFn, count; - + long length; + int found_SOFn, count; + +#define SKIP_CHUNK(j,c) ((j)->skipbits[(c) / 8] & (1 << (7 - (c) % 8))) +#define COPY_CHUNK(f,s,l) while ((l) > 0) { \ + size_t nb_read = fread(work_buffer, sizeof(char), MIN((l), WORK_BUFFER_SIZE), (f)); \ + if (nb_read > 0) \ + pdf_add_stream((s), work_buffer, nb_read); \ + (l) -= nb_read; \ +} rewind(fp); count = 0; found_SOFn = 0; - while (!found_SOFn && - count < MAX_COUNT && - (marker = JPEG_get_marker(fp)) != (JPEG_marker) -1) { - if (marker == JM_SOI || - (marker >= JM_RST0 && marker <= JM_RST7)) { + while (!found_SOFn && count < MAX_COUNT && + (marker = JPEG_get_marker(fp)) != (JPEG_marker) - 1) { + if ( marker == JM_SOI || + (marker >= JM_RST0 && marker <= JM_RST7)) { work_buffer[0] = (char) 0xff; work_buffer[1] = (char) marker; pdf_add_stream(stream, work_buffer, 2); - count++; - continue; - } - length = get_unsigned_pair(fp) - 2; - switch (marker) { - case JM_SOF0: case JM_SOF1: case JM_SOF2: case JM_SOF3: - case JM_SOF5: case JM_SOF6: case JM_SOF7: case JM_SOF9: - case JM_SOF10: case JM_SOF11: case JM_SOF13: case JM_SOF14: - case JM_SOF15: - work_buffer[0] = (char) 0xff; - work_buffer[1] = (char) marker; - work_buffer[2] = ((length + 2) >> 8) & 0xff; - work_buffer[3] = (length + 2) & 0xff; - pdf_add_stream(stream, work_buffer, 4); - while (length > 0) { - nb_read = fread(work_buffer, sizeof(char), - MIN(length, WORK_BUFFER_SIZE), fp); - if (nb_read > 0) - pdf_add_stream(stream, work_buffer, nb_read); - length -= nb_read; - } - found_SOFn = 1; - break; - default: - if (j_info->skipbits[count / 8] & (1 << (7 - (count % 8)))) { - /* skip */ - while (length > 0) { - nb_read = fread(work_buffer, sizeof(char), - MIN(length, WORK_BUFFER_SIZE), fp); - length -= nb_read; - } - } else { - work_buffer[0] = (char) 0xff; - work_buffer[1] = (char) marker; - work_buffer[2] = ((length + 2) >> 8) & 0xff; - work_buffer[3] = (length + 2) & 0xff; - pdf_add_stream(stream, work_buffer, 4); - while (length > 0) { - nb_read = fread(work_buffer, sizeof(char), - MIN(length, WORK_BUFFER_SIZE), fp); - if (nb_read > 0) - pdf_add_stream(stream, work_buffer, nb_read); - length -= nb_read; - } + } else { + length = get_unsigned_pair(fp) - 2; + switch (marker) { + case JM_SOF0: case JM_SOF1: case JM_SOF2: case JM_SOF3: + case JM_SOF5: case JM_SOF6: case JM_SOF7: case JM_SOF9: + case JM_SOF10: case JM_SOF11: case JM_SOF13: case JM_SOF14: + case JM_SOF15: + work_buffer[0] = (char) 0xff; + work_buffer[1] = (char) marker; + work_buffer[2] = ((length + 2) >> 8) & 0xff; + work_buffer[3] = (length + 2) & 0xff; + pdf_add_stream(stream, work_buffer, 4); + COPY_CHUNK(fp, stream, length); + found_SOFn = 1; + break; + default: + if (SKIP_CHUNK(j_info, count)) { + seek_relative(fp, length); + } else { + work_buffer[0] = (char) 0xff; + work_buffer[1] = (char) marker; + work_buffer[2] = ((length + 2) >> 8) & 0xff; + work_buffer[3] = (length + 2) & 0xff; + pdf_add_stream(stream, work_buffer, 4); + COPY_CHUNK(fp, stream, length); + } } } count++; } - while ((length = fread(work_buffer, - sizeof(char), WORK_BUFFER_SIZE, fp)) > 0) { + sizeof(char), WORK_BUFFER_SIZE, fp)) > 0) { pdf_add_stream(stream, work_buffer, length); } return (found_SOFn ? 0 : -1); } +#define SET_SKIP(j,c) if ((c) < MAX_COUNT) { \ + (j)->skipbits[(c) / 8] |= (1 << (7 - ((c) % 8))); \ +} static int JPEG_scan_file (struct JPEG_info *j_info, FILE *fp) { JPEG_marker marker; - unsigned short length; - int found_SOFn, count; - char app_sig[128]; + int found_SOFn, count; + char app_sig[128]; rewind(fp); count = 0; found_SOFn = 0; while (!found_SOFn && - (marker = JPEG_get_marker(fp)) != (JPEG_marker) -1) { - if (marker == JM_SOI || - (marker >= JM_RST0 && marker <= JM_RST7)) { - count++; - continue; - } - length = get_unsigned_pair(fp) - 2; - switch (marker) { - case JM_SOF0: case JM_SOF1: case JM_SOF2: case JM_SOF3: - case JM_SOF5: case JM_SOF6: case JM_SOF7: case JM_SOF9: - case JM_SOF10: case JM_SOF11: case JM_SOF13: case JM_SOF14: - case JM_SOF15: - j_info->bits_per_component = get_unsigned_byte(fp); - j_info->height = get_unsigned_pair(fp); - j_info->width = get_unsigned_pair(fp); - j_info->num_components = get_unsigned_byte(fp); - found_SOFn = 1; - break; - case JM_APP0: - if (length > 5) { - if (fread(app_sig, sizeof(char), 5, fp) != 5) - return -1; - length -= 5; - if (!memcmp(app_sig, "JFIF\000", 5)) { - j_info->flags |= HAVE_APPn_JFIF; - length -= read_APP0_JFIF(j_info, fp); - } else if (!memcmp(app_sig, "JFXX", 5)) { - length -= read_APP0_JFXX(fp, length); - } - } - seek_relative(fp, length); - break; - case JM_APP1: - if (length > 5) { - if (fread(app_sig, sizeof(char), 5, fp) != 5) - return -1; - length -= 5; - if (!memcmp(app_sig, "Exif\000", 5)) { - j_info->flags |= HAVE_APPn_Exif; - length -= read_APP1_Exif(j_info, fp, length); - } - } - seek_relative(fp, length); - break; - case JM_APP2: - if (length >= 14) { - if (fread(app_sig, sizeof(char), 12, fp) != 12) - return -1; - length -= 12; - if (!memcmp(app_sig, "ICC_PROFILE\000", 12)) { - j_info->flags |= HAVE_APPn_ICC; - length -= read_APP2_ICC(j_info, fp, length); - if (count < MAX_COUNT) { - j_info->skipbits[count / 8] |= (1 << (7 - (count % 8))); - } - } - } - seek_relative(fp, length); - break; - case JM_APP14: - if (length > 5) { - if (fread(app_sig, sizeof(char), 5, fp) != 5) - return -1; - length -= 5; - if (!memcmp(app_sig, "Adobe", 5)) { - j_info->flags |= HAVE_APPn_ADOBE; - length -= read_APP14_Adobe(j_info, fp); - } else { - if (count < MAX_COUNT) { - j_info->skipbits[count/8] |= (1 << (7 - (count % 8))); - } - } - } - seek_relative(fp, length); - break; - default: - seek_relative(fp, length); - if (marker >= JM_APP0 && - marker <= JM_APP15) { - if (count < MAX_COUNT) { - j_info->skipbits[count / 8] |= (1 << (7 - (count % 8))); - } + (marker = JPEG_get_marker(fp)) != (JPEG_marker) -1) { + if ( marker != JM_SOI && + (marker < JM_RST0 || marker > JM_RST7)) { + long length = get_unsigned_pair(fp) - 2; + switch (marker) { + case JM_SOF0: case JM_SOF1: case JM_SOF2: case JM_SOF3: + case JM_SOF5: case JM_SOF6: case JM_SOF7: case JM_SOF9: + case JM_SOF10: case JM_SOF11: case JM_SOF13: case JM_SOF14: + case JM_SOF15: + j_info->bits_per_component = get_unsigned_byte(fp); + j_info->height = get_unsigned_pair(fp); + j_info->width = get_unsigned_pair(fp); + j_info->num_components = get_unsigned_byte(fp); + found_SOFn = 1; + break; + case JM_APP0: + if (length > 5) { + if (fread(app_sig, sizeof(char), 5, fp) != 5) + return -1; + length -= 5; + if (!memcmp(app_sig, "JFIF\000", 5)) { + j_info->flags |= HAVE_APPn_JFIF; + length -= read_APP0_JFIF(j_info, fp); + } else if (!memcmp(app_sig, "JFXX", 5)) { + length -= read_APP0_JFXX(fp, length); + } + } + seek_relative(fp, length); + break; + case JM_APP1: + if (length > 5) { + if (fread(app_sig, sizeof(char), 5, fp) != 5) + return -1; + length -= 5; + if (!memcmp(app_sig, "Exif\000", 5)) { + j_info->flags |= HAVE_APPn_Exif; + length -= read_APP1_Exif(j_info, fp, length); + } else if (!memcmp(app_sig, "http:", 5) && length > 24) { + if (fread(app_sig, sizeof(char), 24, fp) != 24) + return -1; + length -= 24; + if (!memcmp(app_sig, "//ns.adobe.com/xap/1.0/\000", 24)) { + j_info->flags |= HAVE_APPn_XMP; + length -= read_APP1_XMP(j_info, fp, length); + SET_SKIP(j_info, count); + } + } + } + seek_relative(fp, length); + break; + case JM_APP2: + if (length >= 14) { + if (fread(app_sig, sizeof(char), 12, fp) != 12) + return -1; + length -= 12; + if (!memcmp(app_sig, "ICC_PROFILE\000", 12)) { + j_info->flags |= HAVE_APPn_ICC; + length -= read_APP2_ICC(j_info, fp, length); + SET_SKIP(j_info, count); + } + } + seek_relative(fp, length); + break; + case JM_APP14: + if (length > 5) { + if (fread(app_sig, sizeof(char), 5, fp) != 5) + return -1; + length -= 5; + if (!memcmp(app_sig, "Adobe", 5)) { + j_info->flags |= HAVE_APPn_ADOBE; + length -= read_APP14_Adobe(j_info, fp); + } else { + SET_SKIP(j_info, count); + } + } + seek_relative(fp, length); + break; + default: + seek_relative(fp, length); + if (marker >= JM_APP0 && marker <= JM_APP15) { + SET_SKIP(j_info, count); + } + break; } - break; } count++; } @@ -937,8 +1000,7 @@ JPEG_scan_file (struct JPEG_info *j_info, FILE *fp) } int -jpeg_get_bbox (FILE *fp, int *width, int *height, - double *xdensity, double *ydensity) +jpeg_get_bbox (FILE *fp, int *width, int *height, double *xdensity, double *ydensity) { struct JPEG_info j_info; diff --git a/Build/source/texk/dvipdfm-x/pdfcolor.c b/Build/source/texk/dvipdfm-x/pdfcolor.c index eea24abf57b..ee6dac5490d 100644 --- a/Build/source/texk/dvipdfm-x/pdfcolor.c +++ b/Build/source/texk/dvipdfm-x/pdfcolor.c @@ -599,7 +599,9 @@ static struct {0, 0}, /* PDF-1.2, we don't support them */ {0x02, 0x10}, /* PDF-1.3 */ {0x02, 0x20}, /* PDF-1.4 */ - {0x04, 0x00} /* PDF-1.5 */ + {0x04, 0x00}, /* PDF-1.5 */ + {0x04, 0x00}, /* PDF-1.6 */ + {0x04, 0x20}, /* PDF-1.7 */ }; static int @@ -608,11 +610,11 @@ iccp_version_supported (int major, int minor) int pdf_ver; pdf_ver = pdf_get_version(); - if (pdf_ver < 6) { + if (pdf_ver < 8) { if (icc_versions[pdf_ver].major < major) return 0; else if (icc_versions[pdf_ver].major == major && - icc_versions[pdf_ver].minor < minor) + icc_versions[pdf_ver].minor < minor) return 0; else { return 1; |