// 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 bool PredictorDecodeTile(TIFF tif, byte[] op0, int occ0, ushort s) { TIFFPredictorState sp = (TIFFPredictorState)tif.tif_data; if (sp.decodetile(tif, op0, occ0, s)) { int rowsize = sp.rowsize; #if DEBUG if (rowsize <= 0) { throw new Exception("rowsize<=0"); } #endif int op0_offset = 0; while (occ0 > 0) { sp.decodepfunc(tif, op0, op0_offset, rowsize); occ0 -= rowsize; op0_offset += rowsize; } return(true); } return(false); }
static bool TIFFPredictorInit(TIFF tif) { TIFFPredictorState sp = (TIFFPredictorState)tif.tif_data; // Merge codec-specific tag information. if (!_TIFFMergeFieldInfo(tif, predictFieldInfo)) { TIFFErrorExt(tif.tif_clientdata, "TIFFPredictorInit", "Merging Predictor codec-specific tags failed"); return(false); } // Override parent get/set field methods. 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 = PREDICTOR.NONE; // default value sp.encodepfunc = null; // no predictor routine sp.decodepfunc = null; // no predictor routine return(true); }
static bool PredictorEncodeRow(TIFF tif, byte[] bp, int cc, ushort s) { TIFFPredictorState sp = (TIFFPredictorState)tif.tif_data; // XXX horizontal differencing alters user's data XXX sp.encodepfunc(tif, bp, 0, cc); return(sp.encoderow(tif, bp, cc, s)); }
static bool TIFFPredictorCleanup(TIFF tif) { TIFFPredictorState sp = (TIFFPredictorState)tif.tif_data; tif.tif_tagmethods.vgetfield = sp.vgetparent; tif.tif_tagmethods.vsetfield = sp.vsetparent; tif.tif_tagmethods.printdir = sp.printdir; tif.tif_setupdecode = sp.setupdecode; tif.tif_setupencode = sp.setupencode; return(true); }
// Decode a scanline and apply the predictor routine. static bool PredictorDecodeRow(TIFF tif, byte[] op0, int occ0, ushort s) { TIFFPredictorState sp = (TIFFPredictorState)tif.tif_data; if (sp.decoderow(tif, op0, occ0, s)) { sp.decodepfunc(tif, op0, 0, occ0); return(true); } return(false); }
static bool PredictorSetupEncode(TIFF tif) { TIFFPredictorState sp = (TIFFPredictorState)tif.tif_data; TIFFDirectory td = tif.tif_dir; if (!sp.setupencode(tif) || !PredictorSetup(tif)) { return(false); } if (sp.predictor == PREDICTOR.HORIZONTAL) { switch (td.td_bitspersample) { case 8: sp.encodepfunc = horDiff8; break; case 16: sp.encodepfunc = horDiff16; break; case 32: sp.encodepfunc = horDiff32; break; } // Override default encoding method with one that does the // predictor stuff. if (tif.tif_encoderow != PredictorEncodeRow) { sp.encoderow = tif.tif_encoderow; tif.tif_encoderow = PredictorEncodeRow; sp.encodestrip = tif.tif_encodestrip; tif.tif_encodestrip = PredictorEncodeTile; sp.encodetile = tif.tif_encodetile; tif.tif_encodetile = PredictorEncodeTile; } } else if (sp.predictor == PREDICTOR.FLOATINGPOINT) { sp.encodepfunc = fpDiff; // Override default encoding method with one that does the // predictor stuff. if (tif.tif_encoderow != PredictorEncodeRow) { sp.encoderow = tif.tif_encoderow; tif.tif_encoderow = PredictorEncodeRow; sp.encodestrip = tif.tif_encodestrip; tif.tif_encodestrip = PredictorEncodeTile; sp.encodetile = tif.tif_encodetile; tif.tif_encodetile = PredictorEncodeTile; } } return(true); }
static bool PredictorVGetField(TIFF tif, TIFFTAG tag, object[] ap) { TIFFPredictorState sp = (TIFFPredictorState)tif.tif_data; switch (tag) { case TIFFTAG.PREDICTOR: ap[0] = (ushort)sp.predictor; break; default: return(sp.vgetparent(tif, tag, ap)); } return(true); }
static bool PredictorVSetField(TIFF tif, TIFFTAG tag, TIFFDataType dt, params object[] ap) { TIFFPredictorState sp = (TIFFPredictorState)tif.tif_data; switch (tag) { case TIFFTAG.PREDICTOR: sp.predictor = (PREDICTOR)__GetAsUshort(ap, 0); TIFFSetFieldBit(tif, FIELD.CODEC); break; default: return(sp.vsetparent(tif, tag, dt, ap)); } tif.tif_flags |= TIF_FLAGS.TIFF_DIRTYDIRECT; return(true); }
static bool PredictorSetup(TIFF tif) { string module = "PredictorSetup"; TIFFPredictorState sp = (TIFFPredictorState)tif.tif_data; TIFFDirectory td = tif.tif_dir; switch (sp.predictor) { case PREDICTOR.NONE: return(true); // no differencing case PREDICTOR.HORIZONTAL: if (td.td_bitspersample != 8 && td.td_bitspersample != 16 && td.td_bitspersample != 32) { TIFFErrorExt(tif.tif_clientdata, module, "Horizontal differencing \"Predictor\" not supported with {0}-bit samples", td.td_bitspersample); return(false); } break; case PREDICTOR.FLOATINGPOINT: if (td.td_sampleformat != SAMPLEFORMAT.IEEEFP) { TIFFErrorExt(tif.tif_clientdata, module, "Floating point \"Predictor\" not supported with {0} data format", td.td_sampleformat); return(false); } break; default: TIFFErrorExt(tif.tif_clientdata, module, "\"Predictor\" value {0} not supported", sp.predictor); return(false); } sp.stride = (td.td_planarconfig == PLANARCONFIG.CONTIG?(int)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(true); }
static bool PredictorEncodeTile(TIFF tif, byte[] bp0, int cc0, ushort s) { string module = "PredictorEncodeTile"; TIFFPredictorState sp = (TIFFPredictorState)tif.tif_data; int cc = cc0; byte[] bp = null; try { bp = new byte[cc0]; } catch { TIFFErrorExt(tif.tif_clientdata, module, "Out of memory allocating {0} byte temp buffer.", cc0); return(false); } bp0.CopyTo(bp, 0); int rowsize = sp.rowsize; #if DEBUG if (rowsize <= 0) { throw new Exception("rowsize<=0"); } if ((cc0 % rowsize) != 0) { throw new Exception("(cc0%rowsize)!=0"); } #endif int bp_offset = 0; while (cc > 0) { sp.encodepfunc(tif, bp, bp_offset, rowsize); cc -= rowsize; bp_offset += rowsize; } return(sp.encodetile(tif, bp, cc0, s)); }
unsafe static void horDiff32(TIFF tif, byte[] cp0, int cp0_offset, int cc) { TIFFPredictorState sp = (TIFFPredictorState)tif.tif_data; int stride = sp.stride; int wc = cc / 4; if (wc > stride) { fixed(byte *cp0_ = cp0) { ushort *wp = (ushort *)(cp0_ + cp0_offset); wc -= stride; wp += wc - 1; do { //was REPEAT4(stride, wp[stride]-=*(wp--)); switch (stride) { default: for (int i = stride - 4; i > 0; i--) { wp[stride] -= *(wp--); } goto case 4; case 4: wp[stride] -= *(wp--); goto case 3; case 3: wp[stride] -= *(wp--); goto case 2; case 2: wp[stride] -= *(wp--); goto case 1; case 1: wp[stride] -= *(wp--); break; case 0: break; } wc -= stride; }while(wc > 0); } } }
static void PredictorPrintDir(TIFF tif, TextWriter fd, TIFFPRINT flags) { TIFFPredictorState sp = (TIFFPredictorState)tif.tif_data; if (TIFFFieldSet(tif, FIELD.CODEC)) { fd.Write(" Predictor: "); switch (sp.predictor) { case PREDICTOR.NONE: fd.Write("none "); break; case PREDICTOR.HORIZONTAL: fd.Write("horizontal differencing "); break; case PREDICTOR.FLOATINGPOINT: fd.Write("floating point predictor "); break; } fd.WriteLine("{0} (0x{1:X2})\n", sp.predictor, sp.predictor); } if (sp.printdir != null) { sp.printdir(tif, fd, flags); } }
// Like TIFFGetField, but return any default // value if the tag is not present in the directory. // // NB: We use the value in the directory, rather than // explicit values so that defaults exist only in one // place in the library -- in TIFFDefaultDirectory. public static bool TIFFVGetFieldDefaulted(TIFF tif, TIFFTAG tag, object[] ap) { TIFFDirectory td = tif.tif_dir; if (TIFFVGetField(tif, tag, ap)) { return(true); } switch (tag) { case TIFFTAG.SUBFILETYPE: ap[0] = td.td_subfiletype; return(true); case TIFFTAG.BITSPERSAMPLE: ap[0] = td.td_bitspersample; return(true); case TIFFTAG.THRESHHOLDING: ap[0] = td.td_threshholding; return(true); case TIFFTAG.FILLORDER: ap[0] = td.td_fillorder; return(true); case TIFFTAG.ORIENTATION: ap[0] = td.td_orientation; return(true); case TIFFTAG.SAMPLESPERPIXEL: ap[0] = td.td_samplesperpixel; return(true); case TIFFTAG.ROWSPERSTRIP: ap[0] = td.td_rowsperstrip; return(true); case TIFFTAG.MINSAMPLEVALUE: ap[0] = td.td_minsamplevalue; return(true); case TIFFTAG.MAXSAMPLEVALUE: ap[0] = td.td_maxsamplevalue; return(true); case TIFFTAG.PLANARCONFIG: ap[0] = td.td_planarconfig; return(true); case TIFFTAG.RESOLUTIONUNIT: ap[0] = td.td_resolutionunit; return(true); case TIFFTAG.PREDICTOR: TIFFPredictorState sp = (TIFFPredictorState)tif.tif_data; ap[0] = sp.predictor; return(true); case TIFFTAG.DOTRANGE: ap[0] = 0; ap[1] = (1 << td.td_bitspersample) - 1; return(true); case TIFFTAG.INKSET: ap[0] = INKSET.CMYK; return(true); case TIFFTAG.NUMBEROFINKS: ap[0] = (ushort)4; return(true); case TIFFTAG.EXTRASAMPLES: ap[0] = td.td_extrasamples; ap[1] = td.td_sampleinfo; return(true); case TIFFTAG.MATTEING: ap[0] = (ushort)((td.td_extrasamples == 1 && td.td_sampleinfo[0] == (ushort)EXTRASAMPLE.ASSOCALPHA)?1:0); return(true); case TIFFTAG.TILEDEPTH: ap[0] = td.td_tiledepth; return(true); case TIFFTAG.DATATYPE: ap[0] = td.td_sampleformat - 1; return(true); case TIFFTAG.SAMPLEFORMAT: ap[0] = td.td_sampleformat; return(true); case TIFFTAG.IMAGEDEPTH: ap[0] = td.td_imagedepth; return(true); case TIFFTAG.YCBCRCOEFFICIENTS: // defaults are from CCIR Recommendation 601-1 double[] ycbcrcoeffs = new double[] { 0.299, 0.587, 0.114 }; ap[0] = ycbcrcoeffs; return(true); case TIFFTAG.YCBCRSUBSAMPLING: ap[0] = td.td_ycbcrsubsampling[0]; ap[1] = td.td_ycbcrsubsampling[1]; return(true); case TIFFTAG.YCBCRPOSITIONING: ap[0] = td.td_ycbcrpositioning; return(true); case TIFFTAG.WHITEPOINT: // TIFF 6.0 specification tells that it is no default // value for the WhitePoint, but AdobePhotoshop TIFF // Technical Note tells that it should be CIE D50. ap[0] = new double[] { D50_X0 / (D50_X0 + D50_Y0 + D50_Z0), D50_Y0 / (D50_X0 + D50_Y0 + D50_Z0) }; return(true); case TIFFTAG.TRANSFERFUNCTION: if (td.td_transferfunction[0] == null && !TIFFDefaultTransferFunction(td)) { TIFFErrorExt(tif.tif_clientdata, tif.tif_name, "No space for \"TransferFunction\" tag"); return(false); } ap[0] = td.td_transferfunction[0]; if (td.td_samplesperpixel - td.td_extrasamples > 1) { ap[1] = td.td_transferfunction[1]; ap[2] = td.td_transferfunction[2]; } return(true); case TIFFTAG.REFERENCEBLACKWHITE: { if (td.td_refblackwhite == null && !TIFFDefaultRefBlackWhite(td)) { return(false); } ap[0] = td.td_refblackwhite; return(true); } } return(false); }
unsafe static void horDiff8(TIFF tif, byte[] cp0, int cp0_offset, int cc) { TIFFPredictorState sp = (TIFFPredictorState)tif.tif_data; int stride = sp.stride; if (cc > stride) { fixed(byte *cp0_ = cp0) { byte *cp = cp0_ + cp0_offset; cc -= stride; // Pipeline the most common cases. if (stride == 3) { byte r1, g1, b1; byte r2 = cp[0]; byte g2 = cp[1]; byte b2 = cp[2]; do { r1 = cp[3]; cp[3] -= r2; r2 = r1; g1 = cp[4]; cp[4] -= g2; g2 = g1; b1 = cp[5]; cp[5] -= b2; b2 = b1; cp += 3; cc -= 3; }while(cc > 0); } else if (stride == 4) { byte r1, g1, b1, a1; byte r2 = cp[0]; byte g2 = cp[1]; byte b2 = cp[2]; byte a2 = cp[3]; do { r1 = cp[4]; cp[4] -= r2; r2 = r1; g1 = cp[5]; cp[5] -= g2; g2 = g1; b1 = cp[6]; cp[6] -= b2; b2 = b1; a1 = cp[7]; cp[7] -= a2; a2 = a1; cp += 4; cc -= 4; }while(cc > 0); } else { cp += cc - 1; do { //was REPEAT4(stride, cp[stride]-=*(cp--)); switch (stride) { default: for (int i = stride - 4; i > 0; i--) { cp[stride] -= *(cp--); } goto case 4; case 4: cp[stride] -= *(cp--); goto case 3; case 3: cp[stride] -= *(cp--); goto case 2; case 2: cp[stride] -= *(cp--); goto case 1; case 1: cp[stride] -= *(cp--); break; case 0: break; } cc -= stride; }while(cc > 0); } } } }
static bool PredictorSetupDecode(TIFF tif) { TIFFPredictorState sp = (TIFFPredictorState)tif.tif_data; TIFFDirectory td = tif.tif_dir; if (!sp.setupdecode(tif) || !PredictorSetup(tif)) { return(false); } if (sp.predictor == PREDICTOR.HORIZONTAL) { switch (td.td_bitspersample) { case 8: sp.decodepfunc = horAcc8; break; case 16: sp.decodepfunc = horAcc16; break; case 32: sp.decodepfunc = horAcc32; break; } // Override default decoding method with one that does the // predictor stuff. if (tif.tif_decoderow != PredictorDecodeRow) { sp.decoderow = tif.tif_decoderow; tif.tif_decoderow = PredictorDecodeRow; sp.decodestrip = tif.tif_decodestrip; tif.tif_decodestrip = PredictorDecodeTile; sp.decodetile = 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 & TIF_FLAGS.TIFF_SWAB) == TIF_FLAGS.TIFF_SWAB) { if (sp.decodepfunc == horAcc16) { sp.decodepfunc = swabHorAcc16; tif.tif_postdecode = TIFFNoPostDecode; } else if (sp.decodepfunc == horAcc32) { sp.decodepfunc = swabHorAcc32; tif.tif_postdecode = TIFFNoPostDecode; } } } else if (sp.predictor == PREDICTOR.FLOATINGPOINT) { sp.decodepfunc = fpAcc; // Override default decoding method with one that does the // predictor stuff. if (tif.tif_decoderow != PredictorDecodeRow) { sp.decoderow = tif.tif_decoderow; tif.tif_decoderow = PredictorDecodeRow; sp.decodestrip = tif.tif_decodestrip; tif.tif_decodestrip = PredictorDecodeTile; sp.decodetile = tif.tif_decodetile; tif.tif_decodetile = PredictorDecodeTile; } // The data should not be swapped outside of the floating // point predictor, the accumulation routine should return // byres in the native order. if ((tif.tif_flags & TIF_FLAGS.TIFF_SWAB) == TIF_FLAGS.TIFF_SWAB) { tif.tif_postdecode = TIFFNoPostDecode; } // Allocate buffer to keep the decoded bytes before // rearranging in the ight order } return(true); }