Esempio n. 1
0
        // **************************************************************************
        // *								TIFFCleanup()							*
        // **************************************************************************

        // Auxiliary function to free the TIFF structure. Given structure will be
        // completetly freed, so you should save opened file handle and pointer
        // to the close procedure in external variables before calling
        // _TIFFCleanup(), if you will need these ones to close the file.
        //
        // @param tif A TIFF pointer.
        public static void TIFFCleanup(TIFF tif)
        {
            if (tif.tif_mode != O.RDONLY)
            {
                TIFFFlush(tif);                                    // Flush buffered data and directory (if dirty).
            }
            tif.tif_cleanup(tif);
            TIFFFreeDirectory(tif);

            tif.tif_dirlist.Clear();

            // Clean up client info links
            tif.tif_clientinfo.Clear();

            tif.tif_rawdata = null;

            tif.tif_fieldinfo.Clear();
        }
Esempio n. 2
0
        // Read the next TIFF directory from a file
        // and convert it to the internal format.
        // We read directories sequentially.
        public static bool TIFFReadDirectory(TIFF tif)
        {
            string module="TIFFReadDirectory";

            ushort iv;
            uint v;
            TIFFFieldInfo fip;
            bool diroutoforderwarning=false;
            bool haveunknowntags=false;

            tif.tif_diroff=tif.tif_nextdiroff;
            // Check whether we have the last offset or bad offset (IFD looping).
            if(!TIFFCheckDirOffset(tif, tif.tif_nextdiroff)) return false;

            // Cleanup any previous compression state.
            tif.tif_cleanup(tif);
            tif.tif_curdir++;

            List<TIFFDirEntry> dir=null;
            ushort dircount=TIFFFetchDirectory(tif, tif.tif_nextdiroff, ref dir, ref tif.tif_nextdiroff);
            if(dircount==0)
            {
                TIFFErrorExt(tif.tif_clientdata, module, "{0}: Failed to read directory at offset{1}", tif.tif_name, tif.tif_nextdiroff);
                return false;
            }

            tif.tif_flags&=~TIF_FLAGS.TIFF_BEENWRITING; // reset before new dir

            // Setup default value and then make a pass over
            // the fields to check type and tag information,
            // and to extract info required to size data
            // structures. A second pass is made afterwards
            // to read in everthing not taken in the first pass.
            TIFFDirectory td=tif.tif_dir;

            // free any old stuff and reinit
            TIFFFreeDirectory(tif);
            TIFFDefaultDirectory(tif);

            // Electronic Arts writes gray-scale TIFF files
            // without a PlanarConfiguration directory entry.
            // Thus we setup a default value here, even though
            // the TIFF spec says there is no default value.
            TIFFSetField(tif, TIFFTAG.PLANARCONFIG, PLANARCONFIG.CONTIG);

            // Sigh, we must make a separate pass through the
            // directory for the following reason:
            //
            // We must process the Compression tag in the first pass
            // in order to merge in codec-private tag definitions (otherwise
            // we may get complaints about unknown tags). However, the
            // Compression tag may be dependent on the SamplesPerPixel
            // tag value because older TIFF specs permited Compression
            // to be written as a SamplesPerPixel-count tag entry.
            // Thus if we don't first figure out the correct SamplesPerPixel
            // tag value then we may end up ignoring the Compression tag
            // value because it has an incorrect count value (if the
            // true value of SamplesPerPixel is not 1).
            //
            // It sure would have been nice if Aldus had really thought
            // this stuff through carefully.
            foreach(TIFFDirEntry dp in dir)
            {
                if((tif.tif_flags&TIF_FLAGS.TIFF_SWAB)!=0)
                {
                    TIFFSwab(ref dp.tdir_tag);
                    TIFFSwab(ref dp.tdir_type);
                    TIFFSwab(ref dp.tdir_count);
                    TIFFSwab(ref dp.tdir_offset);
                }

                if((TIFFTAG)dp.tdir_tag==TIFFTAG.SAMPLESPERPIXEL)
                {
                    if(!TIFFFetchNormalTag(tif, dp)) return false;
                    dp.tdir_tag=IGNORE;
                }
            }

            // First real pass over the directory.
            int fix=0;
            foreach(TIFFDirEntry dp in dir)
            {
                if(dp.tdir_tag==IGNORE) continue;
                if(fix>=tif.tif_fieldinfo.Count) fix=0;

                // Silicon Beach (at least) writes unordered
                // directory tags (violating the spec). Handle
                // it here, but be obnoxious (maybe they'll fix it?).
                if(dp.tdir_tag<(ushort)tif.tif_fieldinfo[fix].field_tag)
                {
                    if(!diroutoforderwarning)
                    {
                        TIFFWarningExt(tif.tif_clientdata, module, "{0}: invalid TIFF directory; tags are not sorted in ascending order", tif.tif_name);
                        diroutoforderwarning=true;
                    }
                    fix=0; // O(n^2)
                }

                while(fix<tif.tif_fieldinfo.Count&&(ushort)tif.tif_fieldinfo[fix].field_tag<dp.tdir_tag) fix++;

                if(fix>=tif.tif_fieldinfo.Count||(ushort)tif.tif_fieldinfo[fix].field_tag!=dp.tdir_tag)
                {
                    // Unknown tag ... we'll deal with it below
                    haveunknowntags=true;
                    continue;
                }

                // Null out old tags that we ignore.
                if(tif.tif_fieldinfo[fix].field_bit==FIELD.IGNORE)
                {
                    dp.tdir_tag=IGNORE;
                    continue;
                }

                // Check data type.
                fip=tif.tif_fieldinfo[fix];
                bool docontinue=false;
                while(dp.tdir_type!=(ushort)fip.field_type&&fix<tif.tif_fieldinfo.Count)
                {
                    if(fip.field_type==TIFFDataType.TIFF_ANY) break; // wildcard

                    fip=tif.tif_fieldinfo[++fix];
                    if(fix>=tif.tif_fieldinfo.Count||(ushort)fip.field_tag!=dp.tdir_tag)
                    {
                        TIFFWarningExt(tif.tif_clientdata, module, "{0}: wrong data type {1} for \"{2}\"; tag ignored", tif.tif_name, dp.tdir_type, tif.tif_fieldinfo[fix-1].field_name);
                        dp.tdir_tag=IGNORE;
                        docontinue=true;
                        break;
                    }
                }
                if(docontinue) continue;

                // Check count if known in advance.
                if(fip.field_readcount!=TIFF_VARIABLE)
                {
                    uint expected=(fip.field_readcount==TIFF_SPP)?td.td_samplesperpixel:(uint)fip.field_readcount;
                    if(!CheckDirCount(tif, dp, expected))
                    {
                        dp.tdir_tag=IGNORE;
                        continue;
                    }
                }

                switch((TIFFTAG)dp.tdir_tag)
                {
                    case TIFFTAG.COMPRESSION:
                        // The 5.0 spec says the Compression tag has
                        // one value, while earlier specs say it has
                        // one value per sample. Because of this, we
                        // accept the tag if one value is supplied.
                        if(dp.tdir_count==1)
                        {
                            //was v = TIFFExtractData(tif, dp.tdir_type, dp.tdir_offset);
                            v=(tif.tif_header.tiff_magic==TIFF_BIGENDIAN?(dp.tdir_offset>>tif_typeshift[dp.tdir_type])&tif_typemask[dp.tdir_type]:dp.tdir_offset&tif_typemask[dp.tdir_type]);

                            if(!TIFFSetField(tif, (TIFFTAG)dp.tdir_tag, (ushort)v)) return false;
                            break;
                            // XXX: workaround for broken TIFFs
                        }

                        if((TIFFDataType)dp.tdir_type==TIFFDataType.TIFF_LONG)
                        {
                            if(!TIFFFetchPerSampleLongs(tif, dp, out v)||!TIFFSetField(tif, (TIFFTAG)dp.tdir_tag, (ushort)v))
                                return false;
                        }
                        else
                        {
                            if(!TIFFFetchPerSampleShorts(tif, dp, out iv)||!TIFFSetField(tif, (TIFFTAG)dp.tdir_tag, iv))
                                return false;
                        }
                        dp.tdir_tag=IGNORE;
                        break;
                    case TIFFTAG.STRIPOFFSETS:
                    case TIFFTAG.STRIPBYTECOUNTS:
                    case TIFFTAG.TILEOFFSETS:
                    case TIFFTAG.TILEBYTECOUNTS:
                        TIFFSetFieldBit(tif, fip.field_bit);
                        break;
                    case TIFFTAG.IMAGEWIDTH:
                    case TIFFTAG.IMAGELENGTH:
                    case TIFFTAG.IMAGEDEPTH:
                    case TIFFTAG.TILELENGTH:
                    case TIFFTAG.TILEWIDTH:
                    case TIFFTAG.TILEDEPTH:
                    case TIFFTAG.PLANARCONFIG:
                    case TIFFTAG.ROWSPERSTRIP:
                    case TIFFTAG.EXTRASAMPLES:
                        if(!TIFFFetchNormalTag(tif, dp)) return false;
                        dp.tdir_tag=IGNORE;
                        break;
                }
            }

            // If we saw any unknown tags, make an extra pass over the directory
            // to deal with them. This must be done separately because the tags
            // could have become known when we registered a codec after finding
            // the Compression tag. In a correctly-sorted directory there's
            // no problem because Compression will come before any codec-private
            // tags, but if the sorting is wrong that might not hold.
            if(haveunknowntags)
            {
                fix=0;
                foreach(TIFFDirEntry dp in dir)
                {
                    if(dp.tdir_tag==IGNORE) continue;
                    if(fix>=tif.tif_fieldinfo.Count||dp.tdir_tag<(ushort)tif.tif_fieldinfo[fix].field_tag) fix=0;	// O(n^2)
                    while(fix<tif.tif_fieldinfo.Count&&(ushort)tif.tif_fieldinfo[fix].field_tag<dp.tdir_tag) fix++;
                    if(fix>=tif.tif_fieldinfo.Count||(ushort)tif.tif_fieldinfo[fix].field_tag!=dp.tdir_tag)
                    {
                        TIFFWarningExt(tif.tif_clientdata, module, "{0}: unknown field with tag %d (0x{1:X}) encountered", tif.tif_name, dp.tdir_tag, dp.tdir_tag);

                        if(!_TIFFMergeFieldInfo(tif, TIFFCreateAnonFieldInfo(tif, (TIFFTAG)dp.tdir_tag, (TIFFDataType)dp.tdir_type)))
                        {
                            TIFFWarningExt(tif.tif_clientdata, module, "Registering anonymous field with tag {0} (0x{1:X}) failed", dp.tdir_tag, dp.tdir_tag);
                            dp.tdir_tag=IGNORE;
                            continue;
                        }
                        fix=0;
                        while(fix<tif.tif_fieldinfo.Count&&(ushort)tif.tif_fieldinfo[fix].field_tag<dp.tdir_tag) fix++;
                    }

                    // Check data type.
                    fip=tif.tif_fieldinfo[fix];
                    while(dp.tdir_type!=(ushort)fip.field_type&&fix<tif.tif_fieldinfo.Count)
                    {
                        if(fip.field_type==TIFFDataType.TIFF_ANY)	// wildcard
                            break;
                        fip=tif.tif_fieldinfo[++fix];
                        if(fix>=tif.tif_fieldinfo.Count||(ushort)fip.field_tag!=dp.tdir_tag)
                        {
                            TIFFWarningExt(tif.tif_clientdata, module, "{0}: wrong data type {1} for \"{2}\"; tag ignored", tif.tif_name, dp.tdir_type, tif.tif_fieldinfo[fix-1].field_name);
                            dp.tdir_tag=IGNORE;
                            break;
                        }
                    }
                }
            }

            // Allocate directory structure and setup defaults.
            if(!TIFFFieldSet(tif, FIELD.IMAGEDIMENSIONS))
            {
                MissingRequired(tif, "ImageLength");
                return false;
            }

            // Setup appropriate structures (by strip or by tile)
            if(!TIFFFieldSet(tif, FIELD.TILEDIMENSIONS))
            {
                td.td_nstrips=(uint)TIFFNumberOfStrips(tif);
                td.td_tilewidth=td.td_imagewidth;
                td.td_tilelength=td.td_rowsperstrip;
                td.td_tiledepth=td.td_imagedepth;
                tif.tif_flags&=~TIF_FLAGS.TIFF_ISTILED;
            }
            else
            {
                td.td_nstrips=(uint)TIFFNumberOfTiles(tif);
                tif.tif_flags|=TIF_FLAGS.TIFF_ISTILED;
            }

            if(td.td_nstrips==0)
            {
                TIFFErrorExt(tif.tif_clientdata, module, "{0}: cannot handle zero number of {1}", tif.tif_name, isTiled(tif)?"tiles":"strips");
                return false;
            }

            td.td_stripsperimage=td.td_nstrips;
            if(td.td_planarconfig==PLANARCONFIG.SEPARATE) td.td_stripsperimage/=td.td_samplesperpixel;
            if(!TIFFFieldSet(tif, FIELD.STRIPOFFSETS))
            {
                MissingRequired(tif, isTiled(tif)?"TileOffsets":"StripOffsets");
                return false;
            }

            // Second pass: extract other information.
            foreach(TIFFDirEntry dp in dir)
            {
                if(dp.tdir_tag==IGNORE) continue;

                switch((TIFFTAG)dp.tdir_tag)
                {
                    case TIFFTAG.MINSAMPLEVALUE:
                    case TIFFTAG.MAXSAMPLEVALUE:
                    case TIFFTAG.BITSPERSAMPLE:
                    case TIFFTAG.DATATYPE:
                    case TIFFTAG.SAMPLEFORMAT:
                        // The 5.0 spec says the Compression tag has
                        // one value, while earlier specs say it has
                        // one value per sample. Because of this, we
                        // accept the tag if one value is supplied.
                        //
                        // The MinSampleValue, MaxSampleValue, BitsPerSample
                        // DataType and SampleFormat tags are supposed to be
                        // written as one value/sample, but some vendors
                        // incorrectly write one value only -- so we accept
                        // that as well (yech). Other vendors write correct
                        // value for NumberOfSamples, but incorrect one for
                        // BitsPerSample and friends, and we will read this
                        // too.
                        if(dp.tdir_count==1)
                        {
                            //was v = TIFFExtractData(tif, dp.tdir_type, dp.tdir_offset);
                            v=(tif.tif_header.tiff_magic==TIFF_BIGENDIAN?(dp.tdir_offset>>tif_typeshift[dp.tdir_type])&tif_typemask[dp.tdir_type]:dp.tdir_offset&tif_typemask[dp.tdir_type]);

                            if(!TIFFSetField(tif, (TIFFTAG)dp.tdir_tag, (ushort)v)) return false;
                            // XXX: workaround for broken TIFFs
                        }
                        else if((TIFFTAG)dp.tdir_tag==TIFFTAG.BITSPERSAMPLE&&(TIFFDataType)dp.tdir_type==TIFFDataType.TIFF_LONG)
                        {
                            if(!TIFFFetchPerSampleLongs(tif, dp, out v)||!TIFFSetField(tif, (TIFFTAG)dp.tdir_tag, (ushort)v))
                                return false;
                        }
                        else
                        {
                            if(!TIFFFetchPerSampleShorts(tif, dp, out iv)||!TIFFSetField(tif, (TIFFTAG)dp.tdir_tag, iv))
                                return false;
                        }
                        break;
                    case TIFFTAG.SMINSAMPLEVALUE:
                    case TIFFTAG.SMAXSAMPLEVALUE:
                        {
                            double dv=0.0;
                            if(!TIFFFetchPerSampleAnys(tif, dp, out dv)||!TIFFSetField(tif, (TIFFTAG)dp.tdir_tag, dv))
                                return false;
                        }
                        break;
                    case TIFFTAG.STRIPOFFSETS:
                    case TIFFTAG.TILEOFFSETS:
                        if(!TIFFFetchStripThing(tif, dp, td.td_nstrips, ref td.td_stripoffset)) return false;
                        break;
                    case TIFFTAG.STRIPBYTECOUNTS:
                    case TIFFTAG.TILEBYTECOUNTS:
                        if(!TIFFFetchStripThing(tif, dp, td.td_nstrips, ref td.td_stripbytecount)) return false;
                        break;
                    case TIFFTAG.COLORMAP:
                    case TIFFTAG.TRANSFERFUNCTION:
                        {
                            // TransferFunction can have either 1x or 3x
                            // data values; Colormap can have only 3x
                            // items.
                            v=1u<<td.td_bitspersample;
                            if((TIFFTAG)dp.tdir_tag==TIFFTAG.COLORMAP||dp.tdir_count!=v)
                            {
                                if(!CheckDirCount(tif, dp, 3*v)) break;
                            }

                            //v*=sizeof(ushort);
                            ushort[] cp=null;
                            try
                            {
                                cp=new ushort[dp.tdir_count];
                            }
                            catch
                            {
                                TIFFErrorExt(tif.tif_clientdata, tif.tif_name, "No space to read \"TransferFunction\" tag");
                            }

                            if(cp==null) break;
                            if(TIFFFetchData(tif, dp, cp)==0) break;

                            // This deals with there being
                            // only one array to apply to
                            // all samples.
                            uint c=1u<<td.td_bitspersample;
                            if(dp.tdir_count==c) TIFFSetField(tif, (TIFFTAG)dp.tdir_tag, cp, cp, cp);
                            else
                            {
                                try
                                {
                                    ushort[] cp1=new ushort[v];
                                    ushort[] cp2=new ushort[v];
                                    ushort[] cp3=new ushort[v];

                                    Array.Copy(cp, 0*v, cp1, 0, v);
                                    Array.Copy(cp, 1*v, cp2, 0, v);
                                    Array.Copy(cp, 2*v, cp3, 0, v);

                                    TIFFSetField(tif, (TIFFTAG)dp.tdir_tag, cp1, cp2, cp3);
                                }
                                catch
                                {
                                    TIFFErrorExt(tif.tif_clientdata, tif.tif_name, "No space to read \"TransferFunction\" tag");
                                }
                            }
                        }
                        break;
                    case TIFFTAG.PAGENUMBER:
                    case TIFFTAG.HALFTONEHINTS:
                    case TIFFTAG.YCBCRSUBSAMPLING:
                    case TIFFTAG.DOTRANGE:
                        TIFFFetchShortPair(tif, dp);
                        break;
                    case TIFFTAG.REFERENCEBLACKWHITE:
                        TIFFFetchRefBlackWhite(tif, dp);
                        break;
                    // BEGIN REV 4.0 COMPATIBILITY
                    case TIFFTAG.OSUBFILETYPE:
                        v=0;
                        //was switch(TIFFExtractData(tif, dp.tdir_type, dp.tdir_offset))
                        switch((OFILETYPE)(tif.tif_header.tiff_magic==TIFF_BIGENDIAN?(dp.tdir_offset>>tif_typeshift[dp.tdir_type])&tif_typemask[dp.tdir_type]:dp.tdir_offset&tif_typemask[dp.tdir_type]))
                        {
                            case OFILETYPE.REDUCEDIMAGE: v=(uint)FILETYPE.REDUCEDIMAGE; break;
                            case OFILETYPE.PAGE: v=(uint)FILETYPE.PAGE; break;
                        }
                        if(v!=0) TIFFSetField(tif, TIFFTAG.SUBFILETYPE, v);
                        break;
                    // END REV 4.0 COMPATIBILITY
                    default:
                        TIFFFetchNormalTag(tif, dp);
                        break;
                }
            }

            // Verify Palette image has a Colormap.
            if(td.td_photometric==PHOTOMETRIC.PALETTE&&!TIFFFieldSet(tif, FIELD.COLORMAP))
            {
                MissingRequired(tif, "Colormap");
                return false;
            }

            // Attempt to deal with a missing StripByteCounts tag.
            if(!TIFFFieldSet(tif, FIELD.STRIPBYTECOUNTS))
            {
                // Some manufacturers violate the spec by not giving
                // the size of the strips. In this case, assume there
                // is one uncompressed strip of data.
                if((td.td_planarconfig==PLANARCONFIG.CONTIG&&td.td_nstrips>1)||
                    (td.td_planarconfig==PLANARCONFIG.SEPARATE&&td.td_nstrips!=td.td_samplesperpixel))
                {
                    MissingRequired(tif, "StripByteCounts");
                    return false;
                }

                TIFFWarningExt(tif.tif_clientdata, module, "{0}: TIFF directory is missing required \"{1}\" field, calculating from imagelength", tif.tif_name, TIFFFieldWithTag(tif, TIFFTAG.STRIPBYTECOUNTS).field_name);
                if(EstimateStripByteCounts(tif, dir)<0) return false;

                // Assume we have wrong StripByteCount value (in case of single strip) in
                // following cases:
                //	-	it is equal to zero along with StripOffset;
                //	-	it is larger than file itself (in case of uncompressed image);
                //	-	it is smaller than the size of the bytes per row multiplied on the
                //		number of rows. The last case should not be checked in the case of
                //		writing new image, because we may do not know the exact strip size
                //		until the whole image will be written and directory dumped out.
            }
            else if(td.td_nstrips==1&&td.td_stripoffset[0]!=0&&((td.td_stripbytecount[0]==0&&td.td_stripoffset[0]!=0)||
                    (td.td_compression==COMPRESSION.NONE&&td.td_stripbytecount[0]>TIFFGetFileSize(tif)-td.td_stripoffset[0])||
                    (tif.tif_mode==O.RDONLY&&td.td_compression==COMPRESSION.NONE&&td.td_stripbytecount[0]<TIFFScanlineSize(tif)*td.td_imagelength)))
            {
                // XXX: Plexus (and others) sometimes give a value of zero for
                // a tag when they don't know what the correct value is! Try
                // and handle the simple case of estimating the size of a one
                // strip image.
                TIFFWarningExt(tif.tif_clientdata, module, "{0}: Bogus \"{1}\" field, ignoring and calculating from imagelength", tif.tif_name, TIFFFieldWithTag(tif, TIFFTAG.STRIPBYTECOUNTS).field_name);
                if(EstimateStripByteCounts(tif, dir)<0) return false;
            }
            else if(td.td_planarconfig==PLANARCONFIG.CONTIG&&td.td_nstrips>2&&td.td_compression==COMPRESSION.NONE&&td.td_stripbytecount[0]!=td.td_stripbytecount[1]&&td.td_stripbytecount[0]!=0&&td.td_stripbytecount[1]!=0)
            {
                // XXX: Some vendors fill StripByteCount array with absolutely
                // wrong values (it can be equal to StripOffset array, for
                // example). Catch this case here.
                TIFFWarningExt(tif.tif_clientdata, module, "{0}: Wrong \"{1}\" field, ignoring and calculating from imagelength", tif.tif_name, TIFFFieldWithTag(tif, TIFFTAG.STRIPBYTECOUNTS).field_name);
                if(EstimateStripByteCounts(tif, dir)<0) return false;
            }

            dir=null;

            if(!TIFFFieldSet(tif, FIELD.MAXSAMPLEVALUE)) td.td_maxsamplevalue=(ushort)((1<<td.td_bitspersample)-1);

            // Setup default compression scheme.

            // XXX: We can optimize checking for the strip bounds using the sorted
            // bytecounts array. See also comments for TIFFAppendToStrip()
            // function in tif_write.cs.
            if(td.td_nstrips>1)
            {
                td.td_stripbytecountsorted=1;
                for(uint strip=1; strip<td.td_nstrips; strip++)
                {
                    if(td.td_stripoffset[strip-1]>td.td_stripoffset[strip])
                    {
                        td.td_stripbytecountsorted=0;
                        break;
                    }
                }
            }

            if(!TIFFFieldSet(tif, FIELD.COMPRESSION)) TIFFSetField(tif, TIFFTAG.COMPRESSION, COMPRESSION.NONE);

            // Some manufacturers make life difficult by writing
            // large amounts of uncompressed data as a single strip.
            // This is contrary to the recommendations of the spec.
            // The following makes an attempt at breaking such images
            // into strips closer to the recommended 8k bytes. A
            // side effect, however, is that the RowsPerStrip tag
            // value may be changed.
            if(td.td_nstrips==1&&td.td_compression==COMPRESSION.NONE&&(tif.tif_flags&(TIF_FLAGS.TIFF_STRIPCHOP|TIF_FLAGS.TIFF_ISTILED))==TIF_FLAGS.TIFF_STRIPCHOP)
                ChopUpSingleUncompressedStrip(tif);

            // Reinitialize i/o since we are starting on a new directory.
            tif.tif_row=0xffffffff;
            tif.tif_curstrip=0xffffffff;
            tif.tif_col=0xffffffff;
            tif.tif_curtile=0xffffffff;
            tif.tif_tilesize=-1;

            tif.tif_scanlinesize=(uint)TIFFScanlineSize(tif);
            if(tif.tif_scanlinesize==0)
            {
                TIFFErrorExt(tif.tif_clientdata, module, "{0}: cannot handle zero scanline size", tif.tif_name);
                return false;
            }

            if(isTiled(tif))
            {
                tif.tif_tilesize=TIFFTileSize(tif);
                if(tif.tif_tilesize==0)
                {
                    TIFFErrorExt(tif.tif_clientdata, module, "{0}: cannot handle zero tile size", tif.tif_name);
                    return false;
                }
            }
            else
            {
                if(TIFFStripSize(tif)==0)
                {
                    TIFFErrorExt(tif.tif_clientdata, module, "{0}: cannot handle zero strip size", tif.tif_name);
                    return false;
                }
            }

            return true;
        }
Esempio n. 3
0
        // Unlink the specified directory from the directory chain.
        public static bool TIFFUnlinkDirectory(TIFF tif, ushort dirn)
        {
            string module="TIFFUnlinkDirectory";

            if(tif.tif_mode==O.RDONLY)
            {
                TIFFErrorExt(tif.tif_clientdata, module, "Can not unlink directory in read-only file");
                return false;
            }

            // Go to the directory before the one we want
            // to unlink and nab the offset of the link
            // field we'll need to patch.
            uint nextdir=tif.tif_header.tiff_diroff;
            uint off=4;
            uint n;
            for(n=dirn-1u; n>0; n--)
            {
                if(nextdir==0)
                {
                    TIFFErrorExt(tif.tif_clientdata, module, "Directory {0} does not exist", dirn);
                    return false;
                }

                if(!TIFFAdvanceDirectory(tif, ref nextdir, out off)) return false;
            }

            // Advance to the directory to be unlinked and fetch
            // the offset of the directory that follows.
            uint @null;
            if(!TIFFAdvanceDirectory(tif, ref nextdir, out @null)) return false;

            // Go back and patch the link field of the preceding
            // directory to point to the offset of the directory
            // that follows.
            TIFFSeekFile(tif, off, SEEK.SET);

            if((tif.tif_flags&TIF_FLAGS.TIFF_SWAB)!=0) TIFFSwab(ref nextdir);

            if(!WriteOK(tif, nextdir))
            {
                TIFFErrorExt(tif.tif_clientdata, module, "Error writing directory link");
                return false;
            }

            // Leave directory state setup safely. We don't have
            // facilities for doing inserting and removing directories,
            // so it's safest to just invalidate everything. This
            // means that the caller can only append to the directory
            // chain.
            tif.tif_cleanup(tif);
            if((tif.tif_flags&TIF_FLAGS.TIFF_MYBUFFER)!=0&&tif.tif_rawdata!=null)
            {
                tif.tif_rawdata=null;
                tif.tif_rawcc=0;
            }

            tif.tif_flags&=~(TIF_FLAGS.TIFF_BEENWRITING|TIF_FLAGS.TIFF_BUFFERSETUP|TIF_FLAGS.TIFF_POSTENCODE);
            TIFFFreeDirectory(tif);
            TIFFDefaultDirectory(tif);
            tif.tif_diroff=0;			// force link on next write
            tif.tif_nextdiroff=0;		// next write must be at end
            tif.tif_curoff=0;
            tif.tif_row=0xffffffff;
            tif.tif_curstrip=0xffffffff;
            return true;
        }
Esempio n. 4
0
        static bool _TIFFVSetField(TIFF tif, TIFFTAG tag, TIFFDataType dt, object[] ap)
        {
            string module="_TIFFVSetField";

            TIFFDirectory td=tif.tif_dir;
            bool status=true;
            uint v;

            switch(tag)
            {
                case TIFFTAG.SUBFILETYPE:
                    td.td_subfiletype=(FILETYPE)__GetAsUint(ap, 0);
                    break;
                case TIFFTAG.IMAGEWIDTH:
                    td.td_imagewidth=__GetAsUint(ap, 0);
                    break;
                case TIFFTAG.IMAGELENGTH:
                    td.td_imagelength=__GetAsUint(ap, 0);
                    break;
                case TIFFTAG.BITSPERSAMPLE:
                    td.td_bitspersample=__GetAsUshort(ap, 0);

                    // If the data require post-decoding processing to byte-swap
                    // samples, set it up here. Note that since tags are required
                    // to be ordered, compression code can override this behaviour
                    // in the setup method if it wants to roll the post decoding
                    // work in with its normal work.
                    if((tif.tif_flags&TIF_FLAGS.TIFF_SWAB)!=0)
                    {
                        if(td.td_bitspersample==16) tif.tif_postdecode=TIFFSwab16BitData;
                        else if(td.td_bitspersample==24) tif.tif_postdecode=TIFFSwab24BitData;
                        else if(td.td_bitspersample==32) tif.tif_postdecode=TIFFSwab32BitData;
                        else if(td.td_bitspersample==64) tif.tif_postdecode=TIFFSwab64BitData;
                        else if(td.td_bitspersample==128) tif.tif_postdecode=TIFFSwab64BitData; // two 64's
                    }
                    break;
                case TIFFTAG.COMPRESSION:
                    v=__GetAsUint(ap, 0)&0xffff;

                    // If we're changing the compression scheme, the notify the
                    // previous module so that it can cleanup any state it's setup.
                    if(TIFFFieldSet(tif, FIELD.COMPRESSION))
                    {
                        if(td.td_compression==(COMPRESSION)v) break;
                        tif.tif_cleanup(tif);
                        tif.tif_flags&=~TIF_FLAGS.TIFF_CODERSETUP;
                    }

                    // Setup new compression routine state.
                    if(status=TIFFSetCompressionScheme(tif, (COMPRESSION)v)) td.td_compression=(COMPRESSION)v;
                    else status=false;
                    break;
                case TIFFTAG.PHOTOMETRIC:
                    td.td_photometric=(PHOTOMETRIC)__GetAsUshort(ap, 0);
                    break;
                case TIFFTAG.THRESHHOLDING:
                    td.td_threshholding=(THRESHHOLD)__GetAsUshort(ap, 0);
                    break;
                case TIFFTAG.FILLORDER:
                    v=__GetAsUint(ap, 0);
                    if((FILLORDER)v!=FILLORDER.LSB2MSB&&(FILLORDER)v!=FILLORDER.MSB2LSB) goto badvalue;
                    td.td_fillorder=(FILLORDER)v;
                    break;
                case TIFFTAG.ORIENTATION:
                    v=__GetAsUint(ap, 0);
                    if((ORIENTATION)v<ORIENTATION.TOPLEFT||ORIENTATION.LEFTBOT<(ORIENTATION)v)
                        goto badvalue;
                    td.td_orientation=(ORIENTATION)v;
                    break;
                case TIFFTAG.SAMPLESPERPIXEL:
                    // XXX should cross check -- e.g. if pallette, then 1
                    v=__GetAsUint(ap, 0);
                    if(v==0) goto badvalue;
                    td.td_samplesperpixel=(ushort)v;
                    break;
                case TIFFTAG.ROWSPERSTRIP:
                    v=__GetAsUint(ap, 0);
                    if(v==0) goto badvalue;
                    td.td_rowsperstrip=v;
                    if(!TIFFFieldSet(tif, FIELD.TILEDIMENSIONS))
                    {
                        td.td_tilelength=v;
                        td.td_tilewidth=td.td_imagewidth;
                    }
                    break;
                case TIFFTAG.MINSAMPLEVALUE:
                    td.td_minsamplevalue=__GetAsUshort(ap, 0);
                    break;
                case TIFFTAG.MAXSAMPLEVALUE:
                    td.td_maxsamplevalue=__GetAsUshort(ap, 0);
                    break;
                case TIFFTAG.SMINSAMPLEVALUE:
                    td.td_sminsamplevalue=__GetAsDouble(ap, 0);
                    break;
                case TIFFTAG.SMAXSAMPLEVALUE:
                    td.td_smaxsamplevalue=__GetAsDouble(ap, 0);
                    break;
                case TIFFTAG.XRESOLUTION:
                    td.td_xresolution=__GetAsDouble(ap, 0);
                    break;
                case TIFFTAG.YRESOLUTION:
                    td.td_yresolution=__GetAsDouble(ap, 0);
                    break;
                case TIFFTAG.PLANARCONFIG:
                    v=__GetAsUint(ap, 0);
                    if((PLANARCONFIG)v!=PLANARCONFIG.CONTIG&&(PLANARCONFIG)v!=PLANARCONFIG.SEPARATE) goto badvalue;
                    td.td_planarconfig=(PLANARCONFIG)v;
                    break;
                case TIFFTAG.XPOSITION:
                    td.td_xposition=__GetAsDouble(ap, 0);
                    break;
                case TIFFTAG.YPOSITION:
                    td.td_yposition=__GetAsDouble(ap, 0);
                    break;
                case TIFFTAG.RESOLUTIONUNIT:
                    v=__GetAsUint(ap, 0);
                    if((RESUNIT)v<RESUNIT.NONE||RESUNIT.CENTIMETER<(RESUNIT)v) goto badvalue;
                    td.td_resolutionunit=(RESUNIT)v;
                    break;
                case TIFFTAG.PAGENUMBER:
                    td.td_pagenumber[0]=__GetAsUshort(ap, 0);
                    td.td_pagenumber[1]=__GetAsUshort(ap, 1);
                    break;
                case TIFFTAG.HALFTONEHINTS:
                    td.td_halftonehints[0]=__GetAsUshort(ap, 0);
                    td.td_halftonehints[1]=__GetAsUshort(ap, 1);
                    break;
                case TIFFTAG.COLORMAP:
                    v=1u<<td.td_bitspersample;
                    TIFFsetShortArray(ref td.td_colormap[0], (ushort[])ap[0], v);
                    TIFFsetShortArray(ref td.td_colormap[1], (ushort[])ap[1], v);
                    TIFFsetShortArray(ref td.td_colormap[2], (ushort[])ap[2], v);
                    break;
                case TIFFTAG.EXTRASAMPLES:
                    if(!setExtraSamples(td, ap, out v)) goto badvalue;
                    break;
                case TIFFTAG.MATTEING:
                    td.td_extrasamples=(ushort)((__GetAsInt(ap, 0)!=0)?1:0);
                    if(td.td_extrasamples!=0)
                    {
                        ushort[] sv=new ushort[] { (ushort)EXTRASAMPLE.ASSOCALPHA };
                        TIFFsetShortArray(ref td.td_sampleinfo, sv, 1);
                    }
                    break;
                case TIFFTAG.TILEWIDTH:
                    v=__GetAsUint(ap, 0);
                    if((v%16)!=0)
                    {
                        if(tif.tif_mode!=O.RDONLY) goto badvalue;
                        TIFFWarningExt(tif.tif_clientdata, tif.tif_name, "Nonstandard tile width {0}, convert file", v);
                    }
                    td.td_tilewidth=v;
                    tif.tif_flags|=TIF_FLAGS.TIFF_ISTILED;
                    break;
                case TIFFTAG.TILELENGTH:
                    v=__GetAsUint(ap, 0);
                    if((v%16)!=0)
                    {
                        if(tif.tif_mode!=O.RDONLY) goto badvalue;
                        TIFFWarningExt(tif.tif_clientdata, tif.tif_name, "Nonstandard tile length {0}, convert file", v);
                    }
                    td.td_tilelength=v;
                    tif.tif_flags|=TIF_FLAGS.TIFF_ISTILED;
                    break;
                case TIFFTAG.TILEDEPTH:
                    v=__GetAsUint(ap, 0);
                    if(v==0) goto badvalue;
                    td.td_tiledepth=v;
                    break;
                case TIFFTAG.DATATYPE:
                    v=__GetAsUint(ap, 0);
                    switch(v)
                    {
                        case DATATYPE_VOID: td.td_sampleformat=SAMPLEFORMAT.VOID; break;
                        case DATATYPE_INT: td.td_sampleformat=SAMPLEFORMAT.INT; break;
                        case DATATYPE_UINT: td.td_sampleformat=SAMPLEFORMAT.UINT; break;
                        case DATATYPE_IEEEFP: td.td_sampleformat=SAMPLEFORMAT.IEEEFP; break;
                        default: goto badvalue;
                    }
                    break;
                case TIFFTAG.SAMPLEFORMAT:
                    v=__GetAsUint(ap, 0);
                    if((SAMPLEFORMAT)v<SAMPLEFORMAT.UINT||SAMPLEFORMAT.COMPLEXIEEEFP<(SAMPLEFORMAT)v) goto badvalue;
                    td.td_sampleformat=(SAMPLEFORMAT)v;

                    // Try to fix up the SWAB function for complex data.
                    if(td.td_sampleformat==SAMPLEFORMAT.COMPLEXINT&&td.td_bitspersample==32&&tif.tif_postdecode==TIFFSwab32BitData) tif.tif_postdecode=TIFFSwab16BitData;
                    else if((td.td_sampleformat==SAMPLEFORMAT.COMPLEXINT||td.td_sampleformat==SAMPLEFORMAT.COMPLEXIEEEFP)&&td.td_bitspersample==64&&
                        tif.tif_postdecode==TIFFSwab64BitData) tif.tif_postdecode=TIFFSwab32BitData;

                    break;
                case TIFFTAG.IMAGEDEPTH:
                    td.td_imagedepth=__GetAsUint(ap, 0);
                    break;
                case TIFFTAG.SUBIFD:
                    if((tif.tif_flags&TIF_FLAGS.TIFF_INSUBIFD)==0)
                    {
                        td.td_nsubifd=__GetAsUshort(ap, 0);
                        uint[] tmp=new uint[1];
                        tmp[0]=(uint)ap[1];
                        TIFFsetLongArray(ref td.td_subifd, tmp, td.td_nsubifd);
                    }
                    else
                    {
                        TIFFErrorExt(tif.tif_clientdata, module, "{0}: Sorry, cannot nest SubIFDs", tif.tif_name);
                        status=false;
                    }
                    break;
                case TIFFTAG.YCBCRPOSITIONING:
                    td.td_ycbcrpositioning=(YCBCRPOSITION)__GetAsUshort(ap, 0);
                    break;
                case TIFFTAG.YCBCRSUBSAMPLING:
                    td.td_ycbcrsubsampling[0]=__GetAsUshort(ap, 0);
                    td.td_ycbcrsubsampling[1]=__GetAsUshort(ap, 1);
                    break;
                case TIFFTAG.TRANSFERFUNCTION:
                    v=(uint)((td.td_samplesperpixel-td.td_extrasamples)>1?3:1);
                    for(int i=0; i<v; i++)
                        TIFFsetShortArray(ref td.td_transferfunction[i], (ushort[])ap[i], 1u<<td.td_bitspersample);
                    break;
                case TIFFTAG.REFERENCEBLACKWHITE:
                    // XXX should check for null range
                    TIFFsetDoubleArray(ref td.td_refblackwhite, (double[])ap[0], 6);
                    break;
                case TIFFTAG.INKNAMES:
                    v=__GetAsUint(ap, 0);
                    string s=(string)ap[1];
                    v=checkInkNamesString(tif, v, s);
                    status=v>0;
                    if(v>0)
                    {
                        td.td_inknames=s.Substring(0, (int)v);
                        td.td_inknameslen=(int)v;
                    }
                    break;
                default:
                    {
                        TIFFFieldInfo fip=TIFFFindFieldInfo(tif, tag, dt); // was TIFFDataType.TIFF_ANY);
                        TIFFTagValue tv;
                        int iCustom;

                        // This can happen if multiple images are open with different
                        // codecs which have private tags. The global tag information
                        // table may then have tags that are valid for one file but not
                        // the other. If the client tries to set a tag that is not valid
                        // for the image's codec then we'll arrive here. This
                        // happens, for example, when tiffcp is used to convert between
                        // compression schemes and codec-specific tags are blindly copied.
                        if(fip==null||fip.field_bit!=FIELD.CUSTOM)
                        {
                            TIFFErrorExt(tif.tif_clientdata, module, "{0}: Invalid {1}tag \"{2}\" (not supported by codec)", tif.tif_name, isPseudoTag(tag)?"pseudo-":"", fip!=null?fip.field_name:"Unknown");
                            status=false;
                            break;
                        }

                        // Find the existing entry for this custom value.
                        tv=null;
                        for(iCustom=0; iCustom<td.td_customValueCount; iCustom++)
                        {
                            if(td.td_customValues[iCustom].info.field_tag==tag)
                            {
                                tv=td.td_customValues[iCustom];
                                tv.value=null;
                                break;
                            }
                        }

                        // Grow the custom list if the entry was not found.
                        if(tv==null)
                        {
                            try
                            {
                                td.td_customValueCount++;
                                if(td.td_customValues==null) td.td_customValues=new List<TIFFTagValue>();

                                tv=new TIFFTagValue();
                                tv.info=fip;

                                td.td_customValues.Add(tv);
                            }
                            catch
                            {
                                TIFFErrorExt(tif.tif_clientdata, module, "{0}: Failed to allocate space for list of custom values", tif.tif_name);
                                status=false;
                                goto end;
                            }
                        }

                        // Set custom value ... save a copy of the custom tag value.
                        if(TIFFDataSize(fip.field_type)==0)
                        {
                            status=false;
                            TIFFErrorExt(tif.tif_clientdata, module, "{0}: Bad field type {1} for \"{2}\"", tif.tif_name, fip.field_type, fip.field_name);
                            goto end;
                        }

                        int apcount=0;
                        if(fip.field_passcount) tv.count=__GetAsInt(ap, apcount++);
                        else if(fip.field_writecount==TIFF_VARIABLE) tv.count=1;
                        else if(fip.field_writecount==TIFF_SPP) tv.count=td.td_samplesperpixel;
                        else tv.count=fip.field_writecount;

                        if(fip.field_type==TIFFDataType.TIFF_ASCII) tv.value=(string)ap[apcount++];
                        else
                        {
                            if(tv.count<1)
                            {
                                status=false;
                                goto end;
                            }

                            byte[] byteArray=null;
                            sbyte[] sbyteArray=null;
                            ushort[] ushortArray=null;
                            short[] shortArray=null;
                            uint[] uintArray=null;
                            int[] intArray=null;
                            float[] floatArray=null;
                            double[] doubleArray=null;

                            try
                            {
                                switch(fip.field_type)
                                {
                                    case TIFFDataType.TIFF_UNDEFINED:
                                    case TIFFDataType.TIFF_BYTE:
                                        tv.value=byteArray=new byte[tv.count];
                                        break;
                                    case TIFFDataType.TIFF_SBYTE:
                                        tv.value=sbyteArray=new sbyte[tv.count];
                                        break;
                                    case TIFFDataType.TIFF_SHORT:
                                        tv.value=ushortArray=new ushort[tv.count];
                                        break;
                                    case TIFFDataType.TIFF_SSHORT:
                                        tv.value=shortArray=new short[tv.count];
                                        break;
                                    case TIFFDataType.TIFF_IFD:
                                    case TIFFDataType.TIFF_LONG:
                                        tv.value=uintArray=new uint[tv.count];
                                        break;
                                    case TIFFDataType.TIFF_SLONG:
                                        tv.value=intArray=new int[tv.count];
                                        break;
                                    case TIFFDataType.TIFF_FLOAT:
                                        tv.value=floatArray=new float[tv.count];
                                        break;
                                    case TIFFDataType.TIFF_RATIONAL:
                                    case TIFFDataType.TIFF_SRATIONAL:
                                    case TIFFDataType.TIFF_DOUBLE:
                                        tv.value=doubleArray=new double[tv.count];
                                        break;
                                    default:
                                        tv.value=null;
                                        break;
                                }
                            }
                            catch
                            {
                                TIFFErrorExt(tif.tif_clientdata, module, "{0}: Out of memory.", tif.tif_name);
                                status=false;
                                goto end;
                            }

                            bool done=false;
                            if((fip.field_passcount||fip.field_writecount==TIFF_VARIABLE||fip.field_writecount==TIFF_SPP))
                            {
                                Array a=ap[apcount] as Array;
                                if(a!=null&&a.Length>=tv.count)
                                {
                                    switch(fip.field_type)
                                    {
                                        case TIFFDataType.TIFF_UNDEFINED:
                                        case TIFFDataType.TIFF_BYTE:
                                            if(a is byte[])
                                            {
                                                Array.Copy(a, byteArray, tv.count);
                                                done=true;
                                            }
                                            else
                                            {
                                                TIFFErrorExt(tif.tif_clientdata, module, "{0}: Bad argument type for \"{2}\" ({1}). Should be a byte[].", tif.tif_name, fip.field_type, fip.field_name);
                                                status=false;
                                                goto end;
                                            }
                                            break;
                                        case TIFFDataType.TIFF_SBYTE:
                                            if(a is sbyte[])
                                            {
                                                Array.Copy(a, sbyteArray, tv.count);
                                                done=true;
                                            }
                                            else
                                            {
                                                TIFFErrorExt(tif.tif_clientdata, module, "{0}: Bad argument type for \"{2}\" ({1}). Should be a sbyte[].", tif.tif_name, fip.field_type, fip.field_name);
                                                status=false;
                                                goto end;
                                            }
                                            break;
                                        case TIFFDataType.TIFF_SHORT:
                                            if(a is ushort[])
                                            {
                                                Array.Copy(a, ushortArray, tv.count);
                                                done=true;
                                            }
                                            else
                                            {
                                                TIFFErrorExt(tif.tif_clientdata, module, "{0}: Bad argument type for \"{2}\" ({1}). Should be a ushort[].", tif.tif_name, fip.field_type, fip.field_name);
                                                status=false;
                                                goto end;
                                            }
                                            break;
                                        case TIFFDataType.TIFF_SSHORT:
                                            if(a is short[])
                                            {
                                                Array.Copy(a, shortArray, tv.count);
                                                done=true;
                                            }
                                            else
                                            {
                                                TIFFErrorExt(tif.tif_clientdata, module, "{0}: Bad argument type for \"{2}\" ({1}). Should be a short[].", tif.tif_name, fip.field_type, fip.field_name);
                                                status=false;
                                                goto end;
                                            }
                                            break;
                                        case TIFFDataType.TIFF_IFD:
                                        case TIFFDataType.TIFF_LONG:
                                            if(a is uint[])
                                            {
                                                Array.Copy(a, uintArray, tv.count);
                                                done=true;
                                            }
                                            else
                                            {
                                                TIFFErrorExt(tif.tif_clientdata, module, "{0}: Bad argument type for \"{2}\" ({1}). Should be a ulong[].", tif.tif_name, fip.field_type, fip.field_name);
                                                status=false;
                                                goto end;
                                            }
                                            break;
                                        case TIFFDataType.TIFF_SLONG:
                                            if(a is int[])
                                            {
                                                Array.Copy(a, intArray, tv.count);
                                                done=true;
                                            }
                                            else
                                            {
                                                TIFFErrorExt(tif.tif_clientdata, module, "{0}: Bad argument type for \"{2}\" ({1}). Should be a long[].", tif.tif_name, fip.field_type, fip.field_name);
                                                status=false;
                                                goto end;
                                            }
                                            break;
                                        case TIFFDataType.TIFF_FLOAT:
                                            if(a is float[])
                                            {
                                                Array.Copy(a, floatArray, tv.count);
                                                done=true;
                                            }
                                            else
                                            {
                                                TIFFErrorExt(tif.tif_clientdata, module, "{0}: Bad argument type for \"{2}\" ({1}). Should be a float[].", tif.tif_name, fip.field_type, fip.field_name);
                                                status=false;
                                                goto end;
                                            }
                                            break;
                                        case TIFFDataType.TIFF_RATIONAL:
                                        case TIFFDataType.TIFF_SRATIONAL:
                                        case TIFFDataType.TIFF_DOUBLE:
                                            if(a is double[])
                                            {
                                                Array.Copy(a, doubleArray, tv.count);
                                                done=true;
                                            }
                                            else
                                            {
                                                TIFFErrorExt(tif.tif_clientdata, module, "{0}: Bad argument type for \"{2}\" ({1}). Should be a double[].", tif.tif_name, fip.field_type, fip.field_name);
                                                status=false;
                                                goto end;
                                            }
                                            break;
                                        default:
                                            tv.value=null;
                                            break;
                                    } // switch
                                } // if(a!=null&&a.Length>=tv.count)
                                else if(a!=null)
                                {
                                    TIFFErrorExt(tif.tif_clientdata, module, "{0}: Bad argument type for \"{2}\" ({1}). Array has too few elements.", tif.tif_name, fip.field_type, fip.field_name);
                                    status=false;
                                    goto end;
                                }
                            }

                            if(!done)
                            {
                                try
                                {
                                    Array a=ap[apcount] as Array;

                                    if(a!=null&&a.Length>=tv.count)
                                    {
                                        switch(fip.field_type)
                                        {
                                            case TIFFDataType.TIFF_UNDEFINED:
                                            case TIFFDataType.TIFF_BYTE:
                                                if(a is byte[])
                                                {
                                                    Array.Copy(a, byteArray, tv.count);
                                                    done=true;
                                                }
                                                else
                                                {
                                                    TIFFErrorExt(tif.tif_clientdata, module, "{0}: Bad argument type for \"{2}\" ({1}). Should be a byte[].", tif.tif_name, fip.field_type, fip.field_name);
                                                    status=false;
                                                    goto end;
                                                }
                                                break;
                                            case TIFFDataType.TIFF_SBYTE:
                                                if(a is sbyte[])
                                                {
                                                    Array.Copy(a, sbyteArray, tv.count);
                                                    done=true;
                                                }
                                                else
                                                {
                                                    TIFFErrorExt(tif.tif_clientdata, module, "{0}: Bad argument type for \"{2}\" ({1}). Should be a sbyte[].", tif.tif_name, fip.field_type, fip.field_name);
                                                    status=false;
                                                    goto end;
                                                }
                                                break;
                                            case TIFFDataType.TIFF_SHORT:
                                                if(a is ushort[])
                                                {
                                                    Array.Copy(a, ushortArray, tv.count);
                                                    done=true;
                                                }
                                                else
                                                {
                                                    TIFFErrorExt(tif.tif_clientdata, module, "{0}: Bad argument type for \"{2}\" ({1}). Should be a ushort[].", tif.tif_name, fip.field_type, fip.field_name);
                                                    status=false;
                                                    goto end;
                                                }
                                                break;
                                            case TIFFDataType.TIFF_SSHORT:
                                                if(a is short[])
                                                {
                                                    Array.Copy(a, shortArray, tv.count);
                                                    done=true;
                                                }
                                                else
                                                {
                                                    TIFFErrorExt(tif.tif_clientdata, module, "{0}: Bad argument type for \"{2}\" ({1}). Should be a short[].", tif.tif_name, fip.field_type, fip.field_name);
                                                    status=false;
                                                    goto end;
                                                }
                                                break;
                                            case TIFFDataType.TIFF_IFD:
                                            case TIFFDataType.TIFF_LONG:
                                                if(a is uint[])
                                                {
                                                    Array.Copy(a, uintArray, tv.count);
                                                    done=true;
                                                }
                                                else
                                                {
                                                    TIFFErrorExt(tif.tif_clientdata, module, "{0}: Bad argument type for \"{2}\" ({1}). Should be a ulong[].", tif.tif_name, fip.field_type, fip.field_name);
                                                    status=false;
                                                    goto end;
                                                }
                                                break;
                                            case TIFFDataType.TIFF_SLONG:
                                                if(a is int[])
                                                {
                                                    Array.Copy(a, intArray, tv.count);
                                                    done=true;
                                                }
                                                else
                                                {
                                                    TIFFErrorExt(tif.tif_clientdata, module, "{0}: Bad argument type for \"{2}\" ({1}). Should be a long[].", tif.tif_name, fip.field_type, fip.field_name);
                                                    status=false;
                                                    goto end;
                                                }
                                                break;
                                            case TIFFDataType.TIFF_FLOAT:
                                                if(a is float[])
                                                {
                                                    Array.Copy(a, floatArray, tv.count);
                                                    done=true;
                                                }
                                                else
                                                {
                                                    TIFFErrorExt(tif.tif_clientdata, module, "{0}: Bad argument type for \"{2}\" ({1}). Should be a float[].", tif.tif_name, fip.field_type, fip.field_name);
                                                    status=false;
                                                    goto end;
                                                }
                                                break;
                                            case TIFFDataType.TIFF_RATIONAL:
                                            case TIFFDataType.TIFF_SRATIONAL:
                                            case TIFFDataType.TIFF_DOUBLE:
                                                if(a is double[])
                                                {
                                                    Array.Copy(a, doubleArray, tv.count);
                                                    done=true;
                                                }
                                                else
                                                {
                                                    TIFFErrorExt(tif.tif_clientdata, module, "{0}: Bad argument type for \"{2}\" ({1}). Should be a double[].", tif.tif_name, fip.field_type, fip.field_name);
                                                    status=false;
                                                    goto end;
                                                }
                                                break;
                                            default:
                                                tv.value=null;
                                                break;
                                        } // switch
                                    }
                                    else
                                    {
                                        switch(fip.field_type)
                                        {
                                            case TIFFDataType.TIFF_UNDEFINED:
                                            case TIFFDataType.TIFF_BYTE:
                                                for(int i=0; i<tv.count; i++) byteArray[i]=__GetAsByte(ap, apcount++);
                                                break;
                                            case TIFFDataType.TIFF_SBYTE:
                                                for(int i=0; i<tv.count; i++) sbyteArray[i]=__GetAsSbyte(ap, apcount++);
                                                break;
                                            case TIFFDataType.TIFF_SHORT:
                                                for(int i=0; i<tv.count; i++) ushortArray[i]=__GetAsUshort(ap, apcount++);
                                                break;
                                            case TIFFDataType.TIFF_SSHORT:
                                                for(int i=0; i<tv.count; i++) shortArray[i]=__GetAsShort(ap, apcount++);
                                                break;
                                            case TIFFDataType.TIFF_IFD:
                                            case TIFFDataType.TIFF_LONG:
                                                for(int i=0; i<tv.count; i++) uintArray[i]=__GetAsUint(ap, apcount++);
                                                break;
                                            case TIFFDataType.TIFF_SLONG:
                                                for(int i=0; i<tv.count; i++) intArray[i]=__GetAsInt(ap, apcount++);
                                                break;
                                            case TIFFDataType.TIFF_FLOAT:
                                                for(int i=0; i<tv.count; i++) floatArray[i]=__GetAsFloat(ap, apcount++);
                                                break;
                                            case TIFFDataType.TIFF_RATIONAL:
                                            case TIFFDataType.TIFF_SRATIONAL:
                                            case TIFFDataType.TIFF_DOUBLE:
                                                for(int i=0; i<tv.count; i++) doubleArray[i]=__GetAsDouble(ap, apcount++);
                                                break;
                                        }
                                    }
                                }
                                catch
                                {
                                    TIFFErrorExt(tif.tif_clientdata, module, "{0}: Bad argument({3}) type for \"{2}\" ({1}). Should be an Array anyway!", tif.tif_name, fip.field_type, fip.field_name, apcount);
                                    status=false;
                                    goto end;
                                }
                            } // if(!done)
                        } // fip.field_type!=TIFFDataType.TIFF_ASCII
                    } // default:
                    break;
            } // switch()

            if(status)
            {
                TIFFSetFieldBit(tif, TIFFFieldWithTag(tif, tag).field_bit);
                tif.tif_flags|=TIF_FLAGS.TIFF_DIRTYDIRECT;
            }

            end:
            return status;

            badvalue:
            TIFFErrorExt(tif.tif_clientdata, module, "{0}: Bad value {1} for \"{2}\" tag", tif.tif_name, v, TIFFFieldWithTag(tif, tag).field_name);
            return false;
        }
Esempio n. 5
0
        // Write the contents of the current directory
        // to the specified file. This routine doesn't
        // handle overwriting a directory with auxiliary
        // storage that's been changed.
        static bool TIFFWriteDirectory(TIFF tif, bool done)
        {
            if(tif.tif_mode==O.RDONLY) return true;

            // Clear write state so that subsequent images with
            // different characteristics get the right buffers
            // setup for them.
            if(done)
            {
                if((tif.tif_flags&TIF_FLAGS.TIFF_POSTENCODE)!=0)
                {
                    tif.tif_flags&=~TIF_FLAGS.TIFF_POSTENCODE;
                    if(!tif.tif_postencode(tif))
                    {
                        TIFFErrorExt(tif.tif_clientdata, tif.tif_name, "Error post-encoding before directory write");
                        return false;
                    }
                }
                tif.tif_close(tif); // shutdown encoder

                // Flush any data that might have been written
                // by the compression close+cleanup routines.
                if(tif.tif_rawcc>0&&(tif.tif_flags&TIF_FLAGS.TIFF_BEENWRITING)!=0&&!TIFFFlushData1(tif))
                {
                    TIFFErrorExt(tif.tif_clientdata, tif.tif_name, "Error flushing data before directory write");
                    return false;
                }

                tif.tif_rawdata=null;
                tif.tif_rawcc=0;
                tif.tif_rawdatasize=0;

                tif.tif_flags&=~(TIF_FLAGS.TIFF_BEENWRITING|TIF_FLAGS.TIFF_BUFFERSETUP);
            }

            TIFFDirectory td=tif.tif_dir;

            // Some Irfan view versions don't like RowsPerStrip set in tiled tifs
            if(isTiled(tif)) TIFFClrFieldBit(tif, FIELD.ROWSPERSTRIP);

            // Size the directory so that we can calculate
            // offsets for the data items that aren't kept
            // in-place in each field.
            uint nfields=0;
            uint[] fields=new uint[FIELD_SETLONGS];
            for(FIELD b=0; b<=(FIELD)FIELD_LAST; b++)
            {
                if(TIFFFieldSet(tif, b)&&b!=FIELD.CUSTOM) nfields+=(b<FIELD.SUBFILETYPE?2u:1u);
            }

            nfields+=(uint)td.td_customValueCount;
            int dirsize=(int)nfields*12; // 12: sizeof(TIFFDirEntry);

            List<TIFFDirEntry> dirs=null;
            try
            {
                dirs=new List<TIFFDirEntry>();
                for(int i=0; i<nfields; i++) dirs.Add(new TIFFDirEntry());
            }
            catch
            {
                TIFFErrorExt(tif.tif_clientdata, tif.tif_name, "Cannot write directory, out of space");
                return false;
            }

            // Directory hasn't been placed yet, put
            // it at the end of the file and link it
            // into the existing directory structure.
            if(tif.tif_diroff==0&&!TIFFLinkDirectory(tif)) return false;

            //tif.tif_dataoff=(uint)(tif.tif_diroff+sizeof(uint16)+dirsize+sizeof(toff_t));
            tif.tif_dataoff=(uint)(tif.tif_diroff+2+dirsize+4);

            if((tif.tif_dataoff&1)==1) tif.tif_dataoff++;

            TIFFSeekFile(tif, tif.tif_dataoff, SEEK.SET);
            tif.tif_curdir++;

            // Setup external form of directory
            // entries and write data items.
            td.td_fieldsset.CopyTo(fields, 0);

            // Write out ExtraSamples tag only if
            // extra samples are present in the data.
            if(FieldSet(fields, FIELD.EXTRASAMPLES)&&td.td_extrasamples==0)
            {
                ResetFieldBit(fields, FIELD.EXTRASAMPLES);
                nfields--;
                dirsize-=12; // 12: sizeof(TIFFDirEntry);
            } // XXX

            int dirsnumber=0;
            TIFFTAG tag;
            foreach(TIFFFieldInfo fip in tif.tif_fieldinfo)
            {
                TIFFDirEntry dir=(dirsnumber<dirs.Count)?dir=dirs[dirsnumber]:null;

                // For custom fields, we test to see if the custom field
                // is set or not. For normal fields, we just use the
                // FieldSet test.
                if(fip.field_bit==FIELD.CUSTOM)
                {
                    bool is_set=false;

                    for(int ci=0; ci<td.td_customValueCount; ci++) is_set|=(td.td_customValues[ci].info==fip);
                    if(!is_set) continue;
                }
                else if(!FieldSet(fields, fip.field_bit)) continue;

                // Handle other fields.
                switch(fip.field_bit)
                {
                    case FIELD.STRIPOFFSETS:

                        // We use one field bit for both strip and tile
                        // offsets, and so must be careful in selecting
                        // the appropriate field descriptor (so that tags
                        // are written in sorted order).
                        tag=isTiled(tif)?TIFFTAG.TILEOFFSETS:TIFFTAG.STRIPOFFSETS;
                        if(tag!=fip.field_tag) continue;

                        dir.tdir_tag=(ushort)tag;
                        dir.tdir_type=(ushort)TIFFDataType.TIFF_LONG;
                        dir.tdir_count=td.td_nstrips;
                        if(!TIFFWriteLongArray(tif, dir, td.td_stripoffset)) return false;
                        break;
                    case FIELD.STRIPBYTECOUNTS:
                        // We use one field bit for both strip and tile
                        // byte counts, and so must be careful in selecting
                        // the appropriate field descriptor (so that tags
                        // are written in sorted order).
                        tag=isTiled(tif)?TIFFTAG.TILEBYTECOUNTS:TIFFTAG.STRIPBYTECOUNTS;
                        if(tag!=fip.field_tag) continue;

                        dir.tdir_tag=(ushort)tag;
                        dir.tdir_type=(ushort)TIFFDataType.TIFF_LONG;
                        dir.tdir_count=td.td_nstrips;
                        if(!TIFFWriteLongArray(tif, dir, td.td_stripbytecount)) return false;
                        break;
                    case FIELD.ROWSPERSTRIP:
                        TIFFSetupShortLong(tif, TIFFTAG.ROWSPERSTRIP, dir, td.td_rowsperstrip);
                        break;
                    case FIELD.COLORMAP:
                        if(!TIFFWriteShortTable(tif, TIFFTAG.COLORMAP, dir, 3, td.td_colormap)) return false;
                        break;
                    case FIELD.IMAGEDIMENSIONS:
                        TIFFSetupShortLong(tif, TIFFTAG.IMAGEWIDTH, dir, td.td_imagewidth);
                        dirsnumber++;
                        dir=dirs[dirsnumber];
                        TIFFSetupShortLong(tif, TIFFTAG.IMAGELENGTH, dir, td.td_imagelength);
                        break;
                    case FIELD.TILEDIMENSIONS:
                        TIFFSetupShortLong(tif, TIFFTAG.TILEWIDTH, dir, td.td_tilewidth);
                        dirsnumber++;
                        dir=dirs[dirsnumber];
                        TIFFSetupShortLong(tif, TIFFTAG.TILELENGTH, dir, td.td_tilelength);
                        break;
                    case FIELD.COMPRESSION:
                        TIFFSetupShort(tif, TIFFTAG.COMPRESSION, dir, (ushort)td.td_compression);
                        break;
                    case FIELD.PHOTOMETRIC:
                        TIFFSetupShort(tif, TIFFTAG.PHOTOMETRIC, dir, (ushort)td.td_photometric);
                        break;
                    case FIELD.POSITION:
                        if(!TIFFWriteRational(tif, TIFFDataType.TIFF_RATIONAL, TIFFTAG.XPOSITION, dir, td.td_xposition)) return false;
                        dirsnumber++;
                        dir=dirs[dirsnumber];
                        if(!TIFFWriteRational(tif, TIFFDataType.TIFF_RATIONAL, TIFFTAG.YPOSITION, dir, td.td_yposition)) return false;
                        break;
                    case FIELD.RESOLUTION:
                        if(!TIFFWriteRational(tif, TIFFDataType.TIFF_RATIONAL, TIFFTAG.XRESOLUTION, dir, td.td_xresolution)) return false;
                        dirsnumber++;
                        dir=dirs[dirsnumber];
                        if(!TIFFWriteRational(tif, TIFFDataType.TIFF_RATIONAL, TIFFTAG.YRESOLUTION, dir, td.td_yresolution)) return false;
                        break;
                    case FIELD.BITSPERSAMPLE:
                    case FIELD.MINSAMPLEVALUE:
                    case FIELD.MAXSAMPLEVALUE:
                    case FIELD.SAMPLEFORMAT:
                        if(!TIFFWritePerSampleShorts(tif, fip.field_tag, dir)) return false;
                        break;
                    case FIELD.SMINSAMPLEVALUE:
                    case FIELD.SMAXSAMPLEVALUE:
                        if(!TIFFWritePerSampleAnys(tif, TIFFSampleToTagType(tif), fip.field_tag, dir)) return false;
                        break;
                    case FIELD.PAGENUMBER:
                    case FIELD.HALFTONEHINTS:
                    case FIELD.YCBCRSUBSAMPLING:
                        if(!TIFFSetupShortPair(tif, fip.field_tag, dir)) return false;
                        break;
                    case FIELD.INKNAMES:
                        if(!TIFFWriteInkNames(tif, dir)) return false;
                        break;
                    case FIELD.TRANSFERFUNCTION:
                        if(!TIFFWriteTransferFunction(tif, dir)) return false;
                        break;
                    case FIELD.SUBIFD:
                        // XXX: Always write this field using LONG type
                        // for backward compatibility.
                        dir.tdir_tag=(ushort)fip.field_tag;
                        dir.tdir_type=(ushort)TIFFDataType.TIFF_LONG;
                        dir.tdir_count=(uint)td.td_nsubifd;
                        if(!TIFFWriteLongArray(tif, dir, td.td_subifd)) return false;

                        // Total hack: if this directory includes a SubIFD
                        // tag then force the next <n> directories to be
                        // written as "sub directories" of this one. This
                        // is used to write things like thumbnails and
                        // image masks that one wants to keep out of the
                        // normal directory linkage access mechanism.
                        if(dir.tdir_count>0)
                        {
                            tif.tif_flags|=TIF_FLAGS.TIFF_INSUBIFD;
                            tif.tif_nsubifd=(ushort)dir.tdir_count;
                            if(dir.tdir_count>1) tif.tif_subifdoff=dir.tdir_offset;
                            //was else tif.tif_subifdoff=(uint)(tif.tif_diroff+2+((char*)&dir.tdir_offset-data));
                            else tif.tif_subifdoff=(uint)(tif.tif_diroff+2+12*dirsnumber-4);
                        }
                        break;
                    default:
                        // XXX: Should be fixed and removed.
                        if(fip.field_tag==TIFFTAG.DOTRANGE)
                        {
                            if(!TIFFSetupShortPair(tif, fip.field_tag, dir)) return false;
                        }
                        else if(!TIFFWriteNormalTag(tif, dir, fip)) return false;
                        break;
                }
                dirsnumber++;

                if(fip.field_bit!=FIELD.CUSTOM) ResetFieldBit(fields, fip.field_bit);
            }

            // Write directory.
            ushort dircount=(ushort)nfields;
            uint diroff=tif.tif_nextdiroff;
            if((tif.tif_flags&TIF_FLAGS.TIFF_SWAB)!=0)
            {
                // The file's byte order is opposite to the
                // native machine architecture. We overwrite
                // the directory information with impunity
                // because it'll be released below after we
                // write it to the file. Note that all the
                // other tag construction routines assume that
                // we do this byte-swapping; i.e. they only
                // byte-swap indirect data.
                foreach(TIFFDirEntry dir in dirs)
                {
                    TIFFSwab(ref dir.tdir_tag);
                    TIFFSwab(ref dir.tdir_type);
                    TIFFSwab(ref dir.tdir_count);
                    TIFFSwab(ref dir.tdir_offset);
                }
                dircount=(ushort)nfields;
                TIFFSwab(ref dircount);
                TIFFSwab(ref diroff);
            }

            TIFFSeekFile(tif, tif.tif_diroff, SEEK.SET);
            if(!WriteOK(tif, dircount))
            {
                TIFFErrorExt(tif.tif_clientdata, tif.tif_name, "Error writing directory count");
                return false;
            }

            if(!WriteOK(tif, dirs, (ushort)dirsize))
            {
                TIFFErrorExt(tif.tif_clientdata, tif.tif_name, "Error writing directory contents");
                return false;
            }

            if(!WriteOK(tif, diroff))
            {
                TIFFErrorExt(tif.tif_clientdata, tif.tif_name, "Error writing directory link");
                return false;
            }

            if(done)
            {
                TIFFFreeDirectory(tif);
                tif.tif_flags&=~TIF_FLAGS.TIFF_DIRTYDIRECT;
                tif.tif_cleanup(tif);

                // Reset directory-related state for subsequent directories.
                TIFFCreateDirectory(tif);
            }

            return true;
        }