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 * 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); } }