📄 tif_luv.c
字号:
tif->tif_rawcc = tif->tif_rawdatasize - occ;
if (!TIFFFlushData1(tif))
return (-1);
op = tif->tif_rawcp;
occ = tif->tif_rawdatasize - tif->tif_rawcc;
}
mask = 0xff << shft; /* find next run */
for (beg = i; beg < npixels; beg += rc) {
b = tp[beg] & mask;
rc = 1;
while (rc < 127+2 && beg+rc < npixels &&
(tp[beg+rc] & mask) == b)
rc++;
if (rc >= MINRUN)
break; /* long enough */
}
if (beg-i > 1 && beg-i < MINRUN) {
b = tp[i] & mask; /* check short run */
j = i+1;
while ((tp[j++] & mask) == b)
if (j == beg) {
*op++ = (tidataval_t)(128-2+j-i);
*op++ = (tidataval_t)(b >> shft);
occ -= 2;
i = beg;
break;
}
}
while (i < beg) { /* write out non-run */
if ((j = beg-i) > 127) j = 127;
if (occ < j+3) {
tif->tif_rawcp = op;
tif->tif_rawcc = tif->tif_rawdatasize - occ;
if (!TIFFFlushData1(tif))
return (-1);
op = tif->tif_rawcp;
occ = tif->tif_rawdatasize - tif->tif_rawcc;
}
*op++ = (tidataval_t) j; occ--;
while (j--) {
*op++ = (tidataval_t)(tp[i++] >> shft & 0xff);
occ--;
}
}
if (rc >= MINRUN) { /* write out run */
*op++ = (tidataval_t) (128-2+rc);
*op++ = (tidataval_t)(tp[beg] >> shft & 0xff);
occ -= 2;
} else
rc = 0;
}
tif->tif_rawcp = op;
tif->tif_rawcc = tif->tif_rawdatasize - occ;
return (0);
}
/*
* Encode a strip of pixels. We break it into rows to
* avoid encoding runs across row boundaries.
*/
static int
LogLuvEncodeStrip(TIFF* tif, tidata_t bp, tsize_t cc, tsample_t s)
{
tsize_t rowlen = TIFFScanlineSize(tif);
assert(cc%rowlen == 0);
while (cc && (*tif->tif_encoderow)(tif, bp, rowlen, s) == 0)
bp += rowlen, cc -= rowlen;
return (cc == 0);
}
/*
* Encode a tile of pixels. We break it into rows to
* avoid encoding runs across row boundaries.
*/
static int
LogLuvEncodeTile(TIFF* tif, tidata_t bp, tsize_t cc, tsample_t s)
{
tsize_t rowlen = TIFFTileRowSize(tif);
assert(cc%rowlen == 0);
while (cc && (*tif->tif_encoderow)(tif, bp, rowlen, s) == 0)
bp += rowlen, cc -= rowlen;
return (cc == 0);
}
/*
* Encode/Decode functions for converting to and from user formats.
*/
#include "uvcode.h"
#ifndef UVSCALE
#define U_NEU 0.210526316
#define V_NEU 0.473684211
#define UVSCALE 410.
#endif
#ifndef M_LN2
#define M_LN2 0.69314718055994530942
#endif
#ifndef M_PI
#define M_PI 3.14159265358979323846
#endif
#define log2(x) ((1./M_LN2)*log(x))
#define exp2(x) exp(M_LN2*(x))
#define itrunc(x,m) ((m)==SGILOGENCODE_NODITHER ? \
(int)(x) : \
(int)((x) + rand()*(1./RAND_MAX) - .5))
#if !LOGLUV_PUBLIC
static
#endif
double
LogL16toY(int p16) /* compute luminance from 16-bit LogL */
{
int Le = p16 & 0x7fff;
double Y;
if (!Le)
return (0.);
Y = exp(M_LN2/256.*(Le+.5) - M_LN2*64.);
return (!(p16 & 0x8000) ? Y : -Y);
}
#if !LOGLUV_PUBLIC
static
#endif
int
LogL16fromY(double Y, int em) /* get 16-bit LogL from Y */
{
if (Y >= 1.8371976e19)
return (0x7fff);
if (Y <= -1.8371976e19)
return (0xffff);
if (Y > 5.4136769e-20)
return itrunc(256.*(log2(Y) + 64.), em);
if (Y < -5.4136769e-20)
return (~0x7fff | itrunc(256.*(log2(-Y) + 64.), em));
return (0);
}
static void
L16toY(LogLuvState* sp, tidata_t op, int n)
{
int16* l16 = (int16*) sp->tbuf;
float* yp = (float*) op;
while (n-- > 0)
*yp++ = (float)LogL16toY(*l16++);
}
static void
L16toGry(LogLuvState* sp, tidata_t op, int n)
{
int16* l16 = (int16*) sp->tbuf;
uint8* gp = (uint8*) op;
while (n-- > 0) {
double Y = LogL16toY(*l16++);
*gp++ = (uint8) ((Y <= 0.) ? 0 : (Y >= 1.) ? 255 : (int)(256.*sqrt(Y)));
}
}
static void
L16fromY(LogLuvState* sp, tidata_t op, int n)
{
int16* l16 = (int16*) sp->tbuf;
float* yp = (float*) op;
while (n-- > 0)
*l16++ = (int16) (LogL16fromY(*yp++, sp->encode_meth));
}
#if !LOGLUV_PUBLIC
static
#endif
void
XYZtoRGB24(float xyz[3], uint8 rgb[3])
{
double r, g, b;
/* assume CCIR-709 primaries */
r = 2.690*xyz[0] + -1.276*xyz[1] + -0.414*xyz[2];
g = -1.022*xyz[0] + 1.978*xyz[1] + 0.044*xyz[2];
b = 0.061*xyz[0] + -0.224*xyz[1] + 1.163*xyz[2];
/* assume 2.0 gamma for speed */
/* could use integer sqrt approx., but this is probably faster */
rgb[0] = (uint8)((r<=0.) ? 0 : (r >= 1.) ? 255 : (int)(256.*sqrt(r)));
rgb[1] = (uint8)((g<=0.) ? 0 : (g >= 1.) ? 255 : (int)(256.*sqrt(g)));
rgb[2] = (uint8)((b<=0.) ? 0 : (b >= 1.) ? 255 : (int)(256.*sqrt(b)));
}
#if !LOGLUV_PUBLIC
static
#endif
double
LogL10toY(int p10) /* compute luminance from 10-bit LogL */
{
if (p10 == 0)
return (0.);
return (exp(M_LN2/64.*(p10+.5) - M_LN2*12.));
}
#if !LOGLUV_PUBLIC
static
#endif
int
LogL10fromY(double Y, int em) /* get 10-bit LogL from Y */
{
if (Y >= 15.742)
return (0x3ff);
else if (Y <= .00024283)
return (0);
else
return itrunc(64.*(log2(Y) + 12.), em);
}
#define NANGLES 100
#define uv2ang(u, v) ( (NANGLES*.499999999/M_PI) \
* atan2((v)-V_NEU,(u)-U_NEU) + .5*NANGLES )
static int
oog_encode(double u, double v) /* encode out-of-gamut chroma */
{
static int oog_table[NANGLES];
static int initialized = 0;
register int i;
if (!initialized) { /* set up perimeter table */
double eps[NANGLES], ua, va, ang, epsa;
int ui, vi, ustep;
for (i = NANGLES; i--; )
eps[i] = 2.;
for (vi = UV_NVS; vi--; ) {
va = UV_VSTART + (vi+.5)*UV_SQSIZ;
ustep = uv_row[vi].nus-1;
if (vi == UV_NVS-1 || vi == 0 || ustep <= 0)
ustep = 1;
for (ui = uv_row[vi].nus-1; ui >= 0; ui -= ustep) {
ua = uv_row[vi].ustart + (ui+.5)*UV_SQSIZ;
ang = uv2ang(ua, va);
i = (int) ang;
epsa = fabs(ang - (i+.5));
if (epsa < eps[i]) {
oog_table[i] = uv_row[vi].ncum + ui;
eps[i] = epsa;
}
}
}
for (i = NANGLES; i--; ) /* fill any holes */
if (eps[i] > 1.5) {
int i1, i2;
for (i1 = 1; i1 < NANGLES/2; i1++)
if (eps[(i+i1)%NANGLES] < 1.5)
break;
for (i2 = 1; i2 < NANGLES/2; i2++)
if (eps[(i+NANGLES-i2)%NANGLES] < 1.5)
break;
if (i1 < i2)
oog_table[i] =
oog_table[(i+i1)%NANGLES];
else
oog_table[i] =
oog_table[(i+NANGLES-i2)%NANGLES];
}
initialized = 1;
}
i = (int) uv2ang(u, v); /* look up hue angle */
return (oog_table[i]);
}
#undef uv2ang
#undef NANGLES
#if !LOGLUV_PUBLIC
static
#endif
int
uv_encode(double u, double v, int em) /* encode (u',v') coordinates */
{
register int vi, ui;
if (v < UV_VSTART)
return oog_encode(u, v);
vi = itrunc((v - UV_VSTART)*(1./UV_SQSIZ), em);
if (vi >= UV_NVS)
return oog_encode(u, v);
if (u < uv_row[vi].ustart)
return oog_encode(u, v);
ui = itrunc((u - uv_row[vi].ustart)*(1./UV_SQSIZ), em);
if (ui >= uv_row[vi].nus)
return oog_encode(u, v);
return (uv_row[vi].ncum + ui);
}
#if !LOGLUV_PUBLIC
static
#endif
int
uv_decode(double *up, double *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+.5)*UV_SQSIZ;
*vp = UV_VSTART + (vi+.5)*UV_SQSIZ;
return (0);
}
#if !LOGLUV_PUBLIC
static
#endif
void
LogLuv24toXYZ(uint32 p, float XYZ[3])
{
int Ce;
double L, u, v, s, x, y;
/* decode luminance */
L = LogL10toY(p>>14 & 0x3ff);
if (L <= 0.) {
XYZ[0] = XYZ[1] = XYZ[2] = 0.;
return;
}
/* decode color */
Ce = p & 0x3fff;
if (uv_decode(&u, &v, Ce) < 0) {
u = U_NEU; v = V_NEU;
}
s = 1./(6.*u - 16.*v + 12.);
x = 9.*u * s;
y = 4.*v * s;
/* convert to XYZ */
XYZ[0] = (float)(x/y * L);
XYZ[1] = (float)L;
XYZ[2] = (float)((1.-x-y)/y * L);
}
#if !LOGLUV_PUBLIC
static
#endif
uint32
LogLuv24fromXYZ(float XYZ[3], int em)
{
int Le, Ce;
double u, v, s;
/* encode luminance */
Le = LogL10fromY(XYZ[1], em);
/* encode color */
s = XYZ[0] + 15.*XYZ[1] + 3.*XYZ[2];
if (!Le || s <= 0.) {
u = U_NEU;
v = V_NEU;
} else {
u = 4.*XYZ[0] / s;
v = 9.*XYZ[1] / s;
}
Ce = uv_encode(u, v, em);
if (Ce < 0) /* never happens */
Ce = uv_encode(U_NEU, V_NEU, SGILOGENCODE_NODITHER);
/* combine encodings */
return (Le << 14 | Ce);
}
static void
Luv24toXYZ(LogLuvState* sp, tidata_t op, int n)
{
uint32* luv = (uint32*) sp->tbuf;
float* xyz = (float*) op;
while (n-- > 0) {
LogLuv24toXYZ(*luv, xyz);
xyz += 3;
luv++;
}
}
static void
Luv24toLuv48(LogLuvState* sp, tidata_t op, int n)
{
uint32* luv = (uint32*) sp->tbuf;
int16* luv3 = (int16*) op;
while (n-- > 0) {
double u, v;
*luv3++ = (int16)((*luv >> 12 & 0xffd) + 13314);
if (uv_decode(&u, &v, *luv&0x3fff) < 0) {
u = U_NEU;
v = V_NEU;
}
*luv3++ = (int16)(u * (1L<<15));
*luv3++ = (int16)(v * (1L<<15));
luv++;
}
}
static void
Luv24toRGB(LogLuvState* sp, tidata_t op, int n)
{
uint32* luv = (uint32*) sp->tbuf;
uint8* rgb = (uint8*) op;
while (n-- > 0) {
float xyz[3];
LogLuv24toXYZ(*luv++, xyz);
XYZtoRGB24(xyz, rgb);
rgb += 3;
}
}
static void
Luv24fromXYZ(LogLuvState* sp, tidata_t op, int n)
{
uint32* luv = (uint32*) sp->tbuf;
float* xyz = (float*) op;
while (n-- > 0) {
*luv++ = LogLuv24fromXYZ(xyz, sp->encode_meth);
xyz += 3;
}
}
static void
Luv24fromLuv48(LogLuvState* sp, tidata_t op, int n)
{
uint32* luv = (uint32*) sp->tbuf;
int16* luv3 = (int16*) op;
while (n-- > 0) {
int Le, Ce;
if (luv3[0] <= 0)
Le = 0;
else if (luv3[0] >= (1<<12)+3314)
Le = (1<<10) - 1;
else if (sp->encode_meth == SGILOGENCODE_NODITHER)
Le = (luv3[0]-3314) >> 2;
else
Le = itrunc(.25*(luv3[0]-3314.), sp->encode_meth);
Ce = uv_encode((luv3[1]+.5)/(1<<15), (luv3[2]+.5)/(1<<15),
sp->encode_meth);
if (Ce < 0) /* never happens */
Ce = uv_encode(U_NEU, V_NEU, SGILOGENCODE_NODITHER);
*luv++ = (uint32)Le << 14 | Ce;
luv3 += 3;
}
}
#if !LOGLUV_PUBLIC
static
#endif
void
LogLuv32toXYZ(uint32 p, float XYZ[3])
{
double L, u, v, s, x, y;
/* decode luminance */
L = LogL16toY((int)p >> 16);
if (L <= 0.) {
XYZ[0] = XYZ[1] = XYZ[2] = 0.;
return;
}
/* decode color */
u = 1./UVSCALE * ((p>>8 & 0xff) + .5);
v = 1./UVSCALE * ((p & 0xff) + .5);
s = 1./(6.*u - 16.*v + 12.);
x = 9.*u * s;
y = 4.*v * s;
/* convert to XYZ */
XYZ[0] = (float)(x/y * L);
XYZ[1] = (float)L;
XYZ[2] = (float)((1.-x-y)/y * L);
}
#if !LOGLUV_PUBLIC
static
#endif
uint32
LogLuv32fromXYZ(float XYZ[3], int em)
{
unsigned int Le, ue, ve;
double u, v, s;
/* encode luminance */
Le = (unsigned int)LogL16fromY(XYZ[1], em);
/* encode color */
s = XYZ[0] + 15.*XYZ[1] + 3.*XYZ[2];
if (!Le || s <= 0.) {
u = U_NEU;
v = V_NEU;
} else {
u = 4.*XYZ[0] / s;
v = 9.*XYZ[1] / s;
}
if (u <= 0.) ue = 0;
else ue = itrunc(UVSCALE*u, em);
if (ue > 255) ue = 255;
if (v <= 0.) ve = 0;
else ve = itrunc(UVSCALE*v, em);
if (ve > 255) ve = 255;
/* combine encodings */
return (Le << 16 | ue << 8 | ve);
}
static void
Luv32toXYZ(LogLuvState* sp, tidata_t op, int n)
{
uint32* luv = (uint32*) sp->tbuf;
float* xyz = (float*) op;
while (n-- > 0) {
LogLuv32toXYZ(*luv++, xyz);
xyz += 3;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -