diff options
Diffstat (limited to 'source/pdf/pdf-device.c')
-rw-r--r-- | source/pdf/pdf-device.c | 444 |
1 files changed, 176 insertions, 268 deletions
diff --git a/source/pdf/pdf-device.c b/source/pdf/pdf-device.c index 85e2f27d..7cc4e5ea 100644 --- a/source/pdf/pdf-device.c +++ b/source/pdf/pdf-device.c @@ -36,14 +36,15 @@ struct gstate_s fz_matrix tm; }; -typedef struct image_entry_s image_entry; - -struct image_entry_s -{ - char digest[16]; - int id; - pdf_obj *ref; -}; +/* The image digest information, object reference, as well as indirect reference + * ID are all stored in doc->resources->image, and so they are maintained + * through the life of the document not just this page level device. As we + * encounter images on a page, we will add to the hash table if they are not + * already present. When we have an image on a particular page, the resource + * dict will be updated with the proper indirect reference across the document. + * We do need to maintain some information as to what image resources we have + * already specified for this page which is the purpose of image_indices + */ typedef struct alpha_entry_s alpha_entry; @@ -91,12 +92,17 @@ struct pdf_device_s int num_imgs; int max_imgs; - image_entry *images; + int *image_indices; + + int num_cid_fonts; + int max_cid_fonts; + int *font_indices; int num_alphas; int max_alphas; alpha_entry *alphas; + /* Base font information */ int num_fonts; int max_fonts; font_entry *fonts; @@ -109,208 +115,6 @@ struct pdf_device_s #define CURRENT_GSTATE(pdev) (&(pdev)->gstates[(pdev)->num_gstates-1]) /* Helper functions */ - -static int -send_image(fz_context *ctx, pdf_device *pdev, fz_image *image, int mask, int smask) -{ - fz_pixmap *pixmap = NULL; - pdf_obj *imobj = NULL; - pdf_obj *imref = NULL; - fz_compressed_buffer *cbuffer = NULL; - fz_compression_params *cp = NULL; - fz_buffer *buffer = NULL; - int i, num; - fz_md5 state; - unsigned char digest[16]; - fz_colorspace *colorspace = image->colorspace; - pdf_document *doc = pdev->doc; - - /* If we can maintain compression, do so */ - cbuffer = image->buffer; - - fz_var(pixmap); - fz_var(buffer); - fz_var(imobj); - fz_var(imref); - - fz_try(ctx) - { - if (cbuffer != NULL && cbuffer->params.type != FZ_IMAGE_PNG && cbuffer->params.type != FZ_IMAGE_TIFF) - { - buffer = fz_keep_buffer(ctx, cbuffer->buffer); - cp = &cbuffer->params; - } - else - { - unsigned int size; - int n; - /* Currently, set to maintain resolution; should we consider - * subsampling here according to desired output res? */ - pixmap = fz_get_pixmap_from_image(ctx, image, image->w, image->h); - colorspace = pixmap->colorspace; /* May be different to image->colorspace! */ - n = (pixmap->n == 1 ? 1 : pixmap->n-1); - size = image->w * image->h * n; - buffer = fz_new_buffer(ctx, size); - buffer->len = size; - if (pixmap->n == 1) - { - memcpy(buffer->data, pixmap->samples, size); - } - else - { - /* Need to remove the alpha plane */ - unsigned char *d = buffer->data; - unsigned char *s = pixmap->samples; - int mod = n; - while (size--) - { - *d++ = *s++; - mod--; - if (mod == 0) - s++, mod = n; - } - } - } - - fz_md5_init(&state); - fz_md5_update(&state, buffer->data, buffer->len); - fz_md5_final(&state, digest); - for(i=0; i < pdev->num_imgs; i++) - { - if (!memcmp(&digest, pdev->images[i].digest, sizeof(digest))) - { - num = i; - break; - } - } - - if (i < pdev->num_imgs) - break; - - if (pdev->num_imgs == pdev->max_imgs) - { - int newmax = pdev->max_imgs * 2; - if (newmax == 0) - newmax = 4; - pdev->images = fz_resize_array(ctx, pdev->images, newmax, sizeof(*pdev->images)); - pdev->max_imgs = newmax; - } - num = pdev->num_imgs++; - memcpy(pdev->images[num].digest,digest,16); - pdev->images[num].ref = NULL; /* Will be filled in later */ - - imobj = pdf_new_dict(ctx, doc, 3); - pdf_dict_put_drop(ctx, imobj, PDF_NAME_Type, PDF_NAME_XObject); - pdf_dict_put_drop(ctx, imobj, PDF_NAME_Subtype, PDF_NAME_Image); - pdf_dict_put_drop(ctx, imobj, PDF_NAME_Width, pdf_new_int(ctx, doc, image->w)); - pdf_dict_put_drop(ctx, imobj, PDF_NAME_Height, pdf_new_int(ctx, doc, image->h)); - if (mask) - {} - else if (!colorspace || colorspace->n == 1) - pdf_dict_put_drop(ctx, imobj, PDF_NAME_ColorSpace, PDF_NAME_DeviceGray); - else if (colorspace->n == 3) - pdf_dict_put_drop(ctx, imobj, PDF_NAME_ColorSpace, PDF_NAME_DeviceRGB); - else if (colorspace->n == 4) - pdf_dict_put_drop(ctx, imobj, PDF_NAME_ColorSpace, PDF_NAME_DeviceCMYK); - if (!mask) - pdf_dict_put_drop(ctx, imobj, PDF_NAME_BitsPerComponent, pdf_new_int(ctx, doc, image->bpc)); - switch (cp ? cp->type : FZ_IMAGE_UNKNOWN) - { - case FZ_IMAGE_UNKNOWN: /* Unknown also means raw */ - default: - break; - case FZ_IMAGE_JPEG: - if (cp->u.jpeg.color_transform != -1) - pdf_dict_put_drop(ctx, imobj, PDF_NAME_ColorTransform, pdf_new_int(ctx, doc, cp->u.jpeg.color_transform)); - pdf_dict_put_drop(ctx, imobj, PDF_NAME_Filter, PDF_NAME_DCTDecode); - break; - case FZ_IMAGE_JPX: - if (cp->u.jpx.smask_in_data) - pdf_dict_put_drop(ctx, imobj, PDF_NAME_SMaskInData, pdf_new_int(ctx, doc, cp->u.jpx.smask_in_data)); - pdf_dict_put_drop(ctx, imobj, PDF_NAME_Filter, PDF_NAME_JPXDecode); - break; - case FZ_IMAGE_FAX: - if (cp->u.fax.columns) - pdf_dict_put_drop(ctx, imobj, PDF_NAME_Columns, pdf_new_int(ctx, doc, cp->u.fax.columns)); - if (cp->u.fax.rows) - pdf_dict_put_drop(ctx, imobj, PDF_NAME_Rows, pdf_new_int(ctx, doc, cp->u.fax.rows)); - if (cp->u.fax.k) - pdf_dict_put_drop(ctx, imobj, PDF_NAME_K, pdf_new_int(ctx, doc, cp->u.fax.k)); - if (cp->u.fax.end_of_line) - pdf_dict_put_drop(ctx, imobj, PDF_NAME_EndOfLine, pdf_new_int(ctx, doc, cp->u.fax.end_of_line)); - if (cp->u.fax.encoded_byte_align) - pdf_dict_put_drop(ctx, imobj, PDF_NAME_EncodedByteAlign, pdf_new_int(ctx, doc, cp->u.fax.encoded_byte_align)); - if (cp->u.fax.end_of_block) - pdf_dict_put_drop(ctx, imobj, PDF_NAME_EndOfBlock, pdf_new_int(ctx, doc, cp->u.fax.end_of_block)); - if (cp->u.fax.black_is_1) - pdf_dict_put_drop(ctx, imobj, PDF_NAME_BlackIs1, pdf_new_int(ctx, doc, cp->u.fax.black_is_1)); - if (cp->u.fax.damaged_rows_before_error) - pdf_dict_put_drop(ctx, imobj, PDF_NAME_DamagedRowsBeforeError, pdf_new_int(ctx, doc, cp->u.fax.damaged_rows_before_error)); - pdf_dict_put_drop(ctx, imobj, PDF_NAME_Filter, PDF_NAME_CCITTFaxDecode); - break; - case FZ_IMAGE_JBIG2: - /* FIXME - jbig2globals */ - cp->type = FZ_IMAGE_UNKNOWN; - break; - case FZ_IMAGE_FLATE: - if (cp->u.flate.columns) - pdf_dict_put_drop(ctx, imobj, PDF_NAME_Columns, pdf_new_int(ctx, doc, cp->u.flate.columns)); - if (cp->u.flate.colors) - pdf_dict_put_drop(ctx, imobj, PDF_NAME_Colors, pdf_new_int(ctx, doc, cp->u.flate.colors)); - if (cp->u.flate.predictor) - pdf_dict_put_drop(ctx, imobj, PDF_NAME_Predictor, pdf_new_int(ctx, doc, cp->u.flate.predictor)); - pdf_dict_put_drop(ctx, imobj, PDF_NAME_Filter, PDF_NAME_FlateDecode); - pdf_dict_put_drop(ctx, imobj, PDF_NAME_BitsPerComponent, pdf_new_int(ctx, doc, image->bpc)); - break; - case FZ_IMAGE_LZW: - if (cp->u.lzw.columns) - pdf_dict_put_drop(ctx, imobj, PDF_NAME_Columns, pdf_new_int(ctx, doc, cp->u.lzw.columns)); - if (cp->u.lzw.colors) - pdf_dict_put_drop(ctx, imobj, PDF_NAME_Colors, pdf_new_int(ctx, doc, cp->u.lzw.colors)); - if (cp->u.lzw.predictor) - pdf_dict_put_drop(ctx, imobj, PDF_NAME_Predictor, pdf_new_int(ctx, doc, cp->u.lzw.predictor)); - if (cp->u.lzw.early_change) - pdf_dict_put_drop(ctx, imobj, PDF_NAME_EarlyChange, pdf_new_int(ctx, doc, cp->u.lzw.early_change)); - pdf_dict_put_drop(ctx, imobj, PDF_NAME_Filter, PDF_NAME_LZWDecode); - break; - case FZ_IMAGE_RLD: - pdf_dict_put_drop(ctx, imobj, PDF_NAME_Filter, PDF_NAME_RunLengthDecode); - break; - } - if (mask) - { - pdf_dict_put_drop(ctx, imobj, PDF_NAME_ImageMask, pdf_new_bool(ctx, doc, 1)); - } - if (image->mask) - { - int smasknum = send_image(ctx, pdev, image->mask, 0, 1); - pdf_dict_put(ctx, imobj, PDF_NAME_SMask, pdev->images[smasknum].ref); - } - - imref = pdf_new_ref(ctx, doc, imobj); - pdf_update_stream(ctx, doc, imref, buffer, 1); - - { - char text[32]; - snprintf(text, sizeof(text), "XObject/Img%d", num); - pdf_dict_putp(ctx, pdev->resources, text, imref); - } - pdev->images[num].ref = imref; - } - fz_always(ctx) - { - fz_drop_buffer(ctx, buffer); - pdf_drop_obj(ctx, imobj); - fz_drop_pixmap(ctx, pixmap); - } - fz_catch(ctx) - { - pdf_drop_obj(ctx, imref); - fz_rethrow(ctx); - } - return num; -} - static void pdf_dev_stroke_state(fz_context *ctx, pdf_device *pdev, const fz_stroke_state *stroke_state) { @@ -550,66 +354,116 @@ pdf_dev_alpha(fz_context *ctx, pdf_device *pdev, float alpha, int stroke) } static void +pdf_dev_add_font_res(fz_context *ctx, fz_device *dev, pdf_res *fres) +{ + char text[32]; + pdf_device *pdev = (pdf_device*)dev; + int k; + int num; + + /* Check if we already had this one */ + for (k = 0; k < pdev->num_cid_fonts; k++) + { + if (pdev->font_indices[k] == fres->num) + return; + } + + /* Not there so add to resources */ + snprintf(text, sizeof(text), "Font/F%d", fres->num); + pdf_dict_putp(ctx, pdev->resources, text, fres->obj); + + /* And add index to our list for this page */ + if (pdev->num_cid_fonts == pdev->max_cid_fonts) + { + int newmax = pdev->max_cid_fonts * 2; + if (newmax == 0) + newmax = 4; + pdev->font_indices = fz_resize_array(ctx, pdev->image_indices, newmax, sizeof(*pdev->font_indices)); + pdev->max_cid_fonts = newmax; + } + num = pdev->num_cid_fonts++; + pdev->font_indices[num] = fres->num; +} + +static void pdf_dev_font(fz_context *ctx, pdf_device *pdev, fz_font *font, float size) { int i; pdf_document *doc = pdev->doc; gstate *gs = CURRENT_GSTATE(pdev); + pdf_res *fres; /* If the font is unchanged, nothing to do */ if (gs->font >= 0 && pdev->fonts[gs->font].font == font) return; - if (font->ft_buffer != NULL || font->ft_substitute) - fz_throw(ctx, FZ_ERROR_GENERIC, "pdf device supports only base 14 fonts currently"); + if (font->ft_substitute) + fz_throw(ctx, FZ_ERROR_GENERIC, "pdf device does not support substitute metrics"); - /* Have we sent such a font before? */ - for (i = 0; i < pdev->num_fonts; i++) - if (pdev->fonts[i].font == font) - break; + if (font->ft_buffer != NULL && !pdf_font_writing_supported(font)) + fz_throw(ctx, FZ_ERROR_GENERIC, "pdf device does not support font types found in this file"); - if (i == pdev->num_fonts) + if (font->ft_buffer != NULL) { - pdf_obj *o; - pdf_obj *ref = NULL; + /* This will add it to the xref if needed */ + fres = pdf_add_cid_font_res(ctx, doc, font->ft_buffer, font); + fz_buffer_printf(ctx, gs->buf, "/F%d %f Tf\n", fres->num, size); - fz_var(ref); + /* Possibly add to page resources */ + pdf_dev_add_font_res(ctx, (fz_device*) pdev, fres); + pdf_drop_obj(ctx, fres->obj); + } + else + { + /* Have the device handle the base fonts */ + /* Have we sent such a font before? */ + for (i = 0; i < pdev->num_fonts; i++) + if (pdev->fonts[i].font == font) + break; - /* No. Need to make a new one */ - if (pdev->num_fonts == pdev->max_fonts) + if (i == pdev->num_fonts) { - int newmax = pdev->max_fonts * 2; - if (newmax == 0) - newmax = 4; - pdev->fonts = fz_resize_array(ctx, pdev->fonts, newmax, sizeof(*pdev->fonts)); - pdev->max_fonts = newmax; - } - pdev->fonts[i].font = fz_keep_font(ctx, font); + pdf_obj *o; + pdf_obj *ref = NULL; - o = pdf_new_dict(ctx, doc, 3); - fz_try(ctx) - { - char text[32]; - pdf_dict_put_drop(ctx, o, PDF_NAME_Type, PDF_NAME_Font); - pdf_dict_put_drop(ctx, o, PDF_NAME_Subtype, PDF_NAME_Type1); - pdf_dict_put_drop(ctx, o, PDF_NAME_BaseFont, pdf_new_name(ctx, doc, font->name)); - pdf_dict_put_drop(ctx, o, PDF_NAME_Encoding, PDF_NAME_WinAnsiEncoding); - ref = pdf_new_ref(ctx, doc, o); - snprintf(text, sizeof(text), "Font/F%d", i); - pdf_dict_putp(ctx, pdev->resources, text, ref); - } - fz_always(ctx) - { - pdf_drop_obj(ctx, o); - pdf_drop_obj(ctx, ref); - } - fz_catch(ctx) - { - fz_rethrow(ctx); + fz_var(ref); + + /* No. Need to make a new one */ + if (pdev->num_fonts == pdev->max_fonts) + { + int newmax = pdev->max_fonts * 2; + if (newmax == 0) + newmax = 4; + pdev->fonts = fz_resize_array(ctx, pdev->fonts, newmax, sizeof(*pdev->fonts)); + pdev->max_fonts = newmax; + } + pdev->fonts[i].font = fz_keep_font(ctx, font); + + o = pdf_new_dict(ctx, doc, 3); + fz_try(ctx) + { + char text[32]; + pdf_dict_put_drop(ctx, o, PDF_NAME_Type, PDF_NAME_Font); + pdf_dict_put_drop(ctx, o, PDF_NAME_Subtype, PDF_NAME_Type1); + pdf_dict_put_drop(ctx, o, PDF_NAME_BaseFont, pdf_new_name(ctx, doc, font->name)); + pdf_dict_put_drop(ctx, o, PDF_NAME_Encoding, PDF_NAME_WinAnsiEncoding); + ref = pdf_new_ref(ctx, doc, o); + snprintf(text, sizeof(text), "Font/Fb%d", i); + pdf_dict_putp(ctx, pdev->resources, text, ref); + } + fz_always(ctx) + { + pdf_drop_obj(ctx, o); + pdf_drop_obj(ctx, ref); + } + fz_catch(ctx) + { + fz_rethrow(ctx); + } + pdev->num_fonts++; } - pdev->num_fonts++; + fz_buffer_printf(ctx, gs->buf, "/Fb%d %f Tf\n", i, size); } - fz_buffer_printf(ctx, gs->buf, "/F%d %f Tf\n", i, size); } static void @@ -721,11 +575,21 @@ pdf_dev_text_span(fz_context *ctx, pdf_device *pdev, fz_text_span *span, float s } fz_buffer_printf(ctx, gs->buf, "<"); - for (/* i from its current value */; i < j; i++) + if (span->font->ft_buffer == NULL) + { + /* A standard 14 type font */ + for (/* i from its current value */; i < j; i++) + { + fz_buffer_printf(ctx, gs->buf, "%02x", span->items[i].ucs); + } + } + else { - /* FIXME: should use it->gid, rather than it->ucs, and convert - * to the correct encoding */ - fz_buffer_printf(ctx, gs->buf, "%02x", span->items[i].ucs); + /* Non-standard font. Saved as Type0 Identity-H */ + for (/* i from its current value */; i < j; i++) + { + fz_buffer_printf(ctx, gs->buf, "%04x", span->items[i].gid); + } } fz_buffer_printf(ctx, gs->buf, "> Tj\n"); } @@ -1040,21 +904,63 @@ pdf_dev_ignore_text(fz_context *ctx, fz_device *dev, const fz_text *text, const } static void -pdf_dev_fill_image(fz_context *ctx, fz_device *dev, fz_image *image, const fz_matrix *ctm, float alpha) +pdf_dev_add_image_res(fz_context *ctx, fz_device *dev, pdf_res *im_res) { + char text[32]; pdf_device *pdev = (pdf_device*)dev; + int k; int num; + + /* Check if we already had this one */ + for (k = 0; k < pdev->num_imgs; k++) + { + if (pdev->image_indices[k] == im_res->num) + return; + } + + /* Not there so add to resources */ + snprintf(text, sizeof(text), "XObject/Img%d", im_res->num); + pdf_dict_putp(ctx, pdev->resources, text, im_res->obj); + + /* And add index to our list for this page */ + if (pdev->num_imgs == pdev->max_imgs) + { + int newmax = pdev->max_imgs * 2; + if (newmax == 0) + newmax = 4; + pdev->image_indices = fz_resize_array(ctx, pdev->image_indices, newmax, sizeof(*pdev->image_indices)); + pdev->max_imgs = newmax; + } + num = pdev->num_imgs++; + pdev->image_indices[num] = im_res->num; +} + +static void +pdf_dev_fill_image(fz_context *ctx, fz_device *dev, fz_image *image, const fz_matrix *ctm, float alpha) +{ + pdf_device *pdev = (pdf_device*)dev; + pdf_res *im_res; gstate *gs = CURRENT_GSTATE(pdev); fz_matrix local_ctm = *ctm; pdf_dev_end_text(ctx, pdev); - num = send_image(ctx, pdev, image, 0, 0); + im_res = pdf_add_image_res(ctx, pdev->doc, image, 0); + if (im_res == NULL) + { + fz_warn(ctx, "pdf_add_image_res: problem adding image resource"); + return; + } pdf_dev_alpha(ctx, pdev, alpha, 0); + /* PDF images are upside down, so fiddle the ctm */ fz_pre_scale(&local_ctm, 1, -1); fz_pre_translate(&local_ctm, 0, -1); pdf_dev_ctm(ctx, pdev, &local_ctm); - fz_buffer_printf(ctx, gs->buf, "/Img%d Do\n", num); + fz_buffer_printf(ctx, gs->buf, "/Img%d Do\n", im_res->num); + + /* Possibly add to page resources */ + pdf_dev_add_image_res(ctx, dev, im_res); + pdf_drop_obj(ctx, im_res->obj); } static void @@ -1071,20 +977,26 @@ pdf_dev_fill_image_mask(fz_context *ctx, fz_device *dev, fz_image *image, const fz_colorspace *colorspace, const float *color, float alpha) { pdf_device *pdev = (pdf_device*)dev; + pdf_res* im_res = NULL; gstate *gs = CURRENT_GSTATE(pdev); - int num; fz_matrix local_ctm = *ctm; pdf_dev_end_text(ctx, pdev); - num = send_image(ctx, pdev, image, 1, 0); + im_res = pdf_add_image_res(ctx, pdev->doc, image, 1); + if (im_res == NULL) + { + fz_warn(ctx, "pdf_add_image_res: problem adding image resource"); + return; + } fz_buffer_printf(ctx, gs->buf, "q\n"); pdf_dev_alpha(ctx, pdev, alpha, 0); pdf_dev_color(ctx, pdev, colorspace, color, 0); + /* PDF images are upside down, so fiddle the ctm */ fz_pre_scale(&local_ctm, 1, -1); fz_pre_translate(&local_ctm, 0, -1); pdf_dev_ctm(ctx, pdev, &local_ctm); - fz_buffer_printf(ctx, gs->buf, "/Img%d Do Q\n", num); + fz_buffer_printf(ctx, gs->buf, "/Img%d Do Q\n", im_res->num); } static void @@ -1283,11 +1195,6 @@ pdf_dev_drop_imp(fz_context *ctx, fz_device *dev) fz_drop_font(ctx, pdev->fonts[i].font); } - for (i = pdev->num_imgs-1; i >= 0; i--) - { - pdf_drop_obj(ctx, pdev->images[i].ref); - } - for (i = pdev->num_groups - 1; i >= 0; i--) { pdf_drop_obj(ctx, pdev->groups[i].ref); @@ -1306,9 +1213,10 @@ pdf_dev_drop_imp(fz_context *ctx, fz_device *dev) pdf_drop_obj(ctx, pdev->resources); + fz_free(ctx, pdev->font_indices); + fz_free(ctx, pdev->image_indices); fz_free(ctx, pdev->groups); fz_free(ctx, pdev->fonts); - fz_free(ctx, pdev->images); fz_free(ctx, pdev->alphas); fz_free(ctx, pdev->gstates); } |