Mercurial > hgrepos > Python2 > PyMuPDF
view mupdf-source/source/fitz/load-psd.c @ 38:8934ac156ef5
Allow to build with the PyPI package "clang" instead of "libclang".
1. It seems to be maintained.
2. In the FreeBSD base system there is no pre-built libclang.so. If you
need this library you have to install llvm from ports additionally.
2. On FreeBSD there is no pre-built wheel "libclang" with a packaged
libclang.so.
| author | Franz Glasner <fzglas.hg@dom66.de> |
|---|---|
| date | Tue, 23 Sep 2025 10:27:15 +0200 |
| parents | b50eed0cc0ef |
| children |
line wrap: on
line source
// Copyright (C) 2004-2024 Artifex Software, Inc. // // This file is part of MuPDF. // // MuPDF is free software: you can redistribute it and/or modify it under the // terms of the GNU Affero General Public License as published by the Free // Software Foundation, either version 3 of the License, or (at your option) // any later version. // // MuPDF is distributed in the hope that it will be useful, but WITHOUT ANY // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS // FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more // details. // // You should have received a copy of the GNU Affero General Public License // along with MuPDF. If not, see <https://www.gnu.org/licenses/agpl-3.0.en.html> // // Alternative licensing terms are available from the licensor. // For commercial licensing, see <https://www.artifex.com/> or contact // Artifex Software, Inc., 39 Mesa Street, Suite 108A, San Francisco, // CA 94129, USA, for further information. #include "mupdf/fitz.h" #include "pixmap-imp.h" #include <limits.h> #include <string.h> struct info { unsigned int width, height, n; int xres, yres; fz_colorspace *cs; }; typedef struct { fz_context *ctx; const unsigned char *p; size_t total; int packbits; int packbits_n; int packbits_rep; } source_t; static int get8(source_t *source) { if (source->total < 1) fz_throw(source->ctx, FZ_ERROR_FORMAT, "Truncated PSD"); source->total--; return *source->p++; } static int get16be(source_t *source) { int v; if (source->total < 2) { source->total = 0; fz_throw(source->ctx, FZ_ERROR_FORMAT, "Truncated PSD"); } source->total -= 2; v = *source->p++; v = (v<<8) | *source->p++; return v; } static int get32be(source_t *source) { int v; if (source->total < 4) { source->total = 0; fz_throw(source->ctx, FZ_ERROR_FORMAT, "Truncated PSD"); } source->total -= 4; v = *source->p++; v = (v<<8) | *source->p++; v = (v<<8) | *source->p++; v = (v<<8) | *source->p++; return v; } static uint32_t getu32be(source_t *source) { return (uint32_t)get32be(source); } static int unpack8(source_t *source) { int i; if (source->packbits == 0) return get8(source); i = source->packbits_n; if (i == 128) { do { i = source->packbits_n = get8(source); } while (i == 128); if (i > 128) source->packbits_rep = get8(source); } if (i < 128) { /* Literal n+1 */ i--; if (i < 0) i = 128; source->packbits_n = i; return get8(source); } else { i++; if (i == 257) i = 128; source->packbits_n = i; return source->packbits_rep; } } static char *getString(source_t *source) { size_t len = get8(source); size_t odd = !(len & 1); char *s; if (source->total < len + odd) { source->total = 0; fz_throw(source->ctx, FZ_ERROR_FORMAT, "Truncated string in PSD"); } s = fz_malloc(source->ctx, len+1); memcpy(s, source->p, len); s[len] = 0; source->p += len + odd; source->total -= len + odd; return s; } static fz_pixmap * psd_read_image(fz_context *ctx, struct info *info, const unsigned char *p, size_t total, int only_metadata) { int v, bpc, c, n; source_t source; size_t ir_len, data_len; fz_separations *seps = NULL; fz_pixmap *image = NULL; size_t m; unsigned char *q; int alpha = 0; source.ctx = ctx; source.p = p; source.total = total; source.packbits = 0; memset(info, 0, sizeof(*info)); fz_var(image); fz_var(seps); fz_try(ctx) { info->xres = 96; info->yres = 96; v = get32be(&source); /* Read signature */ if (v != 0x38425053 /* 8BPS */) fz_throw(ctx, FZ_ERROR_FORMAT, "not a psd image (wrong signature)"); /* Version */ v = get16be(&source); if (v != 1) fz_throw(ctx, FZ_ERROR_FORMAT, "Bad PSD version"); (void)get16be(&source); (void)get32be(&source); info->n = n = get16be(&source); info->height = getu32be(&source); info->width = getu32be(&source); bpc = get16be(&source); if (bpc != 8 && bpc != 16) fz_throw(ctx, FZ_ERROR_UNSUPPORTED, "Only 8 or 16 bpc PSD files supported!"); c = get16be(&source); if (c == 4) /* CMYK (+ Spots?) */ { if (n != 4) fz_throw(ctx, FZ_ERROR_UNSUPPORTED, "CMYK PSD with %d chans not supported!", n); info->cs = fz_keep_colorspace(ctx, fz_device_cmyk(ctx)); } else if (c == 3) /* RGB */ { if (n == 4) alpha = 1; else if (n != 3) fz_throw(ctx, FZ_ERROR_UNSUPPORTED, "RGB PSD with %d chans not supported!", n); info->cs = fz_keep_colorspace(ctx, fz_device_rgb(ctx)); } else if (c == 1) /* Greyscale */ { if (n != 1) fz_throw(ctx, FZ_ERROR_UNSUPPORTED, "Greyscale PSD with %d chans not supported!", n); info->cs = fz_keep_colorspace(ctx, fz_device_gray(ctx)); } else fz_throw(ctx, FZ_ERROR_UNSUPPORTED, "Unsupported PSD colorspace (%d)!", c); v = get32be(&source); if (v != 0) fz_throw(ctx, FZ_ERROR_FORMAT, "Unexpected color data in PSD!"); /* Now read image resources... */ ir_len = getu32be(&source); while (ir_len >= 12) { size_t start = source.p - p; v = get32be(&source); if (v != 0x3842494d) /* 8BIM */ fz_throw(ctx, FZ_ERROR_FORMAT, "Failed to find expected 8BIM in PSD"); v = get16be(&source); fz_free(ctx, getString(&source)); data_len = getu32be(&source); ir_len -= (source.p - p) - start; switch (v) { case 0x3ef: /* Spot */ { int spots = 0; int alpha_found = 0; while (data_len > 0) { int C, M, Y, K; char text[32]; v = get16be(&source); if (v == 0 && alpha_found == 0) alpha_found = 1, alpha = 1; else if (v != 2) fz_throw(ctx, FZ_ERROR_FORMAT, "Non CMYK spot found in PSD"); C = 0xff - (get16be(&source)>>8); M = 0xff - (get16be(&source)>>8); Y = 0xff - (get16be(&source)>>8); K = 0xff - (get16be(&source)>>8); (void)get16be(&source); /* opacity */ (void)get8(&source); /* kind */ (void)get8(&source); /* padding */ if (v == 2) { uint32_t cmyk = C | (M<<8) | (Y<<16) | (K<<24); int R = fz_clampi(255-C-K, 0, 255); int G = fz_clampi(255-M-K, 0, 255); int B = fz_clampi(255-Y-K, 0, 255); uint32_t rgba = R | (G<<8) | (B<<16); if (seps == NULL) seps = fz_new_separations(ctx, 1); snprintf(text, sizeof(text), "s%d", spots); /* Use the old entry-point until we fix the new one */ fz_add_separation_equivalents(ctx, seps, rgba, cmyk, text); spots++; } data_len -= 14; ir_len -= 14; } } } /* Skip any unread data */ if (data_len & 1) data_len++; ir_len -= data_len; while (data_len--) get8(&source); } if (fz_count_separations(ctx, seps) + info->cs->n + 1 == n && alpha == 0) alpha = 1; if (fz_count_separations(ctx, seps) + info->cs->n + alpha != n) fz_throw(ctx, FZ_ERROR_FORMAT, "PSD contains mismatching spot/alpha data"); /* Skip over the Layer data. */ v = get32be(&source); if (v != 0) { if (source.total < (size_t)v) fz_throw(ctx, FZ_ERROR_FORMAT, "Truncated PSD"); source.total -= v; source.p += v; } if (source.total == 0) fz_throw(ctx, FZ_ERROR_UNSUPPORTED, "Unflattened PSD not supported"); v = get16be(&source); switch (v) { case 0: /* No compression */ break; case 1: /* Packbits */ source.packbits = 1; source.packbits_n = 128; /* Skip over rows * channels * byte counts. */ m = ((size_t)info->height) * info->n * 2; if (m > source.total) fz_throw(ctx, FZ_ERROR_FORMAT, "Truncated RLE PSD"); source.total -= m; source.p += m; break; case 2: /* Deflate */ case 3: /* Deflate with prediction */ fz_throw(ctx, FZ_ERROR_UNSUPPORTED, "Deflate PSD not supported"); default: fz_throw(ctx, FZ_ERROR_FORMAT, "Unexpected compression (%d) found in PSD", v); } if (only_metadata) break; m = ((size_t)info->width) * info->height; image = fz_new_pixmap(ctx, info->cs, info->width, info->height, seps, alpha); q = image->samples; if (bpc == 8) { if (n == 1) { while (m--) { *q++ = 255 - unpack8(&source); } } else if (n - alpha == 3) { int N = n; while (N--) { size_t M = m; while (M--) { *q = unpack8(&source); q += n; } q -= m*n - 1; } } else { int N = n - alpha; /* CMYK is inverted */ while (N--) { size_t M = m; while (M--) { *q = 255 - unpack8(&source); q += n; } q -= m*n - 1; } /* But alpha is not */ if (alpha) { size_t M = m; while (M--) { *q = unpack8(&source); q += n; } q -= m*n - 1; } } } else { if (n == 1) { while (m--) { *q++ = 255 - unpack8(&source); (void)unpack8(&source); } } else if (n - alpha == 3) { int N = n; while (N--) { size_t M = m; while (M--) { *q = unpack8(&source); (void)unpack8(&source); q += n; } q -= m*n - 1; } } else { int N = n - alpha; /* CMYK is inverted */ while (N--) { size_t M = m; while (M--) { *q = 255 - unpack8(&source); (void)unpack8(&source); q += n; } q -= m*n - 1; } /* But alpha is not */ if (alpha) { size_t M = m; while (M--) { *q = unpack8(&source); (void)unpack8(&source); q += n; } q -= m*n - 1; } } } if (alpha) fz_premultiply_pixmap(ctx, image); } fz_always(ctx) { fz_drop_separations(ctx, seps); } fz_catch(ctx) { fz_drop_pixmap(ctx, image); fz_drop_colorspace(ctx, info->cs); fz_rethrow(ctx); } return image; } fz_pixmap * fz_load_psd(fz_context *ctx, const unsigned char *p, size_t total) { fz_pixmap *image = NULL; struct info psd; image = psd_read_image(ctx, &psd, p, total, 0); fz_drop_colorspace(ctx, psd.cs); return image; } void fz_load_psd_info(fz_context *ctx, const unsigned char *p, size_t total, int *wp, int *hp, int *xresp, int *yresp, fz_colorspace **cspacep) { struct info psd; psd_read_image(ctx, &psd, p, total, 1); *cspacep = psd.cs; *wp = psd.width; *hp = psd.height; *xresp = psd.xres; *yresp = psd.xres; }
