Beispiel #1
0
static fz_pixmap *
pam_binary_read_image(fz_context *ctx, struct info *pnm, unsigned char *p, unsigned char *e, int onlymeta)
{
	fz_pixmap *img = NULL;
	int bitmap = 0;

	p = pam_binary_read_header(ctx, pnm, p, e);

	if (pnm->tupletype == NULL)
		switch (pnm->depth)
		{
		case 1: pnm->tupletype = fz_strdup(ctx, "BLACKANDWHITE"); break;
		case 2: pnm->tupletype = fz_strdup(ctx, "GRAYSCALE_ALPHA"); break;
		case 3: pnm->tupletype = fz_strdup(ctx, "RGB"); break;
		case 4: pnm->tupletype = fz_strdup(ctx, "CMYK"); break;
		case 5: pnm->tupletype = fz_strdup(ctx, "CMYK_ALPHA"); break;
		default:
			fz_throw(ctx, FZ_ERROR_GENERIC, "cannot guess tupletype based on depth in pnm image");
		}

	if (!strcmp(pnm->tupletype, "BLACKANDWHITE"))
	{
		if (pnm->depth != 1)
			fz_throw(ctx, FZ_ERROR_GENERIC, "depth out of range for b/w pnm image");
		if (pnm->maxval == 1)
			bitmap = 1;
		else if (pnm->maxval < 2 || pnm->maxval > 65535)
			fz_throw(ctx, FZ_ERROR_GENERIC, "maxval out of range for grayscale pnm image");

		pnm->cs = fz_device_gray(ctx);
	}
	else if (!strcmp(pnm->tupletype, "GRAYSCALE"))
	{
		if (pnm->maxval < 2 || pnm->maxval > 65535)
			fz_throw(ctx, FZ_ERROR_GENERIC, "maxval out of range for grayscale pnm image");
		if (pnm->depth != 1)
			fz_throw(ctx, FZ_ERROR_GENERIC, "depth out of range for grayscale pnm image");
		pnm->cs = fz_device_gray(ctx);
	}
	else if (!strcmp(pnm->tupletype, "GRAYSCALE_ALPHA"))
	{
		if (pnm->maxval < 2 || pnm->maxval > 65535)
			fz_throw(ctx, FZ_ERROR_GENERIC, "maxval out of range for grayscale pnm image with alpha");
		if (pnm->depth != 2)
			fz_throw(ctx, FZ_ERROR_GENERIC, "depth out of range for grayscale pnm image with alpha");
		pnm->cs = fz_device_gray(ctx);
		pnm->alpha = 1;
	}
	else if (!strcmp(pnm->tupletype, "RGB"))
	{
		if (pnm->maxval < 1 || pnm->maxval > 65535)
			fz_throw(ctx, FZ_ERROR_GENERIC, "maxval out of range for rgb pnm image");
		if (pnm->depth != 3)
			fz_throw(ctx, FZ_ERROR_GENERIC, "depth out of range for rgb pnm image");
		pnm->cs = fz_device_rgb(ctx);
	}
	else if (!strcmp(pnm->tupletype, "RGB_ALPHA"))
	{
		if (pnm->maxval < 1 || pnm->maxval > 65535)
			fz_throw(ctx, FZ_ERROR_GENERIC, "maxval out of range for rgb pnm image with alpha");
		if (pnm->depth != 4)
			fz_throw(ctx, FZ_ERROR_GENERIC, "depth out of range for rgb pnm image with alpha");
		pnm->cs = fz_device_rgb(ctx);
		pnm->alpha = 1;
	}
	else if (!strcmp(pnm->tupletype, "CMYK"))
	{
		if (pnm->maxval < 1 || pnm->maxval > 65535)
			fz_throw(ctx, FZ_ERROR_GENERIC, "maxval out of range for cmyk pnm image");
		if (pnm->depth != 4)
			fz_throw(ctx, FZ_ERROR_GENERIC, "depth out of range for cmyk pnm image");
		pnm->cs = fz_device_cmyk(ctx);
	}
	else if (!strcmp(pnm->tupletype, "CMYK_ALPHA"))
	{
		if (pnm->maxval < 1 || pnm->maxval > 65535)
			fz_throw(ctx, FZ_ERROR_GENERIC, "maxval out of range for cmyk pnm image with alpha");
		if (pnm->depth != 5)
			fz_throw(ctx, FZ_ERROR_GENERIC, "depth out of range for cmyk pnm image with alpha");
		pnm->cs = fz_device_cmyk(ctx);
		pnm->alpha = 1;
	}
	else
	{
		fz_free(ctx, pnm->tupletype);
		fz_throw(ctx, FZ_ERROR_GENERIC, "unsupported tupletype");
	}

	fz_free(ctx, pnm->tupletype);

	if (!onlymeta)
	{
		unsigned char *dp;
		int x, y, k;

		img = fz_new_pixmap(ctx, pnm->cs, pnm->width, pnm->height, pnm->alpha);
		dp = img->samples;

		if (bitmap)
		{
			if (e - p < pnm->height * pnm->width * img->n)
				fz_throw(ctx, FZ_ERROR_GENERIC, "truncated image");

			for (y = 0; y < pnm->height; y++)
				for (x = 0; x < pnm->width; x++)
					for (k = 0; k < img->colorspace->n; k++)
					{
						if (*p)
							*dp = 0x00;
						else
							*dp = 0xff;
						dp++;
						p++;
					}
		}
		else
		{
			if (pnm->maxval == 255)
			{
				if (e - p < pnm->height * pnm->width * img->n)
					fz_throw(ctx, FZ_ERROR_GENERIC, "truncated image");

				for (y = 0; y < pnm->height; y++)
					for (x = 0; x < pnm->width; x++)
						for (k = 0; k < img->n; k++)
							*dp++ = *p++;
			}
			else if (pnm->maxval < 256)
			{
				if (e - p < pnm->height * pnm->width * img->n)
					fz_throw(ctx, FZ_ERROR_GENERIC, "truncated image");

				for (y = 0; y < pnm->height; y++)
					for (x = 0; x < pnm->width; x++)
						for (k = 0; k < img->n; k++)
							*dp++ = map_color(ctx, *p++, pnm->maxval, 255);
			}
			else
			{
				if (e - p < pnm->height * pnm->width * img->n * 2)
					fz_throw(ctx, FZ_ERROR_GENERIC, "truncated image");

				for (y = 0; y < pnm->height; y++)
					for (x = 0; x < pnm->width; x++)
						for (k = 0; k < img->n; k++)
						{
							*dp++ = map_color(ctx, (p[0] << 8) | p[1], pnm->maxval, 255);
							p += 2;
						}
			}
		}
	}

	return img;
}
Beispiel #2
0
static fz_pixmap *
pam_binary_read_image(fz_context *ctx, struct info *pnm, const unsigned char *p, const unsigned char *e, int onlymeta, const unsigned char **out)
{
	fz_pixmap *img = NULL;
	int bitmap = 0;
	int minval = 1;
	int maxval = 65535;

	fz_var(img);

	p = pam_binary_read_header(ctx, pnm, p, e);

	if (pnm->tupletype == PAM_UNKNOWN)
		switch (pnm->depth)
		{
		case 1: pnm->tupletype = pnm->maxval == 1 ? PAM_BW : PAM_GRAY; break;
		case 2: pnm->tupletype = pnm->maxval == 1 ? PAM_BWA : PAM_GRAYA; break;
		case 3: pnm->tupletype = PAM_RGB; break;
		case 4: pnm->tupletype = PAM_CMYK; break;
		case 5: pnm->tupletype = PAM_CMYKA; break;
		default:
			fz_throw(ctx, FZ_ERROR_GENERIC, "cannot guess tuple type based on depth in pnm image");
		}

	if (pnm->tupletype == PAM_BW && pnm->maxval > 1)
		pnm->tupletype = PAM_GRAY;
	else if (pnm->tupletype == PAM_GRAY && pnm->maxval == 1)
		pnm->tupletype = PAM_BW;
	else if (pnm->tupletype == PAM_BWA && pnm->maxval > 1)
		pnm->tupletype = PAM_GRAYA;
	else if (pnm->tupletype == PAM_GRAYA && pnm->maxval == 1)
		pnm->tupletype = PAM_BWA;

	switch (pnm->tupletype)
	{
	case PAM_BWA:
		pnm->alpha = 1;
		/* fallthrough */
	case PAM_BW:
		pnm->cs = fz_device_gray(ctx);
		maxval = 1;
		bitmap = 1;
		break;
	case PAM_GRAYA:
		pnm->alpha = 1;
		/* fallthrough */
	case PAM_GRAY:
		pnm->cs = fz_device_gray(ctx);
		minval = 2;
		break;
	case PAM_RGBA:
		pnm->alpha = 1;
		/* fallthrough */
	case PAM_RGB:
		pnm->cs = fz_device_rgb(ctx);
		break;
	case PAM_CMYKA:
		pnm->alpha = 1;
		/* fallthrough */
	case PAM_CMYK:
		pnm->cs = fz_device_cmyk(ctx);
		break;
	default:
		fz_throw(ctx, FZ_ERROR_GENERIC, "unsupported tuple type");
	}

	if (pnm->depth != fz_colorspace_n(ctx, pnm->cs) + pnm->alpha)
		fz_throw(ctx, FZ_ERROR_GENERIC, "depth out of tuple type range");
	if (pnm->maxval < minval || pnm->maxval > maxval)
		fz_throw(ctx, FZ_ERROR_GENERIC, "maxval out of range");

	pnm->bitdepth = bitdepth_from_maxval(pnm->maxval);

	if (pnm->height <= 0)
		fz_throw(ctx, FZ_ERROR_GENERIC, "image height must be > 0");
	if (pnm->width <= 0)
		fz_throw(ctx, FZ_ERROR_GENERIC, "image width must be > 0");
	if ((unsigned int)pnm->height > UINT_MAX / pnm->width / fz_colorspace_n(ctx, pnm->cs) / (pnm->bitdepth / 8 + 1))
		fz_throw(ctx, FZ_ERROR_GENERIC, "image too large");

	if (onlymeta)
	{
		int packed;
		int w, h, n;

		w = pnm->width;
		h = pnm->height;
		n = fz_colorspace_n(ctx, pnm->cs) + pnm->alpha;

		/* some encoders incorrectly pack bits into bytes and invert the image */
		packed = 0;
		if (pnm->maxval == 1) {
			const unsigned char *e_packed = p + w * h * n / 8;
			if (e_packed < e - 1 && e_packed[0] == 'P' && e_packed[1] >= '0' && e_packed[1] <= '7')
				e = e_packed;
			if (e - p < w * h * n)
				packed = 1;
		}
		if (packed && e - p < w * h * n / 8)
			fz_throw(ctx, FZ_ERROR_GENERIC, "truncated packed image");
		if (!packed && e - p < w * h * n * (pnm->maxval < 256 ? 1 : 2))
			fz_throw(ctx, FZ_ERROR_GENERIC, "truncated image");

		if (pnm->maxval == 255)
			p += n * w * h;
		else if (bitmap && packed)
			p += ((w + 7) / 8) * h;
		else if (bitmap)
			p += n * w * h;
		else if (pnm->maxval < 255)
			p += n * w * h;
		else
			p += 2 * n * w * h;
	}

	if (!onlymeta)
	{
		unsigned char *dp;
		int x, y, k, packed;
		int w, h, n;

		img = fz_new_pixmap(ctx, pnm->cs, pnm->width, pnm->height, NULL, pnm->alpha);
		fz_try(ctx)
		{
			dp = img->samples;

			w = img->w;
			h = img->h;
			n = img->n;

			/* some encoders incorrectly pack bits into bytes and invert the image */
			packed = 0;
			if (pnm->maxval == 1) {
				const unsigned char *e_packed = p + w * h * n / 8;
				if (e_packed < e - 1 && e_packed[0] == 'P' && e_packed[1] >= '0' && e_packed[1] <= '7')
					e = e_packed;
				if (e - p < w * h * n)
					packed = 1;
			}
			if (packed && e - p < w * h * n / 8)
				fz_throw(ctx, FZ_ERROR_GENERIC, "truncated packed image");
			if (!packed && e - p < w * h * n * (pnm->maxval < 256 ? 1 : 2))
				fz_throw(ctx, FZ_ERROR_GENERIC, "truncated image");

			if (pnm->maxval == 255)
				memcpy(dp, p, w * h * n);
			else if (bitmap && packed)
			{
				for (y = 0; y < h; y++)
					for (x = 0; x < w; x++)
					{
						for (k = 0; k < n; k++)
						{
							*dp++ = (*p & (1 << (7 - (x & 0x7)))) ? 0x00 : 0xff;
							if ((x & 0x7) == 7)
								p++;
						}
						if (w & 0x7)
							p++;
					}
			}
			else if (bitmap)
			{
				for (y = 0; y < h; y++)
					for (x = 0; x < w; x++)
						for (k = 0; k < n; k++)
							*dp++ = *p++ ? 0xff : 0x00;
			}
			else if (pnm->maxval < 255)
			{
				for (y = 0; y < h; y++)
					for (x = 0; x < w; x++)
						for (k = 0; k < n; k++)
							*dp++ = map_color(ctx, *p++, pnm->maxval, 255);
			}
			else
			{
				for (y = 0; y < h; y++)
					for (x = 0; x < w; x++)
						for (k = 0; k < n; k++)
						{
							*dp++ = map_color(ctx, (p[0] << 8) | p[1], pnm->maxval, 255);
							p += 2;
						}
			}

			if (pnm->alpha)
				fz_premultiply_pixmap(ctx, img);
		}
		fz_catch(ctx)
		{
			fz_drop_pixmap(ctx, img);
			fz_rethrow(ctx);
		}
	}