fz_image * fz_new_image_from_data(fz_context *ctx, unsigned char *data, int len) { fz_buffer *buffer = NULL; fz_image *image; fz_var(buffer); fz_var(data); fz_try(ctx) { buffer = fz_new_buffer_from_data(ctx, data, len); data = NULL; image = fz_new_image_from_buffer(ctx, buffer); } fz_always(ctx) { fz_drop_buffer(ctx, buffer); } fz_catch(ctx) { fz_free(ctx, data); fz_rethrow(ctx); } return image; }
/* SumatraPDF: allow to clone a stream */ static fz_stream *reopen_buffer(fz_context *ctx, fz_stream *stm) { fz_stream *clone; fz_buffer *orig = stm->state; fz_buffer *buf = fz_new_buffer_from_data(ctx, orig->data, orig->len); clone = fz_open_buffer(ctx, buf); fz_drop_buffer(ctx, buf); return clone; }
fz_font * xps_lookup_font(fz_context *ctx, xps_document *doc, char *base_uri, char *font_uri, char *style_att) { char partname[1024]; char fakename[1024]; char *subfont; int subfontid = 0; xps_part *part; fz_font *font; xps_resolve_url(ctx, doc, partname, base_uri, font_uri, sizeof partname); subfont = strrchr(partname, '#'); if (subfont) { subfontid = atoi(subfont + 1); *subfont = 0; } /* Make a new part name for font with style simulation applied */ fz_strlcpy(fakename, partname, sizeof fakename); if (style_att) { if (!strcmp(style_att, "BoldSimulation")) fz_strlcat(fakename, "#Bold", sizeof fakename); else if (!strcmp(style_att, "ItalicSimulation")) fz_strlcat(fakename, "#Italic", sizeof fakename); else if (!strcmp(style_att, "BoldItalicSimulation")) fz_strlcat(fakename, "#BoldItalic", sizeof fakename); } font = xps_lookup_font_imp(ctx, doc, fakename); if (!font) { fz_buffer *buf = NULL; fz_var(buf); fz_try(ctx) { part = xps_read_part(ctx, doc, partname); } fz_catch(ctx) { fz_rethrow_if(ctx, FZ_ERROR_TRYLATER); fz_warn(ctx, "cannot find font resource part '%s'", partname); return NULL; } /* deobfuscate if necessary */ if (strstr(part->name, ".odttf")) xps_deobfuscate_font_resource(ctx, doc, part); if (strstr(part->name, ".ODTTF")) xps_deobfuscate_font_resource(ctx, doc, part); fz_try(ctx) { buf = fz_new_buffer_from_data(ctx, part->data, part->size); /* part->data is now owned by buf */ part->data = NULL; font = fz_new_font_from_buffer(ctx, NULL, buf, subfontid, 1); } fz_always(ctx) { fz_drop_buffer(ctx, buf); xps_drop_part(ctx, doc, part); } fz_catch(ctx) { fz_rethrow_if(ctx, FZ_ERROR_TRYLATER); fz_warn(ctx, "cannot load font resource '%s'", partname); return NULL; } if (style_att) { font->ft_bold = !!strstr(style_att, "Bold"); font->ft_italic = !!strstr(style_att, "Italic"); } xps_select_best_font_encoding(ctx, doc, font); xps_insert_font(ctx, doc, fakename, font); }
void xps_parse_glyphs(fz_context *ctx, xps_document *doc, const fz_matrix *ctm, char *base_uri, xps_resource *dict, fz_xml *root) { fz_device *dev = doc->dev; fz_xml *node; char *fill_uri; char *opacity_mask_uri; char *bidi_level_att; char *fill_att; char *font_size_att; char *font_uri_att; char *origin_x_att; char *origin_y_att; char *is_sideways_att; char *indices_att; char *unicode_att; char *style_att; char *transform_att; char *clip_att; char *opacity_att; char *opacity_mask_att; char *navigate_uri_att; fz_xml *transform_tag = NULL; fz_xml *clip_tag = NULL; fz_xml *fill_tag = NULL; fz_xml *opacity_mask_tag = NULL; char *fill_opacity_att = NULL; xps_part *part; fz_font *font; char partname[1024]; char fakename[1024]; char *subfont; float font_size = 10; int subfontid = 0; int is_sideways = 0; int bidi_level = 0; fz_text *text; fz_rect area; fz_matrix local_ctm = *ctm; /* * Extract attributes and extended attributes. */ bidi_level_att = fz_xml_att(root, "BidiLevel"); fill_att = fz_xml_att(root, "Fill"); font_size_att = fz_xml_att(root, "FontRenderingEmSize"); font_uri_att = fz_xml_att(root, "FontUri"); origin_x_att = fz_xml_att(root, "OriginX"); origin_y_att = fz_xml_att(root, "OriginY"); is_sideways_att = fz_xml_att(root, "IsSideways"); indices_att = fz_xml_att(root, "Indices"); unicode_att = fz_xml_att(root, "UnicodeString"); style_att = fz_xml_att(root, "StyleSimulations"); transform_att = fz_xml_att(root, "RenderTransform"); clip_att = fz_xml_att(root, "Clip"); opacity_att = fz_xml_att(root, "Opacity"); opacity_mask_att = fz_xml_att(root, "OpacityMask"); navigate_uri_att = fz_xml_att(root, "FixedPage.NavigateUri"); for (node = fz_xml_down(root); node; node = fz_xml_next(node)) { if (fz_xml_is_tag(node, "Glyphs.RenderTransform")) transform_tag = fz_xml_down(node); if (fz_xml_is_tag(node, "Glyphs.OpacityMask")) opacity_mask_tag = fz_xml_down(node); if (fz_xml_is_tag(node, "Glyphs.Clip")) clip_tag = fz_xml_down(node); if (fz_xml_is_tag(node, "Glyphs.Fill")) fill_tag = fz_xml_down(node); } fill_uri = base_uri; opacity_mask_uri = base_uri; xps_resolve_resource_reference(ctx, doc, dict, &transform_att, &transform_tag, NULL); xps_resolve_resource_reference(ctx, doc, dict, &clip_att, &clip_tag, NULL); xps_resolve_resource_reference(ctx, doc, dict, &fill_att, &fill_tag, &fill_uri); xps_resolve_resource_reference(ctx, doc, dict, &opacity_mask_att, &opacity_mask_tag, &opacity_mask_uri); /* * Check that we have all the necessary information. */ if (!font_size_att || !font_uri_att || !origin_x_att || !origin_y_att) { fz_warn(ctx, "missing attributes in glyphs element"); return; } if (!indices_att && !unicode_att) return; /* nothing to draw */ if (is_sideways_att) is_sideways = !strcmp(is_sideways_att, "true"); if (bidi_level_att) bidi_level = atoi(bidi_level_att); /* * Find and load the font resource */ xps_resolve_url(ctx, doc, partname, base_uri, font_uri_att, sizeof partname); subfont = strrchr(partname, '#'); if (subfont) { subfontid = atoi(subfont + 1); *subfont = 0; } /* Make a new part name for font with style simulation applied */ fz_strlcpy(fakename, partname, sizeof fakename); if (style_att) { if (!strcmp(style_att, "BoldSimulation")) fz_strlcat(fakename, "#Bold", sizeof fakename); else if (!strcmp(style_att, "ItalicSimulation")) fz_strlcat(fakename, "#Italic", sizeof fakename); else if (!strcmp(style_att, "BoldItalicSimulation")) fz_strlcat(fakename, "#BoldItalic", sizeof fakename); } font = xps_lookup_font(ctx, doc, fakename); if (!font) { fz_buffer *buf = NULL; fz_var(buf); fz_try(ctx) { part = xps_read_part(ctx, doc, partname); } fz_catch(ctx) { fz_rethrow_if(ctx, FZ_ERROR_TRYLATER); fz_warn(ctx, "cannot find font resource part '%s'", partname); return; } /* deobfuscate if necessary */ if (strstr(part->name, ".odttf")) xps_deobfuscate_font_resource(ctx, doc, part); if (strstr(part->name, ".ODTTF")) xps_deobfuscate_font_resource(ctx, doc, part); fz_try(ctx) { buf = fz_new_buffer_from_data(ctx, part->data, part->size); /* part->data is now owned by buf */ part->data = NULL; font = fz_new_font_from_buffer(ctx, NULL, buf, subfontid, 1); } fz_always(ctx) { fz_drop_buffer(ctx, buf); xps_drop_part(ctx, doc, part); } fz_catch(ctx) { fz_rethrow_if(ctx, FZ_ERROR_TRYLATER); fz_warn(ctx, "cannot load font resource '%s'", partname); return; } if (style_att) { font->ft_bold = !!strstr(style_att, "Bold"); font->ft_italic = !!strstr(style_att, "Italic"); } xps_select_best_font_encoding(ctx, doc, font); xps_insert_font(ctx, doc, fakename, font); }
pdf_obj * pdf_add_image(fz_context *ctx, pdf_document *doc, fz_image *image) { fz_pixmap *pixmap = NULL; pdf_obj *imobj = NULL; pdf_obj *dp; fz_buffer *buffer = NULL; pdf_obj *imref = NULL; fz_compressed_buffer *cbuffer; unsigned char digest[16]; int i, n; /* If we can maintain compression, do so */ cbuffer = fz_compressed_image_buffer(ctx, image); fz_var(pixmap); fz_var(buffer); fz_var(imobj); fz_var(imref); /* Check if the same image already exists in this doc. */ imref = pdf_find_image_resource(ctx, doc, image, digest); if (imref) return imref; imobj = pdf_add_new_dict(ctx, doc, 3); fz_try(ctx) { dp = pdf_dict_put_dict(ctx, imobj, PDF_NAME(DecodeParms), 3); pdf_dict_put(ctx, imobj, PDF_NAME(Type), PDF_NAME(XObject)); pdf_dict_put(ctx, imobj, PDF_NAME(Subtype), PDF_NAME(Image)); if (cbuffer) { fz_compression_params *cp = &cbuffer->params; switch (cp ? cp->type : FZ_IMAGE_UNKNOWN) { default: goto raw_or_unknown_compression; case FZ_IMAGE_JPEG: if (cp->u.jpeg.color_transform != -1) pdf_dict_put_int(ctx, dp, PDF_NAME(ColorTransform), cp->u.jpeg.color_transform); pdf_dict_put(ctx, imobj, PDF_NAME(Filter), PDF_NAME(DCTDecode)); break; case FZ_IMAGE_JPX: if (cp->u.jpx.smask_in_data) pdf_dict_put_int(ctx, dp, PDF_NAME(SMaskInData), cp->u.jpx.smask_in_data); pdf_dict_put(ctx, imobj, PDF_NAME(Filter), PDF_NAME(JPXDecode)); break; case FZ_IMAGE_FAX: if (cp->u.fax.columns) pdf_dict_put_int(ctx, dp, PDF_NAME(Columns), cp->u.fax.columns); if (cp->u.fax.rows) pdf_dict_put_int(ctx, dp, PDF_NAME(Rows), cp->u.fax.rows); if (cp->u.fax.k) pdf_dict_put_int(ctx, dp, PDF_NAME(K), cp->u.fax.k); if (cp->u.fax.end_of_line) pdf_dict_put_bool(ctx, dp, PDF_NAME(EndOfLine), cp->u.fax.end_of_line); if (cp->u.fax.encoded_byte_align) pdf_dict_put_bool(ctx, dp, PDF_NAME(EncodedByteAlign), cp->u.fax.encoded_byte_align); if (cp->u.fax.end_of_block) pdf_dict_put_bool(ctx, dp, PDF_NAME(EndOfBlock), cp->u.fax.end_of_block); if (cp->u.fax.black_is_1) pdf_dict_put_bool(ctx, dp, PDF_NAME(BlackIs1), cp->u.fax.black_is_1); if (cp->u.fax.damaged_rows_before_error) pdf_dict_put_int(ctx, dp, PDF_NAME(DamagedRowsBeforeError), cp->u.fax.damaged_rows_before_error); pdf_dict_put(ctx, imobj, PDF_NAME(Filter), PDF_NAME(CCITTFaxDecode)); break; case FZ_IMAGE_FLATE: if (cp->u.flate.columns) pdf_dict_put_int(ctx, dp, PDF_NAME(Columns), cp->u.flate.columns); if (cp->u.flate.colors) pdf_dict_put_int(ctx, dp, PDF_NAME(Colors), cp->u.flate.colors); if (cp->u.flate.predictor) pdf_dict_put_int(ctx, dp, PDF_NAME(Predictor), cp->u.flate.predictor); if (cp->u.flate.bpc) pdf_dict_put_int(ctx, dp, PDF_NAME(BitsPerComponent), cp->u.flate.bpc); pdf_dict_put(ctx, imobj, PDF_NAME(Filter), PDF_NAME(FlateDecode)); pdf_dict_put_int(ctx, imobj, PDF_NAME(BitsPerComponent), image->bpc); break; case FZ_IMAGE_LZW: if (cp->u.lzw.columns) pdf_dict_put_int(ctx, dp, PDF_NAME(Columns), cp->u.lzw.columns); if (cp->u.lzw.colors) pdf_dict_put_int(ctx, dp, PDF_NAME(Colors), cp->u.lzw.colors); if (cp->u.lzw.predictor) pdf_dict_put_int(ctx, dp, PDF_NAME(Predictor), cp->u.lzw.predictor); if (cp->u.lzw.early_change) pdf_dict_put_int(ctx, dp, PDF_NAME(EarlyChange), cp->u.lzw.early_change); if (cp->u.lzw.bpc) pdf_dict_put_int(ctx, dp, PDF_NAME(BitsPerComponent), cp->u.lzw.bpc); pdf_dict_put(ctx, imobj, PDF_NAME(Filter), PDF_NAME(LZWDecode)); break; case FZ_IMAGE_RLD: pdf_dict_put(ctx, imobj, PDF_NAME(Filter), PDF_NAME(RunLengthDecode)); break; } if (!pdf_dict_len(ctx, dp)) pdf_dict_del(ctx, imobj, PDF_NAME(DecodeParms)); buffer = fz_keep_buffer(ctx, cbuffer->buffer); if (image->use_decode) { pdf_obj *ary = pdf_dict_put_array(ctx, imobj, PDF_NAME(Decode), image->n * 2); for (i = 0; i < image->n * 2; ++i) pdf_array_push_real(ctx, ary, image->decode[i]); } } else { unsigned int size; int h; unsigned char *d, *s; raw_or_unknown_compression: /* Currently, set to maintain resolution; should we consider * subsampling here according to desired output res? */ pixmap = fz_get_pixmap_from_image(ctx, image, NULL, NULL, NULL, NULL); n = pixmap->n - pixmap->alpha - pixmap->s; /* number of colorants */ if (n == 0) n = 1; /* treat pixmaps with only alpha or spots as grayscale */ size = image->w * n; h = image->h; s = pixmap->samples; d = fz_malloc(ctx, size * h); buffer = fz_new_buffer_from_data(ctx, d, size * h); if (n == pixmap->n) { /* If we use all channels, we can copy the data as is. */ while (h--) { memcpy(d, s, size); d += size; s += pixmap->stride; } } else { /* Need to remove the alpha and spot planes. */ /* TODO: extract alpha plane to a soft mask. */ /* TODO: convert spots to colors. */ int line_skip = pixmap->stride - pixmap->w * pixmap->n; int skip = pixmap->n - n; while (h--) { int w = pixmap->w; while (w--) { int k; for (k = 0; k < n; ++k) *d++ = *s++; s += skip; } s += line_skip; } } } pdf_dict_put_int(ctx, imobj, PDF_NAME(Width), pixmap ? pixmap->w : image->w); pdf_dict_put_int(ctx, imobj, PDF_NAME(Height), pixmap ? pixmap->h : image->h); if (image->imagemask) { pdf_dict_put_bool(ctx, imobj, PDF_NAME(ImageMask), 1); } else { fz_colorspace *cs; pdf_dict_put_int(ctx, imobj, PDF_NAME(BitsPerComponent), image->bpc); cs = pixmap ? pixmap->colorspace : image->colorspace; switch (fz_colorspace_type(ctx, cs)) { case FZ_COLORSPACE_INDEXED: { fz_colorspace *basecs; unsigned char *lookup = NULL; int high = 0; int basen; pdf_obj *arr; lookup = fz_indexed_colorspace_palette(ctx, cs, &high); basecs = fz_colorspace_base(ctx, cs); basen = fz_colorspace_n(ctx, basecs); arr = pdf_dict_put_array(ctx, imobj, PDF_NAME(ColorSpace), 4); pdf_array_push(ctx, arr, PDF_NAME(Indexed)); switch (fz_colorspace_type(ctx, basecs)) { case FZ_COLORSPACE_GRAY: pdf_array_push(ctx, arr, PDF_NAME(DeviceGray)); break; case FZ_COLORSPACE_RGB: pdf_array_push(ctx, arr, PDF_NAME(DeviceRGB)); break; case FZ_COLORSPACE_CMYK: pdf_array_push(ctx, arr, PDF_NAME(DeviceCMYK)); break; default: // TODO: convert to RGB! fz_throw(ctx, FZ_ERROR_GENERIC, "only indexed Gray, RGB, and CMYK colorspaces supported"); break; } pdf_array_push_int(ctx, arr, high); pdf_array_push_string(ctx, arr, (char *) lookup, basen * (high + 1)); } break; case FZ_COLORSPACE_NONE: case FZ_COLORSPACE_GRAY: pdf_dict_put(ctx, imobj, PDF_NAME(ColorSpace), PDF_NAME(DeviceGray)); break; case FZ_COLORSPACE_RGB: pdf_dict_put(ctx, imobj, PDF_NAME(ColorSpace), PDF_NAME(DeviceRGB)); break; case FZ_COLORSPACE_CMYK: pdf_dict_put(ctx, imobj, PDF_NAME(ColorSpace), PDF_NAME(DeviceCMYK)); break; default: // TODO: convert to RGB! fz_throw(ctx, FZ_ERROR_GENERIC, "only Gray, RGB, and CMYK colorspaces supported"); break; } } if (image->mask) { pdf_dict_put_drop(ctx, imobj, PDF_NAME(SMask), pdf_add_image(ctx, doc, image->mask)); } pdf_update_stream(ctx, doc, imobj, buffer, 1); /* Add ref to our image resource hash table. */ imref = pdf_insert_image_resource(ctx, doc, digest, imobj); } fz_always(ctx) { fz_drop_pixmap(ctx, pixmap); fz_drop_buffer(ctx, buffer); pdf_drop_obj(ctx, imobj); } fz_catch(ctx) fz_rethrow(ctx); return imref; }