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 = texpdf_new_stream(STREAM_COMPRESS); stream_dict = texpdf_stream_dict(XMP_stream); texpdf_add_dict(stream_dict, texpdf_new_name("Type"), texpdf_new_name("Metadata")); texpdf_add_dict(stream_dict, texpdf_new_name("Subtype"), texpdf_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; texpdf_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; }
int jpeg_include_image (pdf_ximage *ximage, FILE *fp) { pdf_obj *stream; pdf_obj *stream_dict; pdf_obj *colorspace; int colortype; ximage_info info; struct JPEG_info j_info; if (!texpdf_check_for_jpeg(fp)) { WARN("%s: Not a JPEG file?", JPEG_DEBUG_STR); rewind(fp); return -1; } /* File position is 2 here... */ texpdf_ximage_init_image_info(&info); JPEG_info_init(&j_info); if (JPEG_scan_file(&j_info, fp) < 0) { WARN("%s: Not a JPEG file?", JPEG_DEBUG_STR); JPEG_info_clear(&j_info); return -1; } switch (j_info.num_components) { case 1: colortype = PDF_COLORSPACE_TYPE_GRAY; break; case 3: colortype = PDF_COLORSPACE_TYPE_RGB; break; case 4: colortype = PDF_COLORSPACE_TYPE_CMYK; break; default: WARN("%s: Unknown color space (num components: %d)", JPEG_DEBUG_STR, info.num_components); JPEG_info_clear(&j_info); return -1; } /* JPEG image use DCTDecode. */ stream = texpdf_new_stream (0); stream_dict = texpdf_stream_dict(stream); texpdf_add_dict(stream_dict, texpdf_new_name("Filter"), texpdf_new_name("DCTDecode")); /* XMP Metadata */ if (texpdf_get_version() >= 4) { if (j_info.flags & HAVE_APPn_XMP) { pdf_obj *XMP_stream; XMP_stream = JPEG_get_XMP(&j_info); texpdf_add_dict(stream_dict, texpdf_new_name("Metadata"), texpdf_ref_obj(XMP_stream)); texpdf_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 { if (iccp_check_colorspace(colortype, 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 = texpdf_get_colorspace_reference(cspc_id); intent = iccp_get_rendering_intent(pdf_stream_dataptr(icc_stream), pdf_stream_length (icc_stream)); if (intent) texpdf_add_dict(stream_dict, texpdf_new_name("Intent"), intent); } } texpdf_release_obj(icc_stream); } } /* No ICC or invalid ICC profile. */ if (!colorspace) { switch (colortype) { case PDF_COLORSPACE_TYPE_GRAY: colorspace = texpdf_new_name("DeviceGray"); break; case PDF_COLORSPACE_TYPE_RGB: colorspace = texpdf_new_name("DeviceRGB"); break; case PDF_COLORSPACE_TYPE_CMYK: colorspace = texpdf_new_name("DeviceCMYK"); break; } } texpdf_add_dict(stream_dict, texpdf_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; WARN("Adobe CMYK JPEG: Inverted color assumed."); decode = texpdf_new_array(); for (i = 0; i < j_info.num_components; i++) { texpdf_add_array(decode, texpdf_new_number(1.0)); texpdf_add_array(decode, texpdf_new_number(0.0)); } texpdf_add_dict(stream_dict, texpdf_new_name("Decode"), decode); } /* Copy file */ JPEG_copy_stream(&j_info, stream, fp); info.width = j_info.width; info.height = j_info.height; info.bits_per_component = j_info.bits_per_component; info.num_components = j_info.num_components; jpeg_get_density(&j_info, &info.xdensity, &info.ydensity); texpdf_ximage_set_image(ximage, &info, stream); JPEG_info_clear(&j_info); return 0; }
pdf_obj * CMap_create_stream (CMap *cmap) { pdf_obj *stream; pdf_obj *stream_dict; CIDSysInfo *csi; struct sbuf wbuf; struct rangeDef *ranges; unsigned char *codestr; int i, j, count = 0; if (!cmap || !CMap_is_valid(cmap)) { WARN("Invalid CMap"); return NULL; } if (cmap->type == CMAP_TYPE_IDENTITY) return NULL; stream = texpdf_new_stream(STREAM_COMPRESS); stream_dict = texpdf_stream_dict(stream); csi = CMap_get_CIDSysInfo(cmap); if (!csi) { csi = (cmap->type != CMAP_TYPE_TO_UNICODE) ? &CSI_IDENTITY : &CSI_UNICODE; } if (cmap->type != CMAP_TYPE_TO_UNICODE) { pdf_obj *csi_dict; csi_dict = texpdf_new_dict(); texpdf_add_dict(csi_dict, texpdf_new_name("Registry"), texpdf_new_string(csi->registry, strlen(csi->registry))); texpdf_add_dict(csi_dict, texpdf_new_name("Ordering"), texpdf_new_string(csi->ordering, strlen(csi->ordering))); texpdf_add_dict(csi_dict, texpdf_new_name("Supplement"), texpdf_new_number(csi->supplement)); texpdf_add_dict(stream_dict, texpdf_new_name("Type"), texpdf_new_name("CMap")); texpdf_add_dict(stream_dict, texpdf_new_name("CMapName"), texpdf_new_name(cmap->name)); texpdf_add_dict(stream_dict, texpdf_new_name("CIDSystemInfo"), csi_dict); if (cmap->wmode != 0) texpdf_add_dict(stream_dict, texpdf_new_name("WMode"), texpdf_new_number(cmap->wmode)); } /* TODO: * Predefined CMaps need not to be embedded. */ if (cmap->useCMap) { ERROR("UseCMap found (not supported yet)..."); if (CMap_is_Identity(cmap->useCMap)) { /* not sure */ if (CMap_get_wmode(cmap) == 1) { texpdf_add_dict(stream_dict, texpdf_new_name("UseCMap"), texpdf_new_name("Identity-V")); } else { texpdf_add_dict(stream_dict, texpdf_new_name("UseCMap"), texpdf_new_name("Identity-H")); } } else { long res_id; pdf_obj *ucmap_ref; res_id = pdf_findresource("CMap", CMap_get_name(cmap->useCMap)); if (res_id >= 0) { ucmap_ref = texpdf_get_resource_reference(res_id); } else { pdf_obj *ucmap_obj; ucmap_obj = CMap_create_stream(cmap->useCMap); if (!ucmap_obj) { ERROR("Uh ah. I cannot continue..."); } res_id = pdf_defineresource("CMap", CMap_get_name(cmap->useCMap), ucmap_obj, PDF_RES_FLUSH_IMMEDIATE); ucmap_ref = texpdf_get_resource_reference(res_id); } texpdf_add_dict(stream_dict, texpdf_new_name("UseCMap"), ucmap_ref); } } #define WBUF_SIZE 4096 wbuf.buf = NEW(WBUF_SIZE, char); codestr = NEW(cmap->profile.maxBytesIn, unsigned char); memset(codestr, 0, cmap->profile.maxBytesIn); wbuf.curptr = wbuf.buf; wbuf.limptr = wbuf.buf + WBUF_SIZE - 2 * (cmap->profile.maxBytesIn + cmap->profile.maxBytesOut) + 16; /* Start CMap */ texpdf_add_stream(stream, (const void *) CMAP_BEGIN, strlen(CMAP_BEGIN)); wbuf.curptr += sprintf(wbuf.curptr, "/CMapName /%s def\n", cmap->name); wbuf.curptr += sprintf(wbuf.curptr, "/CMapType %d def\n" , cmap->type); if (cmap->wmode != 0 && cmap->type != CMAP_TYPE_TO_UNICODE) wbuf.curptr += sprintf(wbuf.curptr, "/WMode %d def\n", cmap->wmode); #define CMAP_CSI_FMT "/CIDSystemInfo <<\n\ /Registry (%s)\n\ /Ordering (%s)\n\ /Supplement %d\n\ >> def\n" wbuf.curptr += sprintf(wbuf.curptr, CMAP_CSI_FMT, csi->registry, csi->ordering, csi->supplement); texpdf_add_stream(stream, wbuf.buf, (long)(wbuf.curptr - wbuf.buf)); wbuf.curptr = wbuf.buf; /* codespacerange */ ranges = cmap->codespace.ranges; wbuf.curptr += sprintf(wbuf.curptr, "%d begincodespacerange\n", cmap->codespace.num); for (i = 0; i < cmap->codespace.num; i++) { *(wbuf.curptr)++ = '<'; for (j = 0; j < ranges[i].dim; j++) { sputx(ranges[i].codeLo[j], &(wbuf.curptr), wbuf.limptr); } *(wbuf.curptr)++ = '>'; *(wbuf.curptr)++ = ' '; *(wbuf.curptr)++ = '<'; for (j = 0; j < ranges[i].dim; j++) { sputx(ranges[i].codeHi[j], &(wbuf.curptr), wbuf.limptr); } *(wbuf.curptr)++ = '>'; *(wbuf.curptr)++ = '\n'; } texpdf_add_stream(stream, wbuf.buf, (long)(wbuf.curptr - wbuf.buf)); wbuf.curptr = wbuf.buf; texpdf_add_stream(stream, "endcodespacerange\n", strlen("endcodespacerange\n")); /* CMap body */ if (cmap->mapTbl) { count = write_map(cmap->mapTbl, 0, codestr, 0, &wbuf, stream); /* Top node */ if (count > 0) { /* Flush */ char fmt_buf[32]; if (count > 100) ERROR("Unexpected error....: %d", count); sprintf(fmt_buf, "%d beginbfchar\n", count); texpdf_add_stream(stream, fmt_buf, strlen(fmt_buf)); texpdf_add_stream(stream, wbuf.buf, (long) (wbuf.curptr - wbuf.buf)); texpdf_add_stream(stream, "endbfchar\n", strlen("endbfchar\n")); count = 0; wbuf.curptr = wbuf.buf; } } /* End CMap */ texpdf_add_stream(stream, CMAP_END, strlen(CMAP_END)); RELEASE(codestr); RELEASE(wbuf.buf); return stream; }