Beispiel #1
0
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;
}
Beispiel #2
0
/* 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;
}
Beispiel #3
0
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);
    }
Beispiel #4
0
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);
	}
Beispiel #5
0
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;
}