summaryrefslogtreecommitdiff
path: root/source
diff options
context:
space:
mode:
authorSebastian Rasmussen <sebras@gmail.com>2016-06-26 18:42:37 +0200
committerTor Andersson <tor.andersson@artifex.com>2016-07-06 13:34:37 +0200
commit507d31982280185fe4d3fd22d25c6d11aad480c9 (patch)
tree01de723dabb55ea69de4e3586a79fc09578f5f01 /source
parent40dc2fabdd3bd647c21ee4334bb81f96a2103ff5 (diff)
downloadmupdf-507d31982280185fe4d3fd22d25c6d11aad480c9.tar.xz
Add support for decoding pbm/pgm/ppm/pam images.
Diffstat (limited to 'source')
-rw-r--r--source/cbz/mucbz.c2
-rw-r--r--source/cbz/muimg.c12
-rw-r--r--source/fitz/image.c10
-rw-r--r--source/fitz/load-pnm.c568
4 files changed, 588 insertions, 4 deletions
diff --git a/source/cbz/mucbz.c b/source/cbz/mucbz.c
index f9c73d6b..5a83adc0 100644
--- a/source/cbz/mucbz.c
+++ b/source/cbz/mucbz.c
@@ -6,7 +6,7 @@ typedef struct cbz_document_s cbz_document;
typedef struct cbz_page_s cbz_page;
static const char *cbz_ext_list[] = {
- ".jpg", ".jpeg", ".png", ".gif", ".bmp", ".tif", ".tiff", ".jpx", ".jp2", ".j2k", ".wdp", ".hdp", ".jxr",
+ ".jpg", ".jpeg", ".png", ".gif", ".bmp", ".tif", ".tiff", ".jpx", ".jp2", ".j2k", ".wdp", ".hdp", ".jxr", ".pbm", ".pgm", ".ppm", ".pam", ".pnm",
NULL
};
diff --git a/source/cbz/muimg.c b/source/cbz/muimg.c
index 91b89dfa..de99679f 100644
--- a/source/cbz/muimg.c
+++ b/source/cbz/muimg.c
@@ -162,7 +162,10 @@ img_recognize(fz_context *doc, const char *magic)
!fz_strcasecmp(ext, ".gif") || !fz_strcasecmp(ext, ".bmp") ||
!fz_strcasecmp(ext, ".jpx") || !fz_strcasecmp(ext, ".jp2") ||
!fz_strcasecmp(ext, ".j2k") || !fz_strcasecmp(ext, ".wdp") ||
- !fz_strcasecmp(ext, ".hdp") || !fz_strcasecmp(ext, ".jxr"))
+ !fz_strcasecmp(ext, ".hdp") || !fz_strcasecmp(ext, ".jxr") ||
+ !fz_strcasecmp(ext, ".pbm") || !fz_strcasecmp(ext, ".pgm") ||
+ !fz_strcasecmp(ext, ".ppm") || !fz_strcasecmp(ext, ".pam") ||
+ !fz_strcasecmp(ext, ".pnm"))
return 100;
}
if (!strcmp(magic, "png") || !strcmp(magic, "image/png") ||
@@ -175,7 +178,12 @@ img_recognize(fz_context *doc, const char *magic)
!strcmp(magic, "jp2") || !strcmp(magic, "image/jp2") ||
!strcmp(magic, "j2k") || !strcmp(magic, "wdp") ||
!strcmp(magic, "hdp") || !strcmp(magic, "image/vnd.ms-photo") ||
- !strcmp(magic, "jxr") || !strcmp(magic, "image/jxr"))
+ !strcmp(magic, "jxr") || !strcmp(magic, "image/jxr") ||
+ !strcmp(magic, "pbm") || !strcmp(magic, "image/x-portable-bitmap") ||
+ !strcmp(magic, "pgm") || !strcmp(magic, "image/x-portable-greymap") ||
+ !strcmp(magic, "ppm") || !strcmp(magic, "image/x-portable-pixmap") ||
+ !strcmp(magic, "pam") || !strcmp(magic, "image/x-portable-arbitrarymap") ||
+ !strcmp(magic, "pnm"))
return 100;
return 0;
diff --git a/source/fitz/image.c b/source/fitz/image.c
index 6919808a..064b03c7 100644
--- a/source/fitz/image.c
+++ b/source/fitz/image.c
@@ -407,6 +407,9 @@ compressed_image_get_pixmap(fz_context *ctx, fz_image *image_, fz_irect *subarea
case FZ_IMAGE_TIFF:
tile = fz_load_tiff(ctx, image->buffer->buffer->data, image->buffer->buffer->len);
break;
+ case FZ_IMAGE_PNM:
+ tile = fz_load_pnm(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;
@@ -915,7 +918,12 @@ fz_new_image_from_buffer(fz_context *ctx, fz_buffer *buffer)
bc = fz_malloc_struct(ctx, fz_compressed_buffer);
bc->buffer = fz_keep_buffer(ctx, buffer);
- if (buf[0] == 0xff && buf[1] == 0x4f)
+ if (buf[0] == 'P' && buf[1] >= '1' && buf[1] <= '7')
+ {
+ bc->params.type = FZ_IMAGE_PNM;
+ fz_load_pnm_info(ctx, buf, len, &w, &h, &xres, &yres, &cspace);
+ }
+ else if (buf[0] == 0xff && buf[1] == 0x4f)
{
bc->params.type = FZ_IMAGE_JPX;
fz_load_jpx_info(ctx, buf, len, &w, &h, &xres, &yres, &cspace);
diff --git a/source/fitz/load-pnm.c b/source/fitz/load-pnm.c
new file mode 100644
index 00000000..6fc911e1
--- /dev/null
+++ b/source/fitz/load-pnm.c
@@ -0,0 +1,568 @@
+#include "mupdf/fitz.h"
+
+struct info
+{
+ fz_colorspace *cs;
+ int width, height;
+ int maxval, depth;
+ int alpha;
+ char *tupletype;
+};
+
+/* TODO: parse PAM */
+
+static inline int iswhiteeol(int a)
+{
+ switch (a) {
+ case ' ': case '\t': case '\r': case '\n':
+ return 1;
+ }
+ return 0;
+}
+
+static inline int iswhite(int a)
+{
+ switch (a) {
+ case ' ': case '\t':
+ return 1;
+ }
+ return 0;
+}
+
+static inline int iseol(int a)
+{
+ switch (a) {
+ case '\r': case '\n':
+ return 1;
+ }
+ return 0;
+}
+
+static unsigned char *
+pnm_read_white(fz_context *ctx, unsigned char *p, unsigned char *e, int single_line)
+{
+ if (e - p < 1)
+ fz_throw(ctx, FZ_ERROR_GENERIC, "cannot parse whitespace in pnm image");
+
+ if (single_line)
+ {
+ if (!iswhiteeol(*p) && *p != '#')
+ fz_throw(ctx, FZ_ERROR_GENERIC, "expected whitespace/comment in pnm image");
+ while (p < e && iswhite(*p))
+ p++;
+
+ if (p < e && *p == '#')
+ while (p < e && !iseol(*p))
+ p++;
+ if (p < e && iseol(*p))
+ p++;
+ }
+ else
+ {
+ if (!iswhiteeol(*p) && *p != '#')
+ fz_throw(ctx, FZ_ERROR_GENERIC, "expected whitespace in pnm image");
+ while (p < e && iswhiteeol(*p))
+ p++;
+
+ while (p < e && *p == '#')
+ {
+ while (p < e && !iseol(*p))
+ p++;
+
+ if (p < e && iseol(*p))
+ p++;
+
+ while (p < e && iswhiteeol(*p))
+ p++;
+
+ if (p < e && iseol(*p))
+ p++;
+ }
+
+ }
+
+ return p;
+}
+
+static unsigned char *
+pnm_read_signature(fz_context *ctx, unsigned char *p, unsigned char *e, char *signature)
+{
+ if (e - p < 2)
+ fz_throw(ctx, FZ_ERROR_GENERIC, "cannot parse magic number in pnm image");
+ if (p[0] != 'P' || p[1] < '1' || p[1] > '7')
+ fz_throw(ctx, FZ_ERROR_GENERIC, "expected signature in pnm image");
+
+ signature[0] = *p++;
+ signature[1] = *p++;
+ return p;
+}
+
+static unsigned char *
+pnm_read_number(fz_context *ctx, unsigned char *p, unsigned char *e, int *number)
+{
+ if (e - p < 1)
+ fz_throw(ctx, FZ_ERROR_GENERIC, "cannot parse number in pnm image");
+ if (*p < '0' && *p > '9')
+ fz_throw(ctx, FZ_ERROR_GENERIC, "expected numeric field in pnm image");
+
+ while (p < e && *p >= '0' && *p <= '9')
+ {
+ *number = *number * 10 + *p - '0';
+ p++;
+ }
+
+ return p;
+}
+
+static unsigned char *
+pnm_read_string(fz_context *ctx, unsigned char *p, unsigned char *e, char **out)
+{
+ unsigned char *s;
+
+ if (e - p < 1)
+ fz_throw(ctx, FZ_ERROR_GENERIC, "cannot parse string in pnm image");
+
+ s = p;
+ while (!iswhiteeol(*p))
+ p++;
+
+ *out = fz_malloc(ctx, p - s + 1);
+ memcpy(*out, s, p - s);
+ (*out)[p - s] = '\0';
+
+ return p;
+}
+
+static int
+map_color(fz_context *ctx, int color, int inmax, int outmax)
+{
+ float f = (float) color / inmax;
+ return f * outmax;
+}
+
+static fz_pixmap *
+pnm_ascii_read_image(fz_context *ctx, struct info *pnm, unsigned char *p, unsigned char *e, int onlymeta, int bitmap)
+{
+ fz_pixmap *img = NULL;
+
+ p = pnm_read_number(ctx, p, e, &pnm->width);
+ p = pnm_read_white(ctx, p, e, 0);
+
+ if (bitmap)
+ {
+ p = pnm_read_number(ctx, p, e, &pnm->height);
+ p = pnm_read_white(ctx, p, e, 1);
+ pnm->maxval = 1;
+ }
+ else
+ {
+ p = pnm_read_number(ctx, p, e, &pnm->height);
+ p = pnm_read_white(ctx, p, e, 0);
+ p = pnm_read_number(ctx, p, e, &pnm->maxval);
+ p = pnm_read_white(ctx, p, e, 0);
+ if (pnm->maxval < 0 || pnm->maxval >= 65536)
+ fz_throw(ctx, FZ_ERROR_GENERIC, "maximum sample value of out range in pnm image: %d", pnm->maxval);
+ }
+
+ if (!onlymeta)
+ {
+ unsigned char *dp;
+ int x, y, k;
+
+ img = fz_new_pixmap(ctx, pnm->cs, pnm->width, pnm->height, 0);
+ dp = img->samples;
+
+ if (bitmap)
+ {
+ for (y = 0; y < pnm->height; y++)
+ {
+ for (x = 0; x < pnm->width; x++)
+ {
+ int v = 0;
+ p = pnm_read_number(ctx, p, e, &v);
+ p = pnm_read_white(ctx, p, e, 0);
+ if (v == 0)
+ *dp = 0x00;
+ else
+ *dp = 0xff;
+
+ dp++;
+ }
+ }
+ }
+ else
+ {
+ for (y = 0; y < pnm->height; y++)
+ for (x = 0; x < pnm->width; x++)
+ for (k = 0; k < img->colorspace->n; k++)
+ {
+ int v = 0;
+ p = pnm_read_number(ctx, p, e, &v);
+ p = pnm_read_white(ctx, p, e, 0);
+ v = fz_clampi(v, 0, pnm->maxval);
+ *dp++ = map_color(ctx, v, pnm->maxval, 255);
+ }
+ }
+
+ }
+
+ return img;
+}
+
+static fz_pixmap *
+pnm_binary_read_image(fz_context *ctx, struct info *pnm, unsigned char *p, unsigned char *e, int onlymeta, int bitmap)
+{
+ fz_pixmap *img = NULL;
+
+ p = pnm_read_number(ctx, p, e, &pnm->width);
+ p = pnm_read_white(ctx, p, e, 0);
+
+
+ if (bitmap)
+ {
+ p = pnm_read_number(ctx, p, e, &pnm->height);
+ p = pnm_read_white(ctx, p, e, 1);
+ pnm->maxval = 1;
+ }
+ else
+ {
+ p = pnm_read_number(ctx, p, e, &pnm->height);
+ p = pnm_read_white(ctx, p, e, 0);
+ p = pnm_read_number(ctx, p, e, &pnm->maxval);
+ p = pnm_read_white(ctx, p, e, 1);
+ if (pnm->maxval < 0 || pnm->maxval >= 65536)
+ fz_throw(ctx, FZ_ERROR_GENERIC, "maximum sample value of out range in pnm image: %d", pnm->maxval);
+ }
+
+ if (!onlymeta)
+ {
+ unsigned char *dp;
+ int x, y, k;
+
+ img = fz_new_pixmap(ctx, pnm->cs, pnm->width, pnm->height, 0);
+ dp = img->samples;
+
+ if (bitmap)
+ {
+ for (y = 0; y < pnm->height; y++)
+ {
+ for (x = 0; x < pnm->width; x++)
+ {
+ if (*p & (1 << (7 - (x & 0x7))))
+ *dp = 0x00;
+ else
+ *dp = 0xff;
+
+ dp++;
+ if ((x & 0x7) == 7)
+ p++;
+ }
+ if (pnm->width & 0x7)
+ p++;
+ }
+ }
+ else
+ {
+ if (pnm->maxval == 255)
+ {
+ for (y = 0; y < pnm->height; y++)
+ for (x = 0; x < pnm->width; x++)
+ for (k = 0; k < img->colorspace->n; k++)
+ *dp++ = *p++;
+ }
+ else if (pnm->maxval < 256)
+ {
+ for (y = 0; y < pnm->height; y++)
+ for (x = 0; x < pnm->width; x++)
+ for (k = 0; k < img->colorspace->n; k++)
+ *dp++ = map_color(ctx, *p++, pnm->maxval, 255);
+ }
+ else
+ {
+ for (y = 0; y < pnm->height; y++)
+ for (x = 0; x < pnm->width; x++)
+ for (k = 0; k < img->colorspace->n; k++)
+ {
+ *dp++ = map_color(ctx, (p[0] << 8) | p[1], pnm->maxval, 255);
+ p += 2;
+ }
+ }
+ }
+
+ }
+
+ return img;
+}
+
+static unsigned char *
+pam_binary_read_header(fz_context *ctx, struct info *pnm, unsigned char *p, unsigned char *e)
+{
+ char *token = fz_strdup(ctx, "");
+
+ fz_try(ctx)
+ {
+ while (p < e && strcmp(token, "ENDHDR"))
+ {
+ fz_free(ctx, token);
+ p = pnm_read_string(ctx, p, e, &token);
+ p = pnm_read_white(ctx, p, e, 0);
+ if (!strcmp(token, "WIDTH"))
+ p = pnm_read_number(ctx, p, e, &pnm->width);
+ else if (!strcmp(token, "HEIGHT"))
+ p = pnm_read_number(ctx, p, e, &pnm->height);
+ else if (!strcmp(token, "DEPTH"))
+ p = pnm_read_number(ctx, p, e, &pnm->depth);
+ else if (!strcmp(token, "MAXVAL"))
+ p = pnm_read_number(ctx, p, e, &pnm->maxval);
+ else if (!strcmp(token, "TUPLTYPE"))
+ p = pnm_read_string(ctx, p, e, &pnm->tupletype);
+ else if (strcmp(token, "ENDHDR"))
+ fz_throw(ctx, FZ_ERROR_GENERIC, "unknown header token in pnm image");
+
+ if (strcmp(token, "ENDHDR"))
+ p = pnm_read_white(ctx, p, e, 0);
+ }
+ }
+ fz_always(ctx)
+ {
+ fz_free(ctx, token);
+ }
+ fz_catch(ctx)
+ {
+ fz_rethrow(ctx);
+ }
+
+ return p;
+}
+
+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;
+}
+
+static fz_pixmap *
+pnm_read_image(fz_context *ctx, struct info *pnm, unsigned char *p, size_t total, int onlymeta)
+{
+ unsigned char *e = p + total;
+ char signature[3] = { 0 };
+
+ p = pnm_read_signature(ctx, p, e, signature);
+ p = pnm_read_white(ctx, p, e, 0);
+
+ if (!strcmp(signature, "P1"))
+ {
+ if (!onlymeta)
+ pnm->cs = fz_device_gray(ctx);
+ return pnm_ascii_read_image(ctx, pnm, p, e, onlymeta, 1);
+ }
+ else if (!strcmp(signature, "P2"))
+ {
+ if (!onlymeta)
+ pnm->cs = fz_device_gray(ctx);
+ return pnm_ascii_read_image(ctx, pnm, p, e, onlymeta, 0);
+ }
+ else if (!strcmp(signature, "P3"))
+ {
+ if (!onlymeta)
+ pnm->cs = fz_device_rgb(ctx);
+ return pnm_ascii_read_image(ctx, pnm, p, e, onlymeta, 0);
+ }
+ else if (!strcmp(signature, "P4"))
+ {
+ if (!onlymeta)
+ pnm->cs = fz_device_gray(ctx);
+ return pnm_binary_read_image(ctx, pnm, p, e, onlymeta, 1);
+ }
+ else if (!strcmp(signature, "P5"))
+ {
+ if (!onlymeta)
+ pnm->cs = fz_device_gray(ctx);
+ return pnm_binary_read_image(ctx, pnm, p, e, onlymeta, 0);
+ }
+ else if (!strcmp(signature, "P6"))
+ {
+ if (!onlymeta)
+ pnm->cs = fz_device_rgb(ctx);
+ return pnm_binary_read_image(ctx, pnm, p, e, onlymeta, 0);
+ }
+ else if (!strcmp(signature, "P7"))
+ return pam_binary_read_image(ctx, pnm, p, e, onlymeta);
+ else
+ fz_throw(ctx, FZ_ERROR_GENERIC, "unsupported portable anymap signature (0x%02x, 0x%02x)", signature[0], signature[1]);
+}
+
+fz_pixmap *
+fz_load_pnm(fz_context *ctx, unsigned char *p, size_t total)
+{
+ fz_pixmap *img;
+ struct info pnm = { 0 };
+
+ img = pnm_read_image(ctx, &pnm, p, total, 0);
+
+ return img;
+}
+
+void
+fz_load_pnm_info(fz_context *ctx, unsigned char *p, size_t total, int *wp, int *hp, int *xresp, int *yresp, fz_colorspace **cspacep)
+{
+ struct info pnm = { 0 };
+
+ pnm_read_image(ctx, &pnm, p, total, 1);
+
+ *cspacep = pnm.cs;
+ *wp = pnm.width;
+ *hp = pnm.height;
+ *xresp = 72;
+ *yresp = 72;
+}