mirror of https://github.com/opencv/opencv.git
Open Source Computer Vision Library
https://opencv.org/
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
464 lines
12 KiB
464 lines
12 KiB
/* $Id: tif_predict.c,v 1.1 2005-06-17 13:54:52 vp153 Exp $ */ |
|
|
|
/* |
|
* Copyright (c) 1988-1997 Sam Leffler |
|
* Copyright (c) 1991-1997 Silicon Graphics, Inc. |
|
* |
|
* Permission to use, copy, modify, distribute, and sell this software and |
|
* its documentation for any purpose is hereby granted without fee, provided |
|
* that (i) the above copyright notices and this permission notice appear in |
|
* all copies of the software and related documentation, and (ii) the names of |
|
* Sam Leffler and Silicon Graphics may not be used in any advertising or |
|
* publicity relating to the software without the specific, prior written |
|
* permission of Sam Leffler and Silicon Graphics. |
|
* |
|
* THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, |
|
* EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY |
|
* WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. |
|
* |
|
* IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR |
|
* ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, |
|
* OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, |
|
* WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF |
|
* LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE |
|
* OF THIS SOFTWARE. |
|
*/ |
|
|
|
/* |
|
* TIFF Library. |
|
* |
|
* Predictor Tag Support (used by multiple codecs). |
|
*/ |
|
#include "tiffiop.h" |
|
#include "tif_predict.h" |
|
|
|
#define PredictorState(tif) ((TIFFPredictorState*) (tif)->tif_data) |
|
|
|
static void horAcc8(TIFF*, tidata_t, tsize_t); |
|
static void horAcc16(TIFF*, tidata_t, tsize_t); |
|
static void swabHorAcc16(TIFF*, tidata_t, tsize_t); |
|
static void horDiff8(TIFF*, tidata_t, tsize_t); |
|
static void horDiff16(TIFF*, tidata_t, tsize_t); |
|
static int PredictorDecodeRow(TIFF*, tidata_t, tsize_t, tsample_t); |
|
static int PredictorDecodeTile(TIFF*, tidata_t, tsize_t, tsample_t); |
|
static int PredictorEncodeRow(TIFF*, tidata_t, tsize_t, tsample_t); |
|
static int PredictorEncodeTile(TIFF*, tidata_t, tsize_t, tsample_t); |
|
|
|
static int |
|
PredictorSetup(TIFF* tif) |
|
{ |
|
TIFFPredictorState* sp = PredictorState(tif); |
|
TIFFDirectory* td = &tif->tif_dir; |
|
|
|
if (sp->predictor == 1) /* no differencing */ |
|
return (1); |
|
if (sp->predictor != 2) { |
|
TIFFError(tif->tif_name, "\"Predictor\" value %d not supported", |
|
sp->predictor); |
|
return (0); |
|
} |
|
if (td->td_bitspersample != 8 && td->td_bitspersample != 16) { |
|
TIFFError(tif->tif_name, |
|
"Horizontal differencing \"Predictor\" not supported with %d-bit samples", |
|
td->td_bitspersample); |
|
return (0); |
|
} |
|
sp->stride = (td->td_planarconfig == PLANARCONFIG_CONTIG ? |
|
td->td_samplesperpixel : 1); |
|
/* |
|
* Calculate the scanline/tile-width size in bytes. |
|
*/ |
|
if (isTiled(tif)) |
|
sp->rowsize = TIFFTileRowSize(tif); |
|
else |
|
sp->rowsize = TIFFScanlineSize(tif); |
|
return (1); |
|
} |
|
|
|
static int |
|
PredictorSetupDecode(TIFF* tif) |
|
{ |
|
TIFFPredictorState* sp = PredictorState(tif); |
|
TIFFDirectory* td = &tif->tif_dir; |
|
|
|
if (!(*sp->setupdecode)(tif) || !PredictorSetup(tif)) |
|
return (0); |
|
if (sp->predictor == 2) { |
|
switch (td->td_bitspersample) { |
|
case 8: sp->pfunc = horAcc8; break; |
|
case 16: sp->pfunc = horAcc16; break; |
|
} |
|
/* |
|
* Override default decoding method with |
|
* one that does the predictor stuff. |
|
*/ |
|
sp->coderow = tif->tif_decoderow; |
|
tif->tif_decoderow = PredictorDecodeRow; |
|
sp->codestrip = tif->tif_decodestrip; |
|
tif->tif_decodestrip = PredictorDecodeTile; |
|
sp->codetile = tif->tif_decodetile; |
|
tif->tif_decodetile = PredictorDecodeTile; |
|
/* |
|
* If the data is horizontally differenced |
|
* 16-bit data that requires byte-swapping, |
|
* then it must be byte swapped before the |
|
* accumulation step. We do this with a |
|
* special-purpose routine and override the |
|
* normal post decoding logic that the library |
|
* setup when the directory was read. |
|
*/ |
|
if (tif->tif_flags&TIFF_SWAB) { |
|
if (sp->pfunc == horAcc16) { |
|
sp->pfunc = swabHorAcc16; |
|
tif->tif_postdecode = _TIFFNoPostDecode; |
|
} /* else handle 32-bit case... */ |
|
} |
|
} |
|
return (1); |
|
} |
|
|
|
static int |
|
PredictorSetupEncode(TIFF* tif) |
|
{ |
|
TIFFPredictorState* sp = PredictorState(tif); |
|
TIFFDirectory* td = &tif->tif_dir; |
|
|
|
if (!(*sp->setupencode)(tif) || !PredictorSetup(tif)) |
|
return (0); |
|
if (sp->predictor == 2) { |
|
switch (td->td_bitspersample) { |
|
case 8: sp->pfunc = horDiff8; break; |
|
case 16: sp->pfunc = horDiff16; break; |
|
} |
|
/* |
|
* Override default encoding method with |
|
* one that does the predictor stuff. |
|
*/ |
|
sp->coderow = tif->tif_encoderow; |
|
tif->tif_encoderow = PredictorEncodeRow; |
|
sp->codestrip = tif->tif_encodestrip; |
|
tif->tif_encodestrip = PredictorEncodeTile; |
|
sp->codetile = tif->tif_encodetile; |
|
tif->tif_encodetile = PredictorEncodeTile; |
|
} |
|
return (1); |
|
} |
|
|
|
#define REPEAT4(n, op) \ |
|
switch (n) { \ |
|
default: { int i; for (i = n-4; i > 0; i--) { op; } } \ |
|
case 4: op; \ |
|
case 3: op; \ |
|
case 2: op; \ |
|
case 1: op; \ |
|
case 0: ; \ |
|
} |
|
|
|
static void |
|
horAcc8(TIFF* tif, tidata_t cp0, tsize_t cc) |
|
{ |
|
TIFFPredictorState* sp = PredictorState(tif); |
|
tsize_t stride = sp->stride; |
|
|
|
char* cp = (char*) cp0; |
|
if (cc > stride) { |
|
cc -= stride; |
|
/* |
|
* Pipeline the most common cases. |
|
*/ |
|
if (stride == 3) { |
|
unsigned int cr = cp[0]; |
|
unsigned int cg = cp[1]; |
|
unsigned int cb = cp[2]; |
|
do { |
|
cc -= 3, cp += 3; |
|
cp[0] = (char) (cr += cp[0]); |
|
cp[1] = (char) (cg += cp[1]); |
|
cp[2] = (char) (cb += cp[2]); |
|
} while ((int32) cc > 0); |
|
} else if (stride == 4) { |
|
unsigned int cr = cp[0]; |
|
unsigned int cg = cp[1]; |
|
unsigned int cb = cp[2]; |
|
unsigned int ca = cp[3]; |
|
do { |
|
cc -= 4, cp += 4; |
|
cp[0] = (char) (cr += cp[0]); |
|
cp[1] = (char) (cg += cp[1]); |
|
cp[2] = (char) (cb += cp[2]); |
|
cp[3] = (char) (ca += cp[3]); |
|
} while ((int32) cc > 0); |
|
} else { |
|
do { |
|
REPEAT4(stride, cp[stride] = (char) (cp[stride] + *cp); cp++) |
|
cc -= stride; |
|
} while ((int32) cc > 0); |
|
} |
|
} |
|
} |
|
|
|
static void |
|
swabHorAcc16(TIFF* tif, tidata_t cp0, tsize_t cc) |
|
{ |
|
TIFFPredictorState* sp = PredictorState(tif); |
|
tsize_t stride = sp->stride; |
|
uint16* wp = (uint16*) cp0; |
|
tsize_t wc = cc / 2; |
|
|
|
if (wc > stride) { |
|
TIFFSwabArrayOfShort(wp, wc); |
|
wc -= stride; |
|
do { |
|
REPEAT4(stride, wp[stride] += wp[0]; wp++) |
|
wc -= stride; |
|
} while ((int32) wc > 0); |
|
} |
|
} |
|
|
|
static void |
|
horAcc16(TIFF* tif, tidata_t cp0, tsize_t cc) |
|
{ |
|
tsize_t stride = PredictorState(tif)->stride; |
|
uint16* wp = (uint16*) cp0; |
|
tsize_t wc = cc / 2; |
|
|
|
if (wc > stride) { |
|
wc -= stride; |
|
do { |
|
REPEAT4(stride, wp[stride] += wp[0]; wp++) |
|
wc -= stride; |
|
} while ((int32) wc > 0); |
|
} |
|
} |
|
|
|
/* |
|
* Decode a scanline and apply the predictor routine. |
|
*/ |
|
static int |
|
PredictorDecodeRow(TIFF* tif, tidata_t op0, tsize_t occ0, tsample_t s) |
|
{ |
|
TIFFPredictorState *sp = PredictorState(tif); |
|
|
|
assert(sp != NULL); |
|
assert(sp->coderow != NULL); |
|
assert(sp->pfunc != NULL); |
|
if ((*sp->coderow)(tif, op0, occ0, s)) { |
|
(*sp->pfunc)(tif, op0, occ0); |
|
return (1); |
|
} else |
|
return (0); |
|
} |
|
|
|
/* |
|
* Decode a tile/strip and apply the predictor routine. |
|
* Note that horizontal differencing must be done on a |
|
* row-by-row basis. The width of a "row" has already |
|
* been calculated at pre-decode time according to the |
|
* strip/tile dimensions. |
|
*/ |
|
static int |
|
PredictorDecodeTile(TIFF* tif, tidata_t op0, tsize_t occ0, tsample_t s) |
|
{ |
|
TIFFPredictorState *sp = PredictorState(tif); |
|
|
|
assert(sp != NULL); |
|
assert(sp->codetile != NULL); |
|
if ((*sp->codetile)(tif, op0, occ0, s)) { |
|
tsize_t rowsize = sp->rowsize; |
|
assert(rowsize > 0); |
|
assert(sp->pfunc != NULL); |
|
while ((long)occ0 > 0) { |
|
(*sp->pfunc)(tif, op0, (tsize_t) rowsize); |
|
occ0 -= rowsize; |
|
op0 += rowsize; |
|
} |
|
return (1); |
|
} else |
|
return (0); |
|
} |
|
|
|
static void |
|
horDiff8(TIFF* tif, tidata_t cp0, tsize_t cc) |
|
{ |
|
TIFFPredictorState* sp = PredictorState(tif); |
|
tsize_t stride = sp->stride; |
|
char* cp = (char*) cp0; |
|
|
|
if (cc > stride) { |
|
cc -= stride; |
|
/* |
|
* Pipeline the most common cases. |
|
*/ |
|
if (stride == 3) { |
|
int r1, g1, b1; |
|
int r2 = cp[0]; |
|
int g2 = cp[1]; |
|
int b2 = cp[2]; |
|
do { |
|
r1 = cp[3]; cp[3] = r1-r2; r2 = r1; |
|
g1 = cp[4]; cp[4] = g1-g2; g2 = g1; |
|
b1 = cp[5]; cp[5] = b1-b2; b2 = b1; |
|
cp += 3; |
|
} while ((int32)(cc -= 3) > 0); |
|
} else if (stride == 4) { |
|
int r1, g1, b1, a1; |
|
int r2 = cp[0]; |
|
int g2 = cp[1]; |
|
int b2 = cp[2]; |
|
int a2 = cp[3]; |
|
do { |
|
r1 = cp[4]; cp[4] = r1-r2; r2 = r1; |
|
g1 = cp[5]; cp[5] = g1-g2; g2 = g1; |
|
b1 = cp[6]; cp[6] = b1-b2; b2 = b1; |
|
a1 = cp[7]; cp[7] = a1-a2; a2 = a1; |
|
cp += 4; |
|
} while ((int32)(cc -= 4) > 0); |
|
} else { |
|
cp += cc - 1; |
|
do { |
|
REPEAT4(stride, cp[stride] -= cp[0]; cp--) |
|
} while ((int32)(cc -= stride) > 0); |
|
} |
|
} |
|
} |
|
|
|
static void |
|
horDiff16(TIFF* tif, tidata_t cp0, tsize_t cc) |
|
{ |
|
TIFFPredictorState* sp = PredictorState(tif); |
|
tsize_t stride = sp->stride; |
|
int16 *wp = (int16*) cp0; |
|
tsize_t wc = cc/2; |
|
|
|
if (wc > stride) { |
|
wc -= stride; |
|
wp += wc - 1; |
|
do { |
|
REPEAT4(stride, wp[stride] -= wp[0]; wp--) |
|
wc -= stride; |
|
} while ((int32) wc > 0); |
|
} |
|
} |
|
|
|
static int |
|
PredictorEncodeRow(TIFF* tif, tidata_t bp, tsize_t cc, tsample_t s) |
|
{ |
|
TIFFPredictorState *sp = PredictorState(tif); |
|
|
|
assert(sp != NULL); |
|
assert(sp->pfunc != NULL); |
|
assert(sp->coderow != NULL); |
|
/* XXX horizontal differencing alters user's data XXX */ |
|
(*sp->pfunc)(tif, bp, cc); |
|
return ((*sp->coderow)(tif, bp, cc, s)); |
|
} |
|
|
|
static int |
|
PredictorEncodeTile(TIFF* tif, tidata_t bp0, tsize_t cc0, tsample_t s) |
|
{ |
|
TIFFPredictorState *sp = PredictorState(tif); |
|
tsize_t cc = cc0, rowsize; |
|
unsigned char* bp = bp0; |
|
|
|
assert(sp != NULL); |
|
assert(sp->pfunc != NULL); |
|
assert(sp->codetile != NULL); |
|
rowsize = sp->rowsize; |
|
assert(rowsize > 0); |
|
while ((long)cc > 0) { |
|
(*sp->pfunc)(tif, bp, (tsize_t) rowsize); |
|
cc -= rowsize; |
|
bp += rowsize; |
|
} |
|
return ((*sp->codetile)(tif, bp0, cc0, s)); |
|
} |
|
|
|
#define FIELD_PREDICTOR (FIELD_CODEC+0) /* XXX */ |
|
|
|
static const TIFFFieldInfo predictFieldInfo[] = { |
|
{ TIFFTAG_PREDICTOR, 1, 1, TIFF_SHORT, FIELD_PREDICTOR, |
|
FALSE, FALSE, "Predictor" }, |
|
}; |
|
#define N(a) (sizeof (a) / sizeof (a[0])) |
|
|
|
static int |
|
PredictorVSetField(TIFF* tif, ttag_t tag, va_list ap) |
|
{ |
|
TIFFPredictorState *sp = PredictorState(tif); |
|
|
|
switch (tag) { |
|
case TIFFTAG_PREDICTOR: |
|
sp->predictor = (uint16) va_arg(ap, int); |
|
TIFFSetFieldBit(tif, FIELD_PREDICTOR); |
|
break; |
|
default: |
|
return (*sp->vsetparent)(tif, tag, ap); |
|
} |
|
tif->tif_flags |= TIFF_DIRTYDIRECT; |
|
return (1); |
|
} |
|
|
|
static int |
|
PredictorVGetField(TIFF* tif, ttag_t tag, va_list ap) |
|
{ |
|
TIFFPredictorState *sp = PredictorState(tif); |
|
|
|
switch (tag) { |
|
case TIFFTAG_PREDICTOR: |
|
*va_arg(ap, uint16*) = sp->predictor; |
|
break; |
|
default: |
|
return (*sp->vgetparent)(tif, tag, ap); |
|
} |
|
return (1); |
|
} |
|
|
|
static void |
|
PredictorPrintDir(TIFF* tif, FILE* fd, long flags) |
|
{ |
|
TIFFPredictorState* sp = PredictorState(tif); |
|
|
|
(void) flags; |
|
if (TIFFFieldSet(tif,FIELD_PREDICTOR)) { |
|
fprintf(fd, " Predictor: "); |
|
switch (sp->predictor) { |
|
case 1: fprintf(fd, "none "); break; |
|
case 2: fprintf(fd, "horizontal differencing "); break; |
|
} |
|
fprintf(fd, "%u (0x%x)\n", sp->predictor, sp->predictor); |
|
} |
|
if (sp->printdir) |
|
(*sp->printdir)(tif, fd, flags); |
|
} |
|
|
|
int |
|
TIFFPredictorInit(TIFF* tif) |
|
{ |
|
TIFFPredictorState* sp = PredictorState(tif); |
|
|
|
/* |
|
* Merge codec-specific tag information and |
|
* override parent get/set field methods. |
|
*/ |
|
_TIFFMergeFieldInfo(tif, predictFieldInfo, N(predictFieldInfo)); |
|
sp->vgetparent = tif->tif_tagmethods.vgetfield; |
|
tif->tif_tagmethods.vgetfield = |
|
PredictorVGetField;/* hook for predictor tag */ |
|
sp->vsetparent = tif->tif_tagmethods.vsetfield; |
|
tif->tif_tagmethods.vsetfield = |
|
PredictorVSetField;/* hook for predictor tag */ |
|
sp->printdir = tif->tif_tagmethods.printdir; |
|
tif->tif_tagmethods.printdir = |
|
PredictorPrintDir; /* hook for predictor tag */ |
|
|
|
sp->setupdecode = tif->tif_setupdecode; |
|
tif->tif_setupdecode = PredictorSetupDecode; |
|
sp->setupencode = tif->tif_setupencode; |
|
tif->tif_setupencode = PredictorSetupEncode; |
|
|
|
sp->predictor = 1; /* default value */ |
|
sp->pfunc = NULL; /* no predictor routine */ |
|
return (1); |
|
} |
|
|
|
/* vim: set ts=8 sts=8 sw=8 noet: */
|
|
|