diff options
author | Robin Watts <robin.watts@artifex.com> | 2016-06-14 13:01:57 +0100 |
---|---|---|
committer | Robin Watts <robin.watts@artifex.com> | 2016-06-14 13:06:02 +0100 |
commit | 44d65838233baef2c16397847dca3061cde7ec4e (patch) | |
tree | 711862be21c83e7a6fd8dbe22ee5329335eadfd9 /source/fitz | |
parent | 24c55cc6c823a8d6d76ee3c7a41e5832d8031385 (diff) | |
download | mupdf-44d65838233baef2c16397847dca3061cde7ec4e.tar.xz |
Add TIFF SGI LUV decoding.
Diffstat (limited to 'source/fitz')
-rw-r--r-- | source/fitz/filter-sgi.c | 683 | ||||
-rw-r--r-- | source/fitz/load-tiff.c | 42 |
2 files changed, 725 insertions, 0 deletions
diff --git a/source/fitz/filter-sgi.c b/source/fitz/filter-sgi.c new file mode 100644 index 00000000..c0fd9a74 --- /dev/null +++ b/source/fitz/filter-sgi.c @@ -0,0 +1,683 @@ +#include "mupdf/fitz/system.h" +#include "mupdf/fitz/context.h" +#include "mupdf/fitz/stream.h" + +/* Table stolen from LibTiff */ +#define UV_SQSIZ 0.003500f +#define UV_NDIVS 16289 +#define UV_VSTART 0.016940f +#define UV_NVS 163 +#define U_NEU 0.210526316f +#define V_NEU 0.473684211f +#define UVSCALE 410 +static struct { + float ustart; + short nus, ncum; +} uv_row[UV_NVS] = { + { 0.247663f, 4, 0 }, + { 0.243779f, 6, 4 }, + { 0.241684f, 7, 10 }, + { 0.237874f, 9, 17 }, + { 0.235906f, 10, 26 }, + { 0.232153f, 12, 36 }, + { 0.228352f, 14, 48 }, + { 0.226259f, 15, 62 }, + { 0.222371f, 17, 77 }, + { 0.220410f, 18, 94 }, + { 0.214710f, 21, 112 }, + { 0.212714f, 22, 133 }, + { 0.210721f, 23, 155 }, + { 0.204976f, 26, 178 }, + { 0.202986f, 27, 204 }, + { 0.199245f, 29, 231 }, + { 0.195525f, 31, 260 }, + { 0.193560f, 32, 291 }, + { 0.189878f, 34, 323 }, + { 0.186216f, 36, 357 }, + { 0.186216f, 36, 393 }, + { 0.182592f, 38, 429 }, + { 0.179003f, 40, 467 }, + { 0.175466f, 42, 507 }, + { 0.172001f, 44, 549 }, + { 0.172001f, 44, 593 }, + { 0.168612f, 46, 637 }, + { 0.168612f, 46, 683 }, + { 0.163575f, 49, 729 }, + { 0.158642f, 52, 778 }, + { 0.158642f, 52, 830 }, + { 0.158642f, 52, 882 }, + { 0.153815f, 55, 934 }, + { 0.153815f, 55, 989 }, + { 0.149097f, 58, 1044 }, + { 0.149097f, 58, 1102 }, + { 0.142746f, 62, 1160 }, + { 0.142746f, 62, 1222 }, + { 0.142746f, 62, 1284 }, + { 0.138270f, 65, 1346 }, + { 0.138270f, 65, 1411 }, + { 0.138270f, 65, 1476 }, + { 0.132166f, 69, 1541 }, + { 0.132166f, 69, 1610 }, + { 0.126204f, 73, 1679 }, + { 0.126204f, 73, 1752 }, + { 0.126204f, 73, 1825 }, + { 0.120381f, 77, 1898 }, + { 0.120381f, 77, 1975 }, + { 0.120381f, 77, 2052 }, + { 0.120381f, 77, 2129 }, + { 0.112962f, 82, 2206 }, + { 0.112962f, 82, 2288 }, + { 0.112962f, 82, 2370 }, + { 0.107450f, 86, 2452 }, + { 0.107450f, 86, 2538 }, + { 0.107450f, 86, 2624 }, + { 0.107450f, 86, 2710 }, + { 0.100343f, 91, 2796 }, + { 0.100343f, 91, 2887 }, + { 0.100343f, 91, 2978 }, + { 0.095126f, 95, 3069 }, + { 0.095126f, 95, 3164 }, + { 0.095126f, 95, 3259 }, + { 0.095126f, 95, 3354 }, + { 0.088276f, 100, 3449 }, + { 0.088276f, 100, 3549 }, + { 0.088276f, 100, 3649 }, + { 0.088276f, 100, 3749 }, + { 0.081523f, 105, 3849 }, + { 0.081523f, 105, 3954 }, + { 0.081523f, 105, 4059 }, + { 0.081523f, 105, 4164 }, + { 0.074861f, 110, 4269 }, + { 0.074861f, 110, 4379 }, + { 0.074861f, 110, 4489 }, + { 0.074861f, 110, 4599 }, + { 0.068290f, 115, 4709 }, + { 0.068290f, 115, 4824 }, + { 0.068290f, 115, 4939 }, + { 0.068290f, 115, 5054 }, + { 0.063573f, 119, 5169 }, + { 0.063573f, 119, 5288 }, + { 0.063573f, 119, 5407 }, + { 0.063573f, 119, 5526 }, + { 0.057219f, 124, 5645 }, + { 0.057219f, 124, 5769 }, + { 0.057219f, 124, 5893 }, + { 0.057219f, 124, 6017 }, + { 0.050985f, 129, 6141 }, + { 0.050985f, 129, 6270 }, + { 0.050985f, 129, 6399 }, + { 0.050985f, 129, 6528 }, + { 0.050985f, 129, 6657 }, + { 0.044859f, 134, 6786 }, + { 0.044859f, 134, 6920 }, + { 0.044859f, 134, 7054 }, + { 0.044859f, 134, 7188 }, + { 0.040571f, 138, 7322 }, + { 0.040571f, 138, 7460 }, + { 0.040571f, 138, 7598 }, + { 0.040571f, 138, 7736 }, + { 0.036339f, 142, 7874 }, + { 0.036339f, 142, 8016 }, + { 0.036339f, 142, 8158 }, + { 0.036339f, 142, 8300 }, + { 0.032139f, 146, 8442 }, + { 0.032139f, 146, 8588 }, + { 0.032139f, 146, 8734 }, + { 0.032139f, 146, 8880 }, + { 0.027947f, 150, 9026 }, + { 0.027947f, 150, 9176 }, + { 0.027947f, 150, 9326 }, + { 0.023739f, 154, 9476 }, + { 0.023739f, 154, 9630 }, + { 0.023739f, 154, 9784 }, + { 0.023739f, 154, 9938 }, + { 0.019504f, 158, 10092 }, + { 0.019504f, 158, 10250 }, + { 0.019504f, 158, 10408 }, + { 0.016976f, 161, 10566 }, + { 0.016976f, 161, 10727 }, + { 0.016976f, 161, 10888 }, + { 0.016976f, 161, 11049 }, + { 0.012639f, 165, 11210 }, + { 0.012639f, 165, 11375 }, + { 0.012639f, 165, 11540 }, + { 0.009991f, 168, 11705 }, + { 0.009991f, 168, 11873 }, + { 0.009991f, 168, 12041 }, + { 0.009016f, 170, 12209 }, + { 0.009016f, 170, 12379 }, + { 0.009016f, 170, 12549 }, + { 0.006217f, 173, 12719 }, + { 0.006217f, 173, 12892 }, + { 0.005097f, 175, 13065 }, + { 0.005097f, 175, 13240 }, + { 0.005097f, 175, 13415 }, + { 0.003909f, 177, 13590 }, + { 0.003909f, 177, 13767 }, + { 0.002340f, 177, 13944 }, + { 0.002389f, 170, 14121 }, + { 0.001068f, 164, 14291 }, + { 0.001653f, 157, 14455 }, + { 0.000717f, 150, 14612 }, + { 0.001614f, 143, 14762 }, + { 0.000270f, 136, 14905 }, + { 0.000484f, 129, 15041 }, + { 0.001103f, 123, 15170 }, + { 0.001242f, 115, 15293 }, + { 0.001188f, 109, 15408 }, + { 0.001011f, 103, 15517 }, + { 0.000709f, 97, 15620 }, + { 0.000301f, 89, 15717 }, + { 0.002416f, 82, 15806 }, + { 0.003251f, 76, 15888 }, + { 0.003246f, 69, 15964 }, + { 0.004141f, 62, 16033 }, + { 0.005963f, 55, 16095 }, + { 0.008839f, 47, 16150 }, + { 0.010490f, 40, 16197 }, + { 0.016994f, 31, 16237 }, + { 0.023659f, 21, 16268 }, +}; + +#ifndef M_LN2 +#define M_LN2 0.69314718055994530942 +#endif + +/* SGI Log 16bit (greyscale) */ + +typedef struct fz_sgilog16_s fz_sgilog16; + +struct fz_sgilog16_s +{ + fz_stream *chain; + int run, n, c, w; + uint16_t *temp; +}; + +static inline int +sgilog16val(fz_context *ctx, uint16_t v) +{ + int Le; + float Y; + + Le = v & 0x7fff; + if (!Le) + Y = 0; + else + { + Y = expf(M_LN2/256 * (Le + .5f) - M_LN2*64); + if (v & 0x8000) + Y = -Y; + } + + return ((Y <= 0) ? 0 : (Y >= 1) ? 255 : (int)(256*sqrtf(Y))); +} + +static int +next_sgilog16(fz_context *ctx, fz_stream *stm, int max) +{ + fz_sgilog16 *state = stm->state; + uint16_t *p; + uint16_t *ep; + uint8_t *q; + int shift; + + (void)max; + + if (state->run < 0) + return EOF; + + memset(state->temp, 0, state->w * sizeof(uint16_t)); + + for (shift = 8; shift >= 0; shift -= 8) + { + p = state->temp; + ep = p + state->w; + while (p < ep) + { + if (state->n == 0) + { + state->run = fz_read_byte(ctx, state->chain); + if (state->run < 0) + { + state->run = -1; + fz_throw(ctx, FZ_ERROR_GENERIC, "premature end of data in run length decode"); + } + if (state->run < 128) + state->n = state->run; + else + { + state->n = state->run - 126; + state->c = fz_read_byte(ctx, state->chain); + if (state->c < 0) + { + state->run = -1; + fz_throw(ctx, FZ_ERROR_GENERIC, "premature end of data in run length decode"); + } + } + } + + if (state->run < 128) + { + while (p < ep && state->n) + { + int c = fz_read_byte(ctx, state->chain); + if (c < 0) + { + state->run = -1; + fz_throw(ctx, FZ_ERROR_GENERIC, "premature end of data in run length decode"); + } + *p++ |= c<<shift; + state->n--; + } + } + else + { + while (p < ep && state->n) + { + *p++ |= state->c<<shift; + state->n--; + } + } + } + } + + p = state->temp; + q = (uint8_t *)p; + ep = p + state->w; + while (p < ep) + { + *q++ = sgilog16val(ctx, *p++); + } + + stm->rp = (uint8_t *)(state->temp); + stm->wp = q; + stm->pos += q - stm->rp; + + if (q == stm->rp) + return EOF; + + return *stm->rp++; +} + +static void +close_sgilog16(fz_context *ctx, void *state_) +{ + fz_sgilog16 *state = (fz_sgilog16 *)state_; + fz_stream *chain = state->chain; + + fz_free(ctx, state->temp); + fz_free(ctx, state); + fz_drop_stream(ctx, chain); +} + +fz_stream * +fz_open_sgilog16(fz_context *ctx, fz_stream *chain, int w) +{ + fz_sgilog16 *state = NULL; + + fz_var(state); + + fz_try(ctx) + { + state = fz_malloc_struct(ctx, fz_sgilog16); + state->chain = chain; + state->run = 0; + state->n = 0; + state->c = 0; + state->w = w; + state->temp = fz_malloc(ctx, w * sizeof(uint16_t)); + } + fz_catch(ctx) + { + fz_free(ctx, state); + fz_drop_stream(ctx, chain); + fz_rethrow(ctx); + } + + return fz_new_stream(ctx, state, next_sgilog16, close_sgilog16); +} + +/* SGI Log 24bit (LUV) */ + +typedef struct fz_sgilog24_s fz_sgilog24; + +struct fz_sgilog24_s +{ + fz_stream *chain; + int err, w; + uint8_t *temp; +}; + +static int +uv_decode(float *up, float *vp, int c) /* decode (u',v') index */ +{ + int upper, lower; + register int ui, vi; + + if (c < 0 || c >= UV_NDIVS) + return (-1); + lower = 0; /* binary search */ + upper = UV_NVS; + while (upper - lower > 1) { + vi = (lower + upper) >> 1; + ui = c - uv_row[vi].ncum; + if (ui > 0) + lower = vi; + else if (ui < 0) + upper = vi; + else { + lower = vi; + break; + } + } + vi = lower; + ui = c - uv_row[vi].ncum; + *up = uv_row[vi].ustart + (ui+.5f)*UV_SQSIZ; + *vp = UV_VSTART + (vi+.5f)*UV_SQSIZ; + return (0); +} + +static inline int +sgilog24val(fz_context *ctx, fz_stream *chain, uint8_t *rgb) +{ + int b0, b1, b2; + int luv, p; + float u, v, s, x, y, X, Y, Z; + float r, g, b; + + b0 = fz_read_byte(ctx, chain); + if (b0 < 0) + return b0; + b1 = fz_read_byte(ctx, chain); + if (b1 < 0) + return b1; + b2 = fz_read_byte(ctx, chain); + if (b2 < 0) + return b2; + + luv = (b0<<16) | (b1<<8) | b2; + + /* decode luminance */ + p = (luv>>14) & 0x3ff; + Y = (p == 0 ? 0 : expf(M_LN2/64*(p+.5f) - M_LN2*12)); + if (Y <= 0) + { + X = Y = Z = 0; + } + else + { + /* decode color */ + if (uv_decode(&u, &v, luv & 0x3fff) < 0) { + u = U_NEU; v = V_NEU; + } + s = 6*u - 16*v + 12; + x = 9*u; + y = 4*v; + /* convert to XYZ */ + X = x/y * Y; + Z = (s-x-y)/y * Y; + } + + /* assume CCIR-709 primaries */ + r = 2.690f*X + -1.276f*Y + -0.414f*Z; + g = -1.022f*X + 1.978f*Y + 0.044f*Z; + b = 0.061f*X + -0.224f*Y + 1.163f*Z; + + /* assume 2.0 gamma for speed */ + /* could use integer sqrt approx., but this is probably faster */ + rgb[0] = (uint8_t)((r<=0) ? 0 : (r >= 1) ? 255 : (int)(256*sqrtf(r))); + rgb[1] = (uint8_t)((g<=0) ? 0 : (g >= 1) ? 255 : (int)(256*sqrtf(g))); + rgb[2] = (uint8_t)((b<=0) ? 0 : (b >= 1) ? 255 : (int)(256*sqrtf(b))); + + return 0; +} + +static int +next_sgilog24(fz_context *ctx, fz_stream *stm, int max) +{ + fz_sgilog24 *state = stm->state; + uint8_t *p; + uint8_t *ep; + + (void)max; + + if (state->err) + return EOF; + + memset(state->temp, 0, state->w * 3); + + p = state->temp; + ep = p + state->w * 3; + while (p < ep) + { + int c = sgilog24val(ctx, state->chain, p); + if (c < 0) + { + state->err = 1; + fz_throw(ctx, FZ_ERROR_GENERIC, "premature end of data in run length decode"); + } + p += 3; + } + + stm->rp = state->temp; + stm->wp = p; + stm->pos += p - stm->rp; + + if (p == stm->rp) + return EOF; + + return *stm->rp++; +} + +static void +close_sgilog24(fz_context *ctx, void *state_) +{ + fz_sgilog24 *state = (fz_sgilog24 *)state_; + fz_stream *chain = state->chain; + + fz_free(ctx, state->temp); + fz_free(ctx, state); + fz_drop_stream(ctx, chain); +} + +fz_stream * +fz_open_sgilog24(fz_context *ctx, fz_stream *chain, int w) +{ + fz_sgilog24 *state = NULL; + + fz_var(state); + + fz_try(ctx) + { + state = fz_malloc_struct(ctx, fz_sgilog24); + state->chain = chain; + state->err = 0; + state->w = w; + state->temp = fz_malloc(ctx, w * 3); + } + fz_catch(ctx) + { + fz_free(ctx, state); + fz_drop_stream(ctx, chain); + fz_rethrow(ctx); + } + + return fz_new_stream(ctx, state, next_sgilog24, close_sgilog24); +} + +/* SGI Log 32bit */ + +typedef struct fz_sgilog32_s fz_sgilog32; + +struct fz_sgilog32_s +{ + fz_stream *chain; + int run, n, c, w; + uint32_t *temp; +}; + +static inline void +sgilog32val(fz_context *ctx, uint32_t p, uint8_t *rgb) +{ + float r, g, b; + float u, v, s, x, y; + float X, Y, Z; + + if (p>>31) + { + X = Y = Z = 0; + } + else + { + int Le = (p>>16) & 0x7fff; + Y = !Le ? 0 : expf(M_LN2/256*(Le+.5f) - M_LN2*64); + /* decode color */ + u = (1.f/UVSCALE) * ((p>>8 & 0xff) + .5f); + v = (1.f/UVSCALE) * ((p & 0xff) + .5f); + s = 6*u - 16*v + 12; + x = 9 * u; + y = 4 * v; + + /* convert to XYZ */ + X = x/y * Y; + Z = (s-x-y)/y * Y; + } + + /* assume CCIR-709 primaries */ + r = 2.690f*X + -1.276f*Y + -0.414f*Z; + g = -1.022f*X + 1.978f*Y + 0.044f*Z; + b = 0.061f*X + -0.224f*Y + 1.163f*Z; + + /* assume 2.0 gamma for speed */ + /* could use integer sqrt approx., but this is probably faster */ + rgb[0] = (uint8_t)((r<=0) ? 0 : (r >= 1) ? 255 : (int)(256*sqrtf(r))); + rgb[1] = (uint8_t)((g<=0) ? 0 : (g >= 1) ? 255 : (int)(256*sqrtf(g))); + rgb[2] = (uint8_t)((b<=0) ? 0 : (b >= 1) ? 255 : (int)(256*sqrtf(b))); +} + +static int +next_sgilog32(fz_context *ctx, fz_stream *stm, int max) +{ + fz_sgilog32 *state = stm->state; + uint32_t *p; + uint32_t *ep; + uint8_t *q; + int shift; + + (void)max; + + if (state->run < 0) + return EOF; + + memset(state->temp, 0, state->w * sizeof(uint32_t)); + + for (shift = 24; shift >= 0; shift -= 8) + { + p = state->temp; + ep = p + state->w; + while (p < ep) + { + if (state->n == 0) + { + state->run = fz_read_byte(ctx, state->chain); + if (state->run < 0) + { + state->run = -1; + fz_throw(ctx, FZ_ERROR_GENERIC, "premature end of data in run length decode"); + } + if (state->run < 128) + state->n = state->run; + else + { + state->n = state->run - 126; + state->c = fz_read_byte(ctx, state->chain); + if (state->c < 0) + { + state->run = -1; + fz_throw(ctx, FZ_ERROR_GENERIC, "premature end of data in run length decode"); + } + } + } + + if (state->run < 128) + { + while (p < ep && state->n) + { + int c = fz_read_byte(ctx, state->chain); + if (c < 0) + { + state->run = -1; + fz_throw(ctx, FZ_ERROR_GENERIC, "premature end of data in run length decode"); + } + *p++ |= c<<shift; + state->n--; + } + } + else + { + while (p < ep && state->n) + { + *p++ |= state->c<<shift; + state->n--; + } + } + } + } + + p = state->temp; + q = (uint8_t *)p; + ep = p + state->w; + while (p < ep) + { + sgilog32val(ctx, *p++, q); + q += 3; + } + + stm->rp = (uint8_t *)(state->temp); + stm->wp = q; + stm->pos += q - stm->rp; + + if (q == stm->rp) + return EOF; + + return *stm->rp++; +} + +static void +close_sgilog32(fz_context *ctx, void *state_) +{ + fz_sgilog32 *state = (fz_sgilog32 *)state_; + fz_stream *chain = state->chain; + + fz_free(ctx, state->temp); + fz_free(ctx, state); + fz_drop_stream(ctx, chain); +} + +fz_stream * +fz_open_sgilog32(fz_context *ctx, fz_stream *chain, int w) +{ + fz_sgilog32 *state = NULL; + + fz_var(state); + + fz_try(ctx) + { + state = fz_malloc_struct(ctx, fz_sgilog32); + state->chain = chain; + state->run = 0; + state->n = 0; + state->c = 0; + state->w = w; + state->temp = fz_malloc(ctx, w * sizeof(uint32_t)); + } + fz_catch(ctx) + { + fz_free(ctx, state); + fz_drop_stream(ctx, chain); + fz_rethrow(ctx); + } + + return fz_new_stream(ctx, state, next_sgilog32, close_sgilog32); +} diff --git a/source/fitz/load-tiff.c b/source/fitz/load-tiff.c index 3df9f7c8..297d71dc 100644 --- a/source/fitz/load-tiff.c +++ b/source/fitz/load-tiff.c @@ -154,6 +154,29 @@ fz_decode_tiff_packbits(fz_context *ctx, struct tiff *tiff, fz_stream *chain, un fz_drop_stream(ctx, stm); } +fz_decode_tiff_sgilog16(fz_context *ctx, struct tiff *tiff, fz_stream *chain, unsigned char *wp, int wlen, int w) +{ + fz_stream *stm = fz_open_sgilog16(ctx, chain, w); + fz_read(ctx, stm, wp, wlen); + fz_drop_stream(ctx, stm); +} + +static void +fz_decode_tiff_sgilog24(fz_context *ctx, struct tiff *tiff, fz_stream *chain, unsigned char *wp, int wlen, int w) +{ + fz_stream *stm = fz_open_sgilog24(ctx, chain, w); + fz_read(ctx, stm, wp, wlen); + fz_drop_stream(ctx, stm); +} + +static void +fz_decode_tiff_sgilog32(fz_context *ctx, struct tiff *tiff, fz_stream *chain, unsigned char *wp, int wlen, int w) +{ + fz_stream *stm = fz_open_sgilog32(ctx, chain, w); + fz_read(ctx, stm, wp, wlen); + fz_drop_stream(ctx, stm); +} + static void fz_decode_tiff_lzw(fz_context *ctx, struct tiff *tiff, fz_stream *chain, unsigned char *wp, int wlen, int old_tiff) { @@ -390,6 +413,16 @@ fz_decode_tiff_strips(fz_context *ctx, struct tiff *tiff) /* it's probably a jpeg ... we let jpeg convert to rgb */ tiff->colorspace = fz_device_rgb(ctx); break; + case 32844: /* SGI CIE Log 2 L (16bpp Greyscale) */ + tiff->colorspace = fz_device_gray(ctx); + tiff->bitspersample = 8; + tiff->stride >>= 1; + break; + case 32845: /* SGI CIE Log 2 L, u, v (24bpp or 32bpp) */ + tiff->colorspace = fz_device_rgb(ctx); + tiff->bitspersample = 8; + tiff->stride >>= 1; + break; default: fz_throw(ctx, FZ_ERROR_GENERIC, "unknown photometric: %d", tiff->photometric); } @@ -471,6 +504,15 @@ fz_decode_tiff_strips(fz_context *ctx, struct tiff *tiff) case 32773: fz_decode_tiff_packbits(ctx, tiff, stm, wp, wlen); break; + case 34676: + if (tiff->photometric == 32845) + fz_decode_tiff_sgilog32(ctx, tiff, stm, wp, wlen, tiff->imagewidth); + else + fz_decode_tiff_sgilog16(ctx, tiff, stm, wp, wlen, tiff->imagewidth); + break; + case 34677: + fz_decode_tiff_sgilog24(ctx, tiff, stm, wp, wlen, tiff->imagewidth); + break; default: fz_throw(ctx, FZ_ERROR_GENERIC, "unknown TIFF compression: %d", tiff->compression); } |