Example #1
0
/* cf. http://code.google.com/p/sumatrapdf/issues/detail?id=1333 */
static fz_pixmap *
decomp_image_banded(fz_context *ctx, fz_stream *stm, fz_image *image, int indexed, int l2factor, int native_l2factor)
{
	fz_pixmap *tile = NULL, *part = NULL;
	int w = (image->w + (1 << l2factor) - 1) >> l2factor;
	int h = (image->h + (1 << l2factor) - 1) >> l2factor;
	int part_h, orig_h = image->h;
	int band = 1 << fz_maxi(8, l2factor);

	fz_var(tile);
	fz_var(part);

	fz_try(ctx)
	{
		fz_colorspace *cs = image->colorspace;
		if (indexed)
			cs = *(fz_colorspace **)cs->data; // cf. struct indexed in res_colorspace.c
		tile = fz_new_pixmap(ctx, cs, w, h);
		tile->interpolate = image->interpolate;
		tile->has_alpha = 0; /* SumatraPDF: allow optimizing non-alpha pixmaps */
		/* decompress the image in bands of 256 lines */
		for (part_h = h; part_h > 0; part_h -= band >> l2factor)
		{
			image->h = part_h > band >> l2factor ? band : ((orig_h - 1) % band) + 1;
			part = fz_decomp_image_from_stream(ctx, fz_keep_stream(stm), image, -1 - indexed, l2factor, native_l2factor);
			memcpy(tile->samples + (h - part_h) * tile->w * tile->n, part->samples, part->h * part->w * part->n);
			tile->has_alpha |= part->has_alpha; /* SumatraPDF: allow optimizing non-alpha pixmaps */
			fz_drop_pixmap(ctx, part);
			part = NULL;
		}
		/* cf. http://bugs.ghostscript.com/show_bug.cgi?id=693517 */
		if (image->usecolorkey && image->mask)
			fz_unblend_masked_tile(ctx, tile, image);
	}
	fz_always(ctx)
	{
		image->h = orig_h;
		fz_close(stm);
	}
	fz_catch(ctx)
	{
		fz_drop_pixmap(ctx, part);
		fz_drop_pixmap(ctx, tile);
		fz_rethrow(ctx);
	}

	return tile;
}
Example #2
0
void
pdf_load_compressed_inline_image(fz_context *ctx, pdf_document *doc, pdf_obj *dict, int length, fz_stream *stm, int indexed, fz_image *image)
{
	fz_compressed_buffer *bc = fz_malloc_struct(ctx, fz_compressed_buffer);

	fz_try(ctx)
	{
		int dummy_l2factor = 0;
		bc->buffer = fz_new_buffer(ctx, 1024);

		stm = pdf_open_inline_stream(ctx, doc, dict, length, stm, &bc->params);
		stm = fz_open_leecher(ctx, stm, bc->buffer);
		stm = fz_open_image_decomp_stream(ctx, stm, &bc->params, &dummy_l2factor);

		image->tile = fz_decomp_image_from_stream(ctx, stm, image, indexed, 0, 0);
	}
	fz_catch(ctx)
	{
		fz_drop_compressed_buffer(ctx, bc);
		fz_rethrow(ctx);
	}
	image->buffer = bc;
}
Example #3
0
static fz_pixmap *
standard_image_get_pixmap(fz_context *ctx, fz_image *image, int w, int h, int *l2factor)
{
    int native_l2factor;
    fz_stream *stm;
    int indexed;
    fz_pixmap *tile;

    /* We need to make a new one. */
    /* First check for ones that we can't decode using streams */
    switch (image->buffer->params.type)
    {
    case FZ_IMAGE_PNG:
        tile = fz_load_png(ctx, image->buffer->buffer->data, image->buffer->buffer->len);
        break;
    case FZ_IMAGE_GIF:
        tile = fz_load_gif(ctx, image->buffer->buffer->data, image->buffer->buffer->len);
        break;
    case FZ_IMAGE_TIFF:
        tile = fz_load_tiff(ctx, image->buffer->buffer->data, image->buffer->buffer->len);
        break;
    case FZ_IMAGE_JXR:
        tile = fz_load_jxr(ctx, image->buffer->buffer->data, image->buffer->buffer->len);
        break;
    case FZ_IMAGE_JPEG:
        /* Scan JPEG stream and patch missing height values in header */
    {
        unsigned char *s = image->buffer->buffer->data;
        unsigned char *e = s + image->buffer->buffer->len;
        unsigned char *d;
        for (d = s + 2; s < d && d < e - 9 && d[0] == 0xFF; d += (d[2] << 8 | d[3]) + 2)
        {
            if (d[1] < 0xC0 || (0xC3 < d[1] && d[1] < 0xC9) || 0xCB < d[1])
                continue;
            if ((d[5] == 0 && d[6] == 0) || ((d[5] << 8) | d[6]) > image->h)
            {
                d[5] = (image->h >> 8) & 0xFF;
                d[6] = image->h & 0xFF;
            }
        }
    }
    /* fall through */

    default:
        native_l2factor = l2factor ? *l2factor : 0;
        stm = fz_open_image_decomp_stream_from_buffer(ctx, image->buffer, l2factor);
        if (l2factor)
            native_l2factor -= *l2factor;

        indexed = fz_colorspace_is_indexed(ctx, image->colorspace);
        tile = fz_decomp_image_from_stream(ctx, stm, image, indexed, native_l2factor);

        /* CMYK JPEGs in XPS documents have to be inverted */
        if (image->invert_cmyk_jpeg &&
                image->buffer->params.type == FZ_IMAGE_JPEG &&
                image->colorspace == fz_device_cmyk(ctx) &&
                image->buffer->params.u.jpeg.color_transform)
        {
            fz_invert_pixmap(ctx, tile);
        }

        break;
    }
Example #4
0
fz_pixmap *
fz_image_get_pixmap(fz_context *ctx, fz_image *image, int w, int h)
{
	fz_pixmap *tile;
	fz_stream *stm;
	int l2factor;
	fz_image_key key;
	int native_l2factor;
	int indexed;
	fz_image_key *keyp;

	/* Check for 'simple' images which are just pixmaps */
	if (image->buffer == NULL)
	{
		tile = image->tile;
		if (!tile)
			return NULL;
		return fz_keep_pixmap(ctx, tile); /* That's all we can give you! */
	}

	/* Ensure our expectations for tile size are reasonable */
	if (w > image->w)
		w = image->w;
	if (h > image->h)
		h = image->h;

	/* What is our ideal factor? */
	if (w == 0 || h == 0)
		l2factor = 0;
	else
		for (l2factor=0; image->w>>(l2factor+1) >= w && image->h>>(l2factor+1) >= h && l2factor < 8; l2factor++);

	/* Can we find any suitable tiles in the cache? */
	key.refs = 1;
	key.image = image;
	key.l2factor = l2factor;
	do
	{
		tile = fz_find_item(ctx, fz_free_pixmap_imp, &key, &fz_image_store_type);
		if (tile)
			return tile;
		key.l2factor--;
	}
	while (key.l2factor >= 0);

	/* We need to make a new one. */
	/* First check for ones that we can't decode using streams */
	switch (image->buffer->params.type)
	{
	case FZ_IMAGE_PNG:
		tile = fz_load_png(ctx, image->buffer->buffer->data, image->buffer->buffer->len);
		break;
	case FZ_IMAGE_TIFF:
		tile = fz_load_tiff(ctx, image->buffer->buffer->data, image->buffer->buffer->len);
		break;
	default:
		native_l2factor = l2factor;
		stm = fz_open_image_decomp_stream(ctx, image->buffer, &native_l2factor);

		indexed = fz_colorspace_is_indexed(image->colorspace);
		tile = fz_decomp_image_from_stream(ctx, stm, image, 0, indexed, l2factor, native_l2factor);
		break;
	}

	/* Now we try to cache the pixmap. Any failure here will just result
	 * in us not caching. */
	fz_var(keyp);
	fz_try(ctx)
	{
		fz_pixmap *existing_tile;

		keyp = fz_malloc_struct(ctx, fz_image_key);
		keyp->refs = 1;
		keyp->image = fz_keep_image(ctx, image);
		keyp->l2factor = l2factor;
		existing_tile = fz_store_item(ctx, keyp, tile, fz_pixmap_size(ctx, tile), &fz_image_store_type);
		if (existing_tile)
		{
			/* We already have a tile. This must have been produced by a
			 * racing thread. We'll throw away ours and use that one. */
			fz_drop_pixmap(ctx, tile);
			tile = existing_tile;
		}
	}
	fz_always(ctx)
	{
		fz_drop_image_key(ctx, keyp);
	}
	fz_catch(ctx)
	{
		/* Do nothing */
	}

	return tile;
}
Example #5
0
static fz_image *
pdf_load_image_imp(pdf_document *xref, pdf_obj *rdb, pdf_obj *dict, fz_stream *cstm, int forcemask)
{
	fz_stream *stm = NULL;
	fz_image *image = NULL;
	pdf_obj *obj, *res;

	int w, h, bpc, n;
	int imagemask;
	int interpolate;
	int indexed;
	fz_image *mask = NULL; /* explicit mask/soft mask image */
	int usecolorkey = 0;
	fz_colorspace *colorspace = NULL;
	float decode[FZ_MAX_COLORS * 2];
	int colorkey[FZ_MAX_COLORS * 2];

	int i;
	fz_context *ctx = xref->ctx;

	fz_var(stm);
	fz_var(mask);
	fz_var(image);
	fz_var(colorspace);

	fz_try(ctx)
	{
		/* special case for JPEG2000 images */
		if (pdf_is_jpx_image(ctx, dict))
		{
			image = pdf_load_jpx(xref, dict, forcemask);

			if (forcemask)
			{
				fz_pixmap *mask_pixmap;
				if (image->n != 2)
				{
					/* SumatraPDF: ignore invalid JPX softmasks */
					fz_warn(ctx, "soft mask must be grayscale");
					mask_pixmap = fz_new_pixmap(ctx, NULL, image->tile->w, image->tile->h);
					fz_clear_pixmap_with_value(ctx, mask_pixmap, 255);
				}
				else
				mask_pixmap = fz_alpha_from_gray(ctx, image->tile, 1);
				fz_drop_pixmap(ctx, image->tile);
				image->tile = mask_pixmap;
			}
			break; /* Out of fz_try */
		}

		w = pdf_to_int(pdf_dict_getsa(dict, "Width", "W"));
		h = pdf_to_int(pdf_dict_getsa(dict, "Height", "H"));
		bpc = pdf_to_int(pdf_dict_getsa(dict, "BitsPerComponent", "BPC"));
		if (bpc == 0)
			bpc = 8;
		imagemask = pdf_to_bool(pdf_dict_getsa(dict, "ImageMask", "IM"));
		interpolate = pdf_to_bool(pdf_dict_getsa(dict, "Interpolate", "I"));

		indexed = 0;
		usecolorkey = 0;
		mask = NULL;

		if (imagemask)
			bpc = 1;

		if (w <= 0)
			fz_throw(ctx, "image width is zero (or less)");
		if (h <= 0)
			fz_throw(ctx, "image height is zero (or less)");
		if (bpc <= 0)
			fz_throw(ctx, "image depth is zero (or less)");
		if (bpc > 16)
			fz_throw(ctx, "image depth is too large: %d", bpc);
		if (w > (1 << 16))
			fz_throw(ctx, "image is too wide");
		if (h > (1 << 16))
			fz_throw(ctx, "image is too high");

		obj = pdf_dict_getsa(dict, "ColorSpace", "CS");
		if (obj && !imagemask && !forcemask)
		{
			/* colorspace resource lookup is only done for inline images */
			if (pdf_is_name(obj))
			{
				res = pdf_dict_get(pdf_dict_gets(rdb, "ColorSpace"), obj);
				if (res)
					obj = res;
			}

			colorspace = pdf_load_colorspace(xref, obj);

			if (!strcmp(colorspace->name, "Indexed"))
				indexed = 1;

			n = colorspace->n;
		}
		else
		{
			n = 1;
		}

		obj = pdf_dict_getsa(dict, "Decode", "D");
		if (obj)
		{
			for (i = 0; i < n * 2; i++)
				decode[i] = pdf_to_real(pdf_array_get(obj, i));
		}
		else
		{
			float maxval = indexed ? (1 << bpc) - 1 : 1;
			for (i = 0; i < n * 2; i++)
				decode[i] = i & 1 ? maxval : 0;
		}

		obj = pdf_dict_getsa(dict, "SMask", "Mask");
		if (pdf_is_dict(obj))
		{
			/* Not allowed for inline images or soft masks */
			if (cstm)
				fz_warn(ctx, "Ignoring invalid inline image soft mask");
			else if (forcemask)
				fz_warn(ctx, "Ignoring recursive image soft mask");
			else
				mask = pdf_load_image_imp(xref, rdb, obj, NULL, 1);
		}
		else if (pdf_is_array(obj))
		{
			usecolorkey = 1;
			for (i = 0; i < n * 2; i++)
			{
				if (!pdf_is_int(pdf_array_get(obj, i)))
				{
					fz_warn(ctx, "invalid value in color key mask");
					usecolorkey = 0;
				}
				colorkey[i] = pdf_to_int(pdf_array_get(obj, i));
			}
		}

		/* Now, do we load a ref, or do we load the actual thing? */
		if (!cstm)
		{
			/* Just load the compressed image data now and we can
			 * decode it on demand. */
			int num = pdf_to_num(dict);
			int gen = pdf_to_gen(dict);
			fz_compressed_buffer *buffer = pdf_load_compressed_stream(xref, num, gen);
			image = fz_new_image(ctx, w, h, bpc, colorspace, 96, 96, interpolate, imagemask, decode, usecolorkey ? colorkey : NULL, buffer, mask);
			break; /* Out of fz_try */
		}

		/* We need to decompress the image now */
		if (cstm)
		{
			int stride = (w * n * bpc + 7) / 8;
			stm = pdf_open_inline_stream(xref, dict, stride * h, cstm, NULL);
		}
		else
		{
			stm = pdf_open_stream(xref, pdf_to_num(dict), pdf_to_gen(dict));
		}

		image = fz_new_image(ctx, w, h, bpc, colorspace, 96, 96, interpolate, imagemask, decode, usecolorkey ? colorkey : NULL, NULL, mask);
		image->tile = fz_decomp_image_from_stream(ctx, stm, image, cstm != NULL, indexed, 0, 0);
	}
	fz_catch(ctx)
	{
		/* SumatraPDF: fix memory leak */
		if (!image)
			fz_drop_colorspace(ctx, colorspace);
		else
		fz_drop_image(ctx, image);
		fz_rethrow(ctx);
	}

	/* cf. http://bugs.ghostscript.com/show_bug.cgi?id=693517 */
	fz_try(ctx)
	{
		obj = pdf_dict_getp(dict, "SMask/Matte");
		if (pdf_is_array(obj) && image->mask)
		{
			assert(!image->usecolorkey);
			image->usecolorkey = 2;
			for (i = 0; i < n; i++)
				image->colorkey[i] = pdf_to_int(pdf_array_get(obj, i));
		}
	}
	fz_catch(ctx)
	{
		fz_drop_image(ctx, image);
		fz_rethrow(ctx);
	}

	return image;
}