eBookReaderSwitch/source/fitz/filter-sgi.c

668 lines
14 KiB
C

#include "mupdf/fitz.h"
#include <math.h>
#include <string.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 },
};
/* 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(FZ_LN2/256 * (Le + .5f) - FZ_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, size_t 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 = fz_malloc_struct(ctx, fz_sgilog16);
fz_try(ctx)
{
state->run = 0;
state->n = 0;
state->c = 0;
state->w = w;
state->temp = fz_malloc(ctx, w * sizeof(uint16_t));
state->chain = fz_keep_stream(ctx, chain);
}
fz_catch(ctx)
{
fz_free(ctx, state->temp);
fz_free(ctx, state);
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(FZ_LN2/64*(p+.5f) - FZ_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, size_t 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 = fz_malloc_struct(ctx, fz_sgilog24);
fz_try(ctx)
{
state->err = 0;
state->w = w;
state->temp = fz_malloc(ctx, w * 3);
state->chain = fz_keep_stream(ctx, chain);
}
fz_catch(ctx)
{
fz_free(ctx, state->temp);
fz_free(ctx, state);
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(FZ_LN2/256*(Le+.5f) - FZ_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, size_t 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_drop_stream(ctx, state->chain);
fz_free(ctx, state->temp);
fz_free(ctx, state);
}
fz_stream *
fz_open_sgilog32(fz_context *ctx, fz_stream *chain, int w)
{
fz_sgilog32 *state = fz_malloc_struct(ctx, fz_sgilog32);
fz_try(ctx)
{
state->run = 0;
state->n = 0;
state->c = 0;
state->w = w;
state->temp = fz_malloc(ctx, w * sizeof(uint32_t));
state->chain = fz_keep_stream(ctx, chain);
}
fz_catch(ctx)
{
fz_free(ctx, state->temp);
fz_free(ctx, state);
fz_rethrow(ctx);
}
return fz_new_stream(ctx, state, next_sgilog32, close_sgilog32);
}