📄 tif_luv.c
字号:
}
}
static void
Luv32toLuv48(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 >> 16);
u = 1./UVSCALE * ((*luv>>8 & 0xff) + .5);
v = 1./UVSCALE * ((*luv & 0xff) + .5);
*luv3++ = (int16)(u * (1L<<15));
*luv3++ = (int16)(v * (1L<<15));
luv++;
}
}
static void
Luv32toRGB(LogLuvState* sp, tidata_t op, int n)
{
uint32* luv = (uint32*) sp->tbuf;
uint8* rgb = (uint8*) op;
while (n-- > 0) {
float xyz[3];
LogLuv32toXYZ(*luv++, xyz);
XYZtoRGB24(xyz, rgb);
rgb += 3;
}
}
static void
Luv32fromXYZ(LogLuvState* sp, tidata_t op, int n)
{
uint32* luv = (uint32*) sp->tbuf;
float* xyz = (float*) op;
while (n-- > 0) {
*luv++ = LogLuv32fromXYZ(xyz, sp->encode_meth);
xyz += 3;
}
}
static void
Luv32fromLuv48(LogLuvState* sp, tidata_t op, int n)
{
uint32* luv = (uint32*) sp->tbuf;
int16* luv3 = (int16*) op;
if (sp->encode_meth == SGILOGENCODE_NODITHER) {
while (n-- > 0) {
*luv++ = (uint32)luv3[0] << 16 |
(luv3[1]*(uint32)(UVSCALE+.5) >> 7 & 0xff00) |
(luv3[2]*(uint32)(UVSCALE+.5) >> 15 & 0xff);
luv3 += 3;
}
return;
}
while (n-- > 0) {
*luv++ = (uint32)luv3[0] << 16 |
(itrunc(luv3[1]*(UVSCALE/(1<<15)), sp->encode_meth) << 8 & 0xff00) |
(itrunc(luv3[2]*(UVSCALE/(1<<15)), sp->encode_meth) & 0xff);
luv3 += 3;
}
}
static void
_logLuvNop(LogLuvState* sp, tidata_t op, int n)
{
(void) sp; (void) op; (void) n;
}
static int
LogL16GuessDataFmt(TIFFDirectory *td)
{
#define PACK(s,b,f) (((b)<<6)|((s)<<3)|(f))
switch (PACK(td->td_samplesperpixel, td->td_bitspersample, td->td_sampleformat)) {
case PACK(1, 32, SAMPLEFORMAT_IEEEFP):
return (SGILOGDATAFMT_FLOAT);
case PACK(1, 16, SAMPLEFORMAT_VOID):
case PACK(1, 16, SAMPLEFORMAT_INT):
case PACK(1, 16, SAMPLEFORMAT_UINT):
return (SGILOGDATAFMT_16BIT);
case PACK(1, 8, SAMPLEFORMAT_VOID):
case PACK(1, 8, SAMPLEFORMAT_UINT):
return (SGILOGDATAFMT_8BIT);
}
#undef PACK
return (SGILOGDATAFMT_UNKNOWN);
}
static uint32
multiply(size_t m1, size_t m2)
{
uint32 bytes = m1 * m2;
if (m1 && bytes / m1 != m2)
bytes = 0;
return bytes;
}
static int
LogL16InitState(TIFF* tif)
{
TIFFDirectory *td = &tif->tif_dir;
LogLuvState* sp = DecoderState(tif);
static const char module[] = "LogL16InitState";
assert(sp != NULL);
assert(td->td_photometric == PHOTOMETRIC_LOGL);
/* for some reason, we can't do this in TIFFInitLogL16 */
if (sp->user_datafmt == SGILOGDATAFMT_UNKNOWN)
sp->user_datafmt = LogL16GuessDataFmt(td);
switch (sp->user_datafmt) {
case SGILOGDATAFMT_FLOAT:
sp->pixel_size = sizeof (float);
break;
case SGILOGDATAFMT_16BIT:
sp->pixel_size = sizeof (int16);
break;
case SGILOGDATAFMT_8BIT:
sp->pixel_size = sizeof (uint8);
break;
default:
TIFFError(tif->tif_name,
"No support for converting user data format to LogL");
return (0);
}
sp->tbuflen = multiply(td->td_imagewidth, td->td_rowsperstrip);
if (multiply(sp->tbuflen, sizeof (int16)) == 0 ||
(sp->tbuf = (tidata_t*) _TIFFmalloc(sp->tbuflen * sizeof (int16))) == NULL) {
TIFFError(module, "%s: No space for SGILog translation buffer",
tif->tif_name);
return (0);
}
return (1);
}
static int
LogLuvGuessDataFmt(TIFFDirectory *td)
{
int guess;
/*
* If the user didn't tell us their datafmt,
* take our best guess from the bitspersample.
*/
#define PACK(a,b) (((a)<<3)|(b))
switch (PACK(td->td_bitspersample, td->td_sampleformat)) {
case PACK(32, SAMPLEFORMAT_IEEEFP):
guess = SGILOGDATAFMT_FLOAT;
break;
case PACK(32, SAMPLEFORMAT_VOID):
case PACK(32, SAMPLEFORMAT_UINT):
case PACK(32, SAMPLEFORMAT_INT):
guess = SGILOGDATAFMT_RAW;
break;
case PACK(16, SAMPLEFORMAT_VOID):
case PACK(16, SAMPLEFORMAT_INT):
case PACK(16, SAMPLEFORMAT_UINT):
guess = SGILOGDATAFMT_16BIT;
break;
case PACK( 8, SAMPLEFORMAT_VOID):
case PACK( 8, SAMPLEFORMAT_UINT):
guess = SGILOGDATAFMT_8BIT;
break;
default:
guess = SGILOGDATAFMT_UNKNOWN;
break;
#undef PACK
}
/*
* Double-check samples per pixel.
*/
switch (td->td_samplesperpixel) {
case 1:
if (guess != SGILOGDATAFMT_RAW)
guess = SGILOGDATAFMT_UNKNOWN;
break;
case 3:
if (guess == SGILOGDATAFMT_RAW)
guess = SGILOGDATAFMT_UNKNOWN;
break;
default:
guess = SGILOGDATAFMT_UNKNOWN;
break;
}
return (guess);
}
static int
LogLuvInitState(TIFF* tif)
{
TIFFDirectory* td = &tif->tif_dir;
LogLuvState* sp = DecoderState(tif);
static const char module[] = "LogLuvInitState";
assert(sp != NULL);
assert(td->td_photometric == PHOTOMETRIC_LOGLUV);
/* for some reason, we can't do this in TIFFInitLogLuv */
if (td->td_planarconfig != PLANARCONFIG_CONTIG) {
TIFFError(module,
"SGILog compression cannot handle non-contiguous data");
return (0);
}
if (sp->user_datafmt == SGILOGDATAFMT_UNKNOWN)
sp->user_datafmt = LogLuvGuessDataFmt(td);
switch (sp->user_datafmt) {
case SGILOGDATAFMT_FLOAT:
sp->pixel_size = 3*sizeof (float);
break;
case SGILOGDATAFMT_16BIT:
sp->pixel_size = 3*sizeof (int16);
break;
case SGILOGDATAFMT_RAW:
sp->pixel_size = sizeof (uint32);
break;
case SGILOGDATAFMT_8BIT:
sp->pixel_size = 3*sizeof (uint8);
break;
default:
TIFFError(tif->tif_name,
"No support for converting user data format to LogLuv");
return (0);
}
sp->tbuflen = multiply(td->td_imagewidth, td->td_rowsperstrip);
if (multiply(sp->tbuflen, sizeof (uint32)) == 0 ||
(sp->tbuf = (tidata_t*) _TIFFmalloc(sp->tbuflen * sizeof (uint32))) == NULL) {
TIFFError(module, "%s: No space for SGILog translation buffer",
tif->tif_name);
return (0);
}
return (1);
}
static int
LogLuvSetupDecode(TIFF* tif)
{
LogLuvState* sp = DecoderState(tif);
TIFFDirectory* td = &tif->tif_dir;
tif->tif_postdecode = _TIFFNoPostDecode;
switch (td->td_photometric) {
case PHOTOMETRIC_LOGLUV:
if (!LogLuvInitState(tif))
break;
if (td->td_compression == COMPRESSION_SGILOG24) {
tif->tif_decoderow = LogLuvDecode24;
switch (sp->user_datafmt) {
case SGILOGDATAFMT_FLOAT:
sp->tfunc = Luv24toXYZ;
break;
case SGILOGDATAFMT_16BIT:
sp->tfunc = Luv24toLuv48;
break;
case SGILOGDATAFMT_8BIT:
sp->tfunc = Luv24toRGB;
break;
}
} else {
tif->tif_decoderow = LogLuvDecode32;
switch (sp->user_datafmt) {
case SGILOGDATAFMT_FLOAT:
sp->tfunc = Luv32toXYZ;
break;
case SGILOGDATAFMT_16BIT:
sp->tfunc = Luv32toLuv48;
break;
case SGILOGDATAFMT_8BIT:
sp->tfunc = Luv32toRGB;
break;
}
}
return (1);
case PHOTOMETRIC_LOGL:
if (!LogL16InitState(tif))
break;
tif->tif_decoderow = LogL16Decode;
switch (sp->user_datafmt) {
case SGILOGDATAFMT_FLOAT:
sp->tfunc = L16toY;
break;
case SGILOGDATAFMT_8BIT:
sp->tfunc = L16toGry;
break;
}
return (1);
default:
TIFFError(tif->tif_name,
"Inappropriate photometric interpretation %d for SGILog compression; %s",
td->td_photometric, "must be either LogLUV or LogL");
break;
}
return (0);
}
static int
LogLuvSetupEncode(TIFF* tif)
{
LogLuvState* sp = EncoderState(tif);
TIFFDirectory* td = &tif->tif_dir;
switch (td->td_photometric) {
case PHOTOMETRIC_LOGLUV:
if (!LogLuvInitState(tif))
break;
if (td->td_compression == COMPRESSION_SGILOG24) {
tif->tif_encoderow = LogLuvEncode24;
switch (sp->user_datafmt) {
case SGILOGDATAFMT_FLOAT:
sp->tfunc = Luv24fromXYZ;
break;
case SGILOGDATAFMT_16BIT:
sp->tfunc = Luv24fromLuv48;
break;
case SGILOGDATAFMT_RAW:
break;
default:
goto notsupported;
}
} else {
tif->tif_encoderow = LogLuvEncode32;
switch (sp->user_datafmt) {
case SGILOGDATAFMT_FLOAT:
sp->tfunc = Luv32fromXYZ;
break;
case SGILOGDATAFMT_16BIT:
sp->tfunc = Luv32fromLuv48;
break;
case SGILOGDATAFMT_RAW:
break;
default:
goto notsupported;
}
}
break;
case PHOTOMETRIC_LOGL:
if (!LogL16InitState(tif))
break;
tif->tif_encoderow = LogL16Encode;
switch (sp->user_datafmt) {
case SGILOGDATAFMT_FLOAT:
sp->tfunc = L16fromY;
break;
case SGILOGDATAFMT_16BIT:
break;
default:
goto notsupported;
}
break;
default:
TIFFError(tif->tif_name,
"Inappropriate photometric interpretation %d for SGILog compression; %s",
td->td_photometric, "must be either LogLUV or LogL");
break;
}
return (1);
notsupported:
TIFFError(tif->tif_name,
"SGILog compression supported only for %s, or raw data",
td->td_photometric == PHOTOMETRIC_LOGL ? "Y, L" : "XYZ, Luv");
return (0);
}
static void
LogLuvClose(TIFF* tif)
{
TIFFDirectory *td = &tif->tif_dir;
/*
* For consistency, we always want to write out the same
* bitspersample and sampleformat for our TIFF file,
* regardless of the data format being used by the application.
* Since this routine is called after tags have been set but
* before they have been recorded in the file, we reset them here.
*/
td->td_samplesperpixel =
(td->td_photometric == PHOTOMETRIC_LOGL) ? 1 : 3;
td->td_bitspersample = 16;
td->td_sampleformat = SAMPLEFORMAT_INT;
}
static void
LogLuvCleanup(TIFF* tif)
{
LogLuvState* sp = (LogLuvState *)tif->tif_data;
if (sp) {
if (sp->tbuf)
_TIFFfree(sp->tbuf);
_TIFFfree(sp);
tif->tif_data = NULL;
}
}
static int
LogLuvVSetField(TIFF* tif, ttag_t tag, va_list ap)
{
LogLuvState* sp = DecoderState(tif);
int bps, fmt;
switch (tag) {
case TIFFTAG_SGILOGDATAFMT:
sp->user_datafmt = va_arg(ap, int);
/*
* Tweak the TIFF header so that the rest of libtiff knows what
* size of data will be passed between app and library, and
* assume that the app knows what it is doing and is not
* confused by these header manipulations...
*/
switch (sp->user_datafmt) {
case SGILOGDATAFMT_FLOAT:
bps = 32, fmt = SAMPLEFORMAT_IEEEFP;
break;
case SGILOGDATAFMT_16BIT:
bps = 16, fmt = SAMPLEFORMAT_INT;
break;
case SGILOGDATAFMT_RAW:
bps = 32, fmt = SAMPLEFORMAT_UINT;
TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, 1);
break;
case SGILOGDATAFMT_8BIT:
bps = 8, fmt = SAMPLEFORMAT_UINT;
break;
default:
TIFFError(tif->tif_name,
"Unknown data format %d for LogLuv compression",
sp->user_datafmt);
return (0);
}
TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, bps);
TIFFSetField(tif, TIFFTAG_SAMPLEFORMAT, fmt);
/*
* Must recalculate sizes should bits/sample change.
*/
tif->tif_tilesize = isTiled(tif) ? TIFFTileSize(tif) : (tsize_t) -1;
tif->tif_scanlinesize = TIFFScanlineSize(tif);
return (1);
case TIFFTAG_SGILOGENCODE:
sp->encode_meth = va_arg(ap, int);
if (sp->encode_meth != SGILOGENCODE_NODITHER &&
sp->encode_meth != SGILOGENCODE_RANDITHER) {
TIFFError(tif->tif_name,
"Unknown encoding %d for LogLuv compression",
sp->encode_meth);
return (0);
}
return (1);
default:
return (*sp->vsetparent)(tif, tag, ap);
}
}
static int
LogLuvVGetField(TIFF* tif, ttag_t tag, va_list ap)
{
LogLuvState *sp = (LogLuvState *)tif->tif_data;
switch (tag) {
case TIFFTAG_SGILOGDATAFMT:
*va_arg(ap, int*) = sp->user_datafmt;
return (1);
default:
return (*sp->vgetparent)(tif, tag, ap);
}
}
static const TIFFFieldInfo LogLuvFieldInfo[] = {
{ TIFFTAG_SGILOGDATAFMT, 0, 0, TIFF_SHORT, FIELD_PSEUDO,
TRUE, FALSE, "SGILogDataFmt"},
{ TIFFTAG_SGILOGENCODE, 0, 0, TIFF_SHORT, FIELD_PSEUDO,
TRUE, FALSE, "SGILogEncode"}
};
int
TIFFInitSGILog(TIFF* tif, int scheme)
{
static const char module[] = "TIFFInitSGILog";
LogLuvState* sp;
assert(scheme == COMPRESSION_SGILOG24 || scheme == COMPRESSION_SGILOG);
/*
* Allocate state block so tag methods have storage to record values.
*/
tif->tif_data = (tidata_t) _TIFFmalloc(sizeof (LogLuvState));
if (tif->tif_data == NULL)
goto bad;
sp = (LogLuvState*) tif->tif_data;
_TIFFmemset((tdata_t)sp, 0, sizeof (*sp));
sp->user_datafmt = SGILOGDATAFMT_UNKNOWN;
sp->encode_meth = (scheme == COMPRESSION_SGILOG24) ?
SGILOGENCODE_RANDITHER : SGILOGENCODE_NODITHER;
sp->tfunc = _logLuvNop;
/*
* Install codec methods.
* NB: tif_decoderow & tif_encoderow are filled
* in at setup time.
*/
tif->tif_setupdecode = LogLuvSetupDecode;
tif->tif_decodestrip = LogLuvDecodeStrip;
tif->tif_decodetile = LogLuvDecodeTile;
tif->tif_setupencode = LogLuvSetupEncode;
tif->tif_encodestrip = LogLuvEncodeStrip;
tif->tif_encodetile = LogLuvEncodeTile;
tif->tif_close = LogLuvClose;
tif->tif_cleanup = LogLuvCleanup;
/* override SetField so we can handle our private pseudo-tag */
_TIFFMergeFieldInfo(tif, LogLuvFieldInfo, N(LogLuvFieldInfo));
sp->vgetparent = tif->tif_tagmethods.vgetfield;
tif->tif_tagmethods.vgetfield = LogLuvVGetField; /* hook for codec tags */
sp->vsetparent = tif->tif_tagmethods.vsetfield;
tif->tif_tagmethods.vsetfield = LogLuvVSetField; /* hook for codec tags */
return (1);
bad:
TIFFError(module, "%s: No space for LogLuv state block", tif->tif_name);
return (0);
}
#endif /* LOGLUV_SUPPORT */
/* vim: set ts=8 sts=8 sw=8 noet: */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -