Ejemplo n.º 1
0
        private static void printField(Stream fd, TiffFieldInfo fip, int value_count, object raw_data)
        {
            fprintf(fd, "  {0}: ", fip.Name);

            byte[] bytes = raw_data as byte[];
            sbyte[] sbytes = raw_data as sbyte[];
            short[] shorts = raw_data as short[];
            ushort[] ushorts = raw_data as ushort[];
            int[] ints = raw_data as int[];
            uint[] uints = raw_data as uint[];
            float[] floats = raw_data as float[];
            double[] doubles = raw_data as double[];
            string s = raw_data as string;

            for (int j = 0; j < value_count; j++)
            {
                if (fip.Type == TiffType.Byte || fip.Type == TiffType.SByte)
                {
                    if (bytes != null)
                        fprintf(fd, "{0}", bytes[j]);
                    else if (sbytes != null)
                        fprintf(fd, "{0}", sbytes[j]);
                }
                else if (fip.Type == TiffType.Undefined)
                {
                    if (bytes != null)
                        fprintf(fd, "0x{0:x}", bytes[j]);
                }
                else if (fip.Type == TiffType.Short || fip.Type == TiffType.SShort)
                {
                    if (shorts != null)
                        fprintf(fd, "{0}", shorts[j]);
                    else if (ushorts != null)
                        fprintf(fd, "{0}", ushorts[j]);
                }
                else if (fip.Type == TiffType.Long || fip.Type == TiffType.SLong)
                {
                    if (ints != null)
                        fprintf(fd, "{0}", ints[j]);
                    else if (uints != null)
                        fprintf(fd, "{0}", uints[j]);
                }
                else if (fip.Type == TiffType.Rational ||
                    fip.Type == TiffType.SRational ||
                    fip.Type == TiffType.Float)
                {
                    if (floats != null)
                        fprintf(fd, "{0}", floats[j]);
                }
                else if (fip.Type == TiffType.IFD)
                {
                    if (ints != null)
                        fprintf(fd, "0x{0:x}", ints[j]);
                    else if (uints != null)
                        fprintf(fd, "0x{0:x}", uints[j]);
                }
                else if (fip.Type == TiffType.ASCII)
                {
                    if (s != null)
                        fprintf(fd, "{0}", s);

                    break;
                }
                else if (fip.Type == TiffType.Double || fip.Type == TiffType.Float)
                {
                    if (floats != null)
                        fprintf(fd, "{0}", floats[j]);
                    else if (doubles != null)
                        fprintf(fd, "{0}", doubles[j]);
                }
                else
                {
                    fprintf(fd, "<unsupported data type in printField>");
                    break;
                }

                if (j < value_count - 1)
                    fprintf(fd, ",");
            }

            fprintf(fd, "\r\n");
        }
Ejemplo n.º 2
0
        /// <summary>
        /// Reads the contents of the next TIFF directory in an open TIFF file/stream and makes
        /// it the current directory.
        /// </summary>
        /// <returns><c>true</c> if directory was successfully read; otherwise, <c>false</c> if an
        /// error was encountered, or if there are no more directories to be read.</returns>
        /// <remarks><para>Directories are read sequentially.</para>
        /// <para>Applications only need to call <see cref="ReadDirectory"/> to read multiple
        /// subfiles in a single TIFF file/stream - the first directory in a file/stream is
        /// automatically read when <see cref="Open"/> or <see cref="ClientOpen"/> is called.
        /// </para><para>
        /// The images that have a single uncompressed strip or tile of data are automatically
        /// treated as if they were made up of multiple strips or tiles of approximately 8
        /// kilobytes each. This operation is done only in-memory; it does not alter the contents
        /// of the file/stream. However, the construction of the "chopped strips" is visible to
        /// the application through the number of strips returned by <see cref="NumberOfStrips"/>
        /// or the number of tiles returned by <see cref="NumberOfTiles"/>.</para>
        /// </remarks>
        public bool ReadDirectory()
        {
            const string module = "ReadDirectory";

            m_diroff = m_nextdiroff;
            if (m_diroff == 0)
            {
                // no more directories
                return false;
            }

            // Check whether we have the last offset or bad offset (IFD looping).
            if (!checkDirOffset(m_nextdiroff))
                return false;

            // Cleanup any previous compression state.
            m_currentCodec.Cleanup();
            m_curdir++;
            TiffDirEntry[] dir;
            short dircount = fetchDirectory(m_nextdiroff, out dir, out m_nextdiroff);
            if (dircount == 0)
            {
                ErrorExt(this, m_clientdata, module, "{0}: Failed to read directory at offset {1}", m_name, m_nextdiroff);
                return false;
            }

            // reset before new dir
            m_flags &= ~TiffFlags.BeenWriting;

            // 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.

            // free any old stuff and reinit
            FreeDirectory();
            setupDefaultDirectory();

            // 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.
            SetField(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.

            for (int i = 0; i < dircount; i++)
            {
                TiffDirEntry dp = dir[i];
                if ((m_flags & TiffFlags.Swab) == TiffFlags.Swab)
                {
                    short temp = (short)dp.tdir_tag;
                    SwabShort(ref temp);
                    dp.tdir_tag = (TiffTag)(ushort)temp;

                    temp = (short)dp.tdir_type;
                    SwabShort(ref temp);
                    dp.tdir_type = (TiffType)temp;

                    SwabLong(ref dp.tdir_count);
                    SwabUInt(ref dp.tdir_offset);
                }

                if (dp.tdir_tag == TiffTag.SamplesPerPixel)
                {
                    if (!fetchNormalTag(dir[i]))
                        return false;

                    dp.tdir_tag = TiffTag.Ignore;
                }
            }

            // First real pass over the directory.
            int fix = 0;
            bool diroutoforderwarning = false;
            bool haveunknowntags = false;
            for (int i = 0; i < dircount; i++)
            {
                if (dir[i].tdir_tag == TiffTag.Ignore)
                    continue;

                if (fix >= m_nfields)
                    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 (dir[i].tdir_tag < m_fieldinfo[fix].Tag)
                {
                    if (!diroutoforderwarning)
                    {
                        WarningExt(this, m_clientdata, module,
                            "{0}: invalid TIFF directory; tags are not sorted in ascending order", m_name);
                        diroutoforderwarning = true;
                    }

                    fix = 0; // O(n^2)
                }

                while (fix < m_nfields && m_fieldinfo[fix].Tag < dir[i].tdir_tag)
                    fix++;

                if (fix >= m_nfields || m_fieldinfo[fix].Tag != dir[i].tdir_tag)
                {
                    // Unknown tag ... we'll deal with it below
                    haveunknowntags = true;
                    continue;
                }

                // null out old tags that we ignore.
                if (m_fieldinfo[fix].Bit == FieldBit.Ignore)
                {
                    dir[i].tdir_tag = TiffTag.Ignore;
                    continue;
                }

                // Check data type.
                TiffFieldInfo fip = m_fieldinfo[fix];
                while (dir[i].tdir_type != fip.Type && fix < m_nfields)
                {
                    if (fip.Type == TiffType.Any)
                    {
                        // wildcard
                        break;
                    }

                    fip = m_fieldinfo[++fix];
                    if (fix >= m_nfields || fip.Tag != dir[i].tdir_tag)
                    {
                        WarningExt(this, m_clientdata, module,
                            "{0}: wrong data type {1} for \"{2}\"; tag ignored",
                            m_name, dir[i].tdir_type, m_fieldinfo[fix - 1].Name);

                        dir[i].tdir_tag = TiffTag.Ignore;
                        continue;
                    }
                }

                // Check count if known in advance.
                if (fip.ReadCount != TiffFieldInfo.Variable &&
                    fip.ReadCount != TiffFieldInfo.Variable2)
                {
                    int expected = fip.ReadCount;
                    if (fip.ReadCount == TiffFieldInfo.Spp)
                        expected = m_dir.td_samplesperpixel;

                    if (!checkDirCount(dir[i], expected))
                    {
                        dir[i].tdir_tag = TiffTag.Ignore;
                        continue;
                    }
                }

                switch (dir[i].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 (dir[i].tdir_count == 1)
                        {
                            int v = extractData(dir[i]);
                            if (!SetField(dir[i].tdir_tag, v))
                                return false;

                            break;
                            // XXX: workaround for broken TIFFs
                        }
                        else if (dir[i].tdir_type == TiffType.Long)
                        {
                            int v;
                            if (!fetchPerSampleLongs(dir[i], out v) || !SetField(dir[i].tdir_tag, v))
                                return false;
                        }
                        else
                        {
                            short iv;
                            if (!fetchPerSampleShorts(dir[i], out iv) || !SetField(dir[i].tdir_tag, iv))
                                return false;
                        }
                        dir[i].tdir_tag = TiffTag.Ignore;
                        break;
                    case TiffTag.StripOffsets:
                    case TiffTag.StripByteCounts:
                    case TiffTag.TileOffsets:
                    case TiffTag.TileByteCounts:
                        setFieldBit(fip.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 (!fetchNormalTag(dir[i]))
                            return false;
                        dir[i].tdir_tag = TiffTag.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;
                for (int i = 0; i < dircount; i++)
                {
                    if (dir[i].tdir_tag == TiffTag.Ignore)
                        continue;

                    if (fix >= m_nfields || dir[i].tdir_tag < m_fieldinfo[fix].Tag)
                    {
                        // O(n^2)
                        fix = 0;
                    }

                    while (fix < m_nfields && m_fieldinfo[fix].Tag < dir[i].tdir_tag)
                        fix++;

                    if (fix >= m_nfields || m_fieldinfo[fix].Tag != dir[i].tdir_tag)
                    {
                        Tiff.WarningExt(this, m_clientdata, module,
                            "{0}: unknown field with tag {1} (0x{2:x}) encountered",
                            m_name, (ushort)dir[i].tdir_tag, (ushort)dir[i].tdir_tag);

                        TiffFieldInfo[] arr = new TiffFieldInfo[1];
                        arr[0] = createAnonFieldInfo(dir[i].tdir_tag, dir[i].tdir_type);
                        MergeFieldInfo(arr, 1);

                        fix = 0;
                        while (fix < m_nfields && m_fieldinfo[fix].Tag < dir[i].tdir_tag)
                            fix++;
                    }

                    // Check data type.
                    TiffFieldInfo fip = m_fieldinfo[fix];
                    while (dir[i].tdir_type != fip.Type && fix < m_nfields)
                    {
                        if (fip.Type == TiffType.Any)
                        {
                            // wildcard
                            break;
                        }

                        fip = m_fieldinfo[++fix];
                        if (fix >= m_nfields || fip.Tag != dir[i].tdir_tag)
                        {
                            Tiff.WarningExt(this, m_clientdata, module,
                                "{0}: wrong data type {1} for \"{2}\"; tag ignored",
                                m_name, dir[i].tdir_type, m_fieldinfo[fix - 1].Name);

                            dir[i].tdir_tag = TiffTag.Ignore;
                            break;
                        }
                    }
                }
            }

            // XXX: OJPEG hack.
            // If a) compression is OJPEG, b) planarconfig tag says it's separate, c) strip
            // offsets/bytecounts tag are both present and d) both contain exactly one value, then
            // we consistently find that the buggy implementation of the buggy compression scheme
            // matches contig planarconfig best. So we 'fix-up' the tag here
            if ((m_dir.td_compression == Compression.OJPEG) && (m_dir.td_planarconfig == PlanarConfig.Separate))
            {
                int dpIndex = readDirectoryFind(dir, dircount, TiffTag.StripOffsets);
                if (dpIndex != -1 && dir[dpIndex].tdir_count == 1)
                {
                    dpIndex = readDirectoryFind(dir, dircount, TiffTag.StripByteCounts);
                    if (dpIndex != -1 && dir[dpIndex].tdir_count == 1)
                    {
                        m_dir.td_planarconfig = PlanarConfig.Contig;
                        WarningExt(this, m_clientdata, "ReadDirectory",
                            "Planarconfig tag value assumed incorrect, assuming data is contig instead of chunky");
                    }
                }
            }

            // Allocate directory structure and setup defaults.
            if (!fieldSet(FieldBit.ImageDimensions))
            {
                missingRequired("ImageLength");
                return false;
            }

            // Setup appropriate structures (by strip or by tile)
            if (!fieldSet(FieldBit.TileDimensions))
            {
                m_dir.td_nstrips = NumberOfStrips();
                m_dir.td_tilewidth = m_dir.td_imagewidth;
                m_dir.td_tilelength = m_dir.td_rowsperstrip;
                m_dir.td_tiledepth = m_dir.td_imagedepth;
                m_flags &= ~TiffFlags.IsTiled;
            }
            else
            {
                m_dir.td_nstrips = NumberOfTiles();
                m_flags |= TiffFlags.IsTiled;
            }

            if (m_dir.td_nstrips == 0)
            {
                ErrorExt(this, m_clientdata, module,
                    "{0}: cannot handle zero number of {1}", m_name, IsTiled() ? "tiles" : "strips");
                return false;
            }

            m_dir.td_stripsperimage = m_dir.td_nstrips;
            if (m_dir.td_planarconfig == PlanarConfig.Separate)
                m_dir.td_stripsperimage /= m_dir.td_samplesperpixel;

            if (!fieldSet(FieldBit.StripOffsets))
            {
                if ((m_dir.td_compression == Compression.OJPEG) && !IsTiled() && (m_dir.td_nstrips == 1))
                {
                    // XXX: OJPEG hack.
                    // If a) compression is OJPEG, b) it's not a tiled TIFF, and c) the number of
                    // strips is 1, then we tolerate the absence of stripoffsets tag, because,
                    // presumably, all required data is in the JpegInterchangeFormat stream.
                    setFieldBit(FieldBit.StripOffsets);
                }
                else
                {
                    missingRequired(IsTiled() ? "TileOffsets" : "StripOffsets");
                    return false;
                }
            }

            // Second pass: extract other information.
            for (int i = 0; i < dircount; i++)
            {
                if (dir[i].tdir_tag == TiffTag.Ignore)
                    continue;

                switch (dir[i].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 (dir[i].tdir_count == 1)
                        {
                            int v = extractData(dir[i]);
                            if (!SetField(dir[i].tdir_tag, v))
                                return false;
                            // XXX: workaround for broken TIFFs
                        }
                        else if (dir[i].tdir_tag == TiffTag.BitsPerSample && dir[i].tdir_type == TiffType.Long)
                        {
                            int v;
                            if (!fetchPerSampleLongs(dir[i], out v) || !SetField(dir[i].tdir_tag, v))
                                return false;
                        }
                        else
                        {
                            short iv;
                            if (!fetchPerSampleShorts(dir[i], out iv) || !SetField(dir[i].tdir_tag, iv))
                                return false;
                        }
                        break;
                    case TiffTag.SMinSampleValue:
                    case TiffTag.SMaxSampleValue:
                        double dv;
                        if (!fetchPerSampleAnys(dir[i], out dv) || !SetField(dir[i].tdir_tag, dv))
                            return false;
                        break;
                    case TiffTag.StripOffsets:
                    case TiffTag.TileOffsets:
                        if (!fetchStripThing(dir[i], m_dir.td_nstrips, ref m_dir.td_stripoffset))
                            return false;
                        break;
                    case TiffTag.StripByteCounts:
                    case TiffTag.TileByteCounts:
                        if (!fetchStripThing(dir[i], m_dir.td_nstrips, ref m_dir.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.
                            int v = 1 << m_dir.td_bitspersample;
                            if (dir[i].tdir_tag == TiffTag.Colormap || dir[i].tdir_count != v)
                            {
                                if (!checkDirCount(dir[i], 3 * v))
                                    break;
                            }

                            byte[] cp = new byte[dir[i].tdir_count * sizeof(short)];
                            if (fetchData(dir[i], cp) != 0)
                            {
                                int c = 1 << m_dir.td_bitspersample;
                                if (dir[i].tdir_count == c)
                                {
                                    // This deals with there being only one array to apply to all samples.
                                    short[] u = ByteArrayToShorts(cp, 0, dir[i].tdir_count * sizeof(short));
                                    SetField(dir[i].tdir_tag, u, u, u);
                                }
                                else
                                {
                                    v *= sizeof(short);
                                    short[] u0 = ByteArrayToShorts(cp, 0, v);
                                    short[] u1 = ByteArrayToShorts(cp, v, v);
                                    short[] u2 = ByteArrayToShorts(cp, 2 * v, v);
                                    SetField(dir[i].tdir_tag, u0, u1, u2);
                                }
                            }
                            break;
                        }
                    case TiffTag.PageNumber:
                    case TiffTag.HalfToneHints:
                    case TiffTag.YCBCRSUBSAMPLING:
                    case TiffTag.DotRange:
                        fetchShortPair(dir[i]);
                        break;
                    case TiffTag.REFERENCEBLACKWHITE:
                        fetchRefBlackWhite(dir[i]);
                        break;
                    // BEGIN REV 4.0 COMPATIBILITY
                    case TiffTag.OSubFileType:
                        FileType ft = 0;
                        switch ((SubFileType)extractData(dir[i]))
                        {
                            case SubFileType.ReducedSizeImage:
                                ft = FileType.ReducedResImage;
                                break;
                            case SubFileType.Page:
                                ft = FileType.Page;
                                break;
                        }

                        if (ft != 0)
                            SetField(TiffTag.SubFileType, ft);

                        break;
                    // END REV 4.0 COMPATIBILITY
                    default:
                        fetchNormalTag(dir[i]);
                        break;
                }
            }

            // OJPEG hack:
            // - If a) compression is OJPEG, and b) photometric tag is missing, then we
            // consistently find that photometric should be YCbCr
            // - If a) compression is OJPEG, and b) photometric tag says it's RGB, then we
            // consistently find that the buggy implementation of the buggy compression scheme
            // matches photometric YCbCr instead.
            // - If a) compression is OJPEG, and b) bitspersample tag is missing, then we
            // consistently find bitspersample should be 8.
            // - If a) compression is OJPEG, b) samplesperpixel tag is missing, and c) photometric
            // is RGB or YCbCr, then we consistently find samplesperpixel should be 3
            // - If a) compression is OJPEG, b) samplesperpixel tag is missing, and c) photometric
            // is MinIsWhite or MinIsBlack, then we consistently find samplesperpixel should be 3
            if (m_dir.td_compression == Compression.OJPEG)
            {
                if (!fieldSet(FieldBit.Photometric))
                {
                    WarningExt(this, m_clientdata,
                        "ReadDirectory", "Photometric tag is missing, assuming data is YCbCr");

                    if (!SetField(TiffTag.Photometric, Photometric.YCBCR))
                        return false;
                }
                else if (m_dir.td_photometric == Photometric.RGB)
                {
                    m_dir.td_photometric = Photometric.YCBCR;
                    WarningExt(this, m_clientdata, "ReadDirectory",
                        "Photometric tag value assumed incorrect, assuming data is YCbCr instead of RGB");
                }

                if (!fieldSet(FieldBit.BitsPerSample))
                {
                    WarningExt(this, m_clientdata, "ReadDirectory",
                        "BitsPerSample tag is missing, assuming 8 bits per sample");

                    if (!SetField(TiffTag.BitsPerSample, 8))
                        return false;
                }

                if (!fieldSet(FieldBit.SamplesPerPixel))
                {
                    if ((m_dir.td_photometric == Photometric.RGB) ||
                        (m_dir.td_photometric == Photometric.YCBCR))
                    {
                        WarningExt(this, m_clientdata, "ReadDirectory",
                            "SamplesPerPixel tag is missing, assuming correct SamplesPerPixel value is 3");

                        if (!SetField(TiffTag.SamplesPerPixel, 3))
                            return false;
                    }
                    else if ((m_dir.td_photometric == Photometric.MinIsWhite) ||
                        (m_dir.td_photometric == Photometric.MinIsBlack))
                    {
                        WarningExt(this, m_clientdata, "ReadDirectory",
                            "SamplesPerPixel tag is missing, assuming correct SamplesPerPixel value is 1");
                        if (!SetField(TiffTag.SamplesPerPixel, 1))
                            return false;
                    }
                }
            }

            // Verify Palette image has a Colormap.
            if (m_dir.td_photometric == Photometric.Palette && !fieldSet(FieldBit.ColorMap))
            {
                missingRequired("Colormap");
                return false;
            }

            // OJPEG hack:
            // We do no further messing with strip/tile offsets/bytecounts in OJPEG TIFFs
            if (m_dir.td_compression != Compression.OJPEG)
            {
                // Attempt to deal with a missing StripByteCounts tag.
                if (!fieldSet(FieldBit.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 ((m_dir.td_planarconfig == PlanarConfig.Contig && m_dir.td_nstrips > 1) ||
                        (m_dir.td_planarconfig == PlanarConfig.Separate && m_dir.td_nstrips != m_dir.td_samplesperpixel))
                    {
                        missingRequired("StripByteCounts");
                        return false;
                    }

                    WarningExt(this, m_clientdata, module,
                        "{0}: TIFF directory is missing required \"{1}\" field, calculating from imagelength",
                        m_name, FieldWithTag(TiffTag.StripByteCounts).Name);

                    if (!estimateStripByteCounts(dir, dircount))
                        return false;
                }
                else if (m_dir.td_nstrips == 1 && m_dir.td_stripoffset[0] != 0 && byteCountLooksBad(m_dir))
                {
                    // 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.
                    WarningExt(this, m_clientdata, module,
                        "{0}: Bogus \"{1}\" field, ignoring and calculating from imagelength",
                        m_name, FieldWithTag(TiffTag.StripByteCounts).Name);

                    if (!estimateStripByteCounts(dir, dircount))
                        return false;
                }
                else if (m_dir.td_planarconfig == PlanarConfig.Contig && m_dir.td_nstrips > 2 &&
                    m_dir.td_compression == Compression.None &&
                    m_dir.td_stripbytecount[0] != m_dir.td_stripbytecount[1])
                {
                    // XXX: Some vendors fill StripByteCount array with absolutely wrong values
                    // (it can be equal to StripOffset array, for example). Catch this case here.
                    WarningExt(this, m_clientdata, module,
                        "{0}: Wrong \"{1}\" field, ignoring and calculating from imagelength",
                        m_name, FieldWithTag(TiffTag.StripByteCounts).Name);

                    if (!estimateStripByteCounts(dir, dircount))
                        return false;
                }
            }

            dir = null;

            if (!fieldSet(FieldBit.MaxSampleValue))
                m_dir.td_maxsamplevalue = (short)((1 << m_dir.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 appendToStrip() function.
            if (m_dir.td_nstrips > 1)
            {
                m_dir.td_stripbytecountsorted = true;
                for (int strip = 1; strip < m_dir.td_nstrips; strip++)
                {
                    if (m_dir.td_stripoffset[strip - 1] > m_dir.td_stripoffset[strip])
                    {
                        m_dir.td_stripbytecountsorted = false;
                        break;
                    }
                }
            }

            if (!fieldSet(FieldBit.Compression))
                SetField(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 (m_dir.td_nstrips == 1 && m_dir.td_compression == Compression.None &&
                (m_flags & TiffFlags.StripChop) == TiffFlags.StripChop &&
                (m_flags & TiffFlags.IsTiled) != TiffFlags.IsTiled)
            {
                chopUpSingleUncompressedStrip();
            }

            // Reinitialize i/o since we are starting on a new directory.
            m_row = -1;
            m_curstrip = -1;
            m_col = -1;
            m_curtile = -1;
            m_tilesize = -1;

            m_scanlinesize = ScanlineSize();
            if (m_scanlinesize == 0)
            {
                ErrorExt(this, m_clientdata, module, "{0}: cannot handle zero scanline size", m_name);
                return false;
            }

            if (IsTiled())
            {
                m_tilesize = TileSize();
                if (m_tilesize == 0)
                {
                    ErrorExt(this, m_clientdata, module, "{0}: cannot handle zero tile size", m_name);
                    return false;
                }
            }
            else
            {
                if (StripSize() == 0)
                {
                    ErrorExt(this, m_clientdata, module, "{0}: cannot handle zero strip size", m_name);
                    return false;
                }
            }

            return true;
        }
Ejemplo n.º 3
0
        /// <summary>
        /// Reads a custom directory from the arbitrary offset within file/stream.
        /// </summary>
        /// <param name="offset">The directory offset.</param>
        /// <param name="info">The array of <see cref="TiffFieldInfo"/> objects to merge to
        /// existing field information.</param>
        /// <param name="count">The number of items to use from
        /// the <paramref name="info"/> array.</param>
        /// <returns><c>true</c> if a custom directory was read successfully;
        /// otherwise, <c>false</c></returns>
        public bool ReadCustomDirectory(long offset, TiffFieldInfo[] info, int count)
        {
            const string module = "ReadCustomDirectory";

            setupFieldInfo(info, count);

            uint dummyNextDirOff;
            TiffDirEntry[] dir;
            short dircount = fetchDirectory((uint)offset, out dir, out dummyNextDirOff);
            if (dircount == 0)
            {
                ErrorExt(this, m_clientdata, module,
                    "{0}: Failed to read custom directory at offset {1}", m_name, offset);
                return false;
            }

            FreeDirectory();
            m_dir = new TiffDirectory();

            int fix = 0;
            for (short i = 0; i < dircount; i++)
            {
                if ((m_flags & TiffFlags.Swab) == TiffFlags.Swab)
                {
                    short temp = (short)dir[i].tdir_tag;
                    SwabShort(ref temp);
                    dir[i].tdir_tag = (TiffTag)(ushort)temp;

                    temp = (short)dir[i].tdir_type;
                    SwabShort(ref temp);
                    dir[i].tdir_type = (TiffType)temp;

                    SwabLong(ref dir[i].tdir_count);
                    SwabUInt(ref dir[i].tdir_offset);
                }

                if (fix >= m_nfields || dir[i].tdir_tag == TiffTag.Ignore)
                    continue;

                while (fix < m_nfields && m_fieldinfo[fix].Tag < dir[i].tdir_tag)
                    fix++;

                if (fix >= m_nfields || m_fieldinfo[fix].Tag != dir[i].tdir_tag)
                {
                    WarningExt(this, m_clientdata, module,
                        "{0}: unknown field with tag {1} (0x{2:x}) encountered",
                        m_name, (ushort)dir[i].tdir_tag, (ushort)dir[i].tdir_tag);

                    TiffFieldInfo[] arr = new TiffFieldInfo[1];
                    arr[0] = createAnonFieldInfo(dir[i].tdir_tag, dir[i].tdir_type);
                    MergeFieldInfo(arr, 1);

                    fix = 0;
                    while (fix < m_nfields && m_fieldinfo[fix].Tag < dir[i].tdir_tag)
                        fix++;
                }

                // null out old tags that we ignore.
                if (m_fieldinfo[fix].Bit == FieldBit.Ignore)
                {
                    dir[i].tdir_tag = TiffTag.Ignore;
                    continue;
                }

                // Check data type.
                TiffFieldInfo fip = m_fieldinfo[fix];
                while (dir[i].tdir_type != fip.Type && fix < m_nfields)
                {
                    if (fip.Type == TiffType.Any)
                    {
                        // wildcard
                        break;
                    }

                    fip = m_fieldinfo[++fix];
                    if (fix >= m_nfields || fip.Tag != dir[i].tdir_tag)
                    {
                        WarningExt(this, m_clientdata, module,
                            "{0}: wrong data type {1} for \"{2}\"; tag ignored",
                            m_name, dir[i].tdir_type, m_fieldinfo[fix - 1].Name);

                        dir[i].tdir_tag = TiffTag.Ignore;
                        continue;
                    }
                }

                // Check count if known in advance.
                if (fip.ReadCount != TiffFieldInfo.Variable &&
                    fip.ReadCount != TiffFieldInfo.Variable2)
                {
                    int expected = fip.ReadCount;
                    if (fip.ReadCount == TiffFieldInfo.Spp)
                        expected = m_dir.td_samplesperpixel;

                    if (!checkDirCount(dir[i], expected))
                    {
                        dir[i].tdir_tag = TiffTag.Ignore;
                        continue;
                    }
                }

                // EXIF tags which need to be specifically processed.
                switch (dir[i].tdir_tag)
                {
                    case TiffTag.EXIF_SUBJECTDISTANCE:
                        fetchSubjectDistance(dir[i]);
                        break;
                    default:
                        fetchNormalTag(dir[i]);
                        break;
                }
            }

            return true;
        }
Ejemplo n.º 4
0
        /// <summary>
        /// Merges given field information to existing one.
        /// </summary>
        /// <param name="info">The array of <see cref="TiffFieldInfo"/> objects.</param>
        /// <param name="count">The number of items to use from the <paramref name="info"/> array.</param>
        public void MergeFieldInfo(TiffFieldInfo[] info, int count)
        {
            m_foundfield = null;

            if (m_nfields > 0)
                m_fieldinfo = Realloc(m_fieldinfo, m_nfields, m_nfields + count);
            else
                m_fieldinfo = new TiffFieldInfo[count];

            for (int i = 0; i < count; i++)
            {
                TiffFieldInfo fip = FindFieldInfo(info[i].Tag, info[i].Type);

                // only add definitions that aren't already present
                if (fip == null)
                {
                    m_fieldinfo[m_nfields] = info[i];
                    m_nfields++;
                }
            }

            // Sort the field info by tag number
            IComparer myComparer = new TagCompare();
            Array.Sort(m_fieldinfo, 0, m_nfields, myComparer);
        }
Ejemplo n.º 5
0
        /// <summary>
        /// Retrieves field information for the tag with specified name.
        /// </summary>
        /// <param name="name">The name of the tag to retrieve field information for.</param>
        /// <param name="type">The tiff data type to use us additional filter.</param>
        /// <returns>The field information for specified tag with specified type or <c>null</c> if
        /// the field information wasn't found.</returns>
        public TiffFieldInfo FindFieldInfoByName(string name, TiffType type)
        {
            if (m_foundfield != null && m_foundfield.Name == name &&
                (type == TiffType.Any || type == m_foundfield.Type))
            {
                return m_foundfield;
            }

            // If we are invoked with no field information, then just return.
            if (m_fieldinfo == null)
                return null;

            m_foundfield = null;

            foreach (TiffFieldInfo info in m_fieldinfo)
            {
                if (info != null && info.Name == name &&
                    (type == TiffType.Any || type == info.Type))
                {
                    m_foundfield = info;
                    break;
                }
            }

            return m_foundfield;
        }
Ejemplo n.º 6
0
        /*
        * Setup a default directory structure.
        */
        private void setupDefaultDirectory()
        {
            int tiffFieldInfoCount;
            TiffFieldInfo[] tiffFieldInfo = getFieldInfo(out tiffFieldInfoCount);
            setupFieldInfo(tiffFieldInfo, tiffFieldInfoCount);

            m_dir = new TiffDirectory();
            m_postDecodeMethod = PostDecodeMethodType.pdmNone;
            m_foundfield = null;

            m_tagmethods = m_defaultTagMethods;

            /*
             *  Give client code a chance to install their own
             *  tag extensions & methods, prior to compression overloads.
             */
            if (m_extender != null)
                m_extender(this);

            SetField(TiffTag.Compression, Compression.None);

            /*
             * NB: The directory is marked dirty as a result of setting
             * up the default compression scheme.  However, this really
             * isn't correct -- we want DirtyDirect to be set only
             * if the user does something.  We could just do the setup
             * by hand, but it seems better to use the normal mechanism
             * (i.e. SetField).
             */
            m_flags &= ~TiffFlags.DirtyDirect;

            /*
             * we clear the IsTiled flag when setting up a new directory.
             * Should we also be clearing stuff like InSubIFD?
             */
            m_flags &= ~TiffFlags.IsTiled;

            /*
             * Clear other directory-specific fields.
             */
            m_tilesize = -1;
            m_scanlinesize = -1;
        }
Ejemplo n.º 7
0
        private static TiffFieldInfo createAnonFieldInfo(TiffTag tag, TiffType field_type)
        {
            TiffFieldInfo fld = new TiffFieldInfo(tag, TiffFieldInfo.Variable2,
                TiffFieldInfo.Variable2, field_type, FieldBit.Custom, true, true, null);

            // note that this name is a special sign to Close() and
            // setupFieldInfo() to free the field
            fld.Name = string.Format(CultureInfo.InvariantCulture, "Tag {0}", tag);
            return fld;
        }
Ejemplo n.º 8
0
 private void setupFieldInfo(TiffFieldInfo[] info, int n)
 {
     m_nfields = 0;
     MergeFieldInfo(info, n);
 }
Ejemplo n.º 9
0
        /// <summary>
        /// Writes tags that are not special cased.
        /// </summary>
        private bool writeNormalTag(ref TiffDirEntry dir, TiffFieldInfo fip)
        {
            short wc = fip.WriteCount;
            dir.tdir_tag = fip.Tag;
            dir.tdir_type = fip.Type;
            dir.tdir_count = wc;

            switch (fip.Type)
            {
                case TiffType.Short:
                case TiffType.SShort:
                    if (fip.PassCount)
                    {
                        short[] wp;
                        int wc2;
                        if (wc == TiffFieldInfo.Variable2)
                        {
                            FieldValue[] result = GetField(fip.Tag);
                            wc2 = result[0].ToInt();
                            wp = result[1].ToShortArray();

                            dir.tdir_count = wc2;
                        }
                        else
                        {
                            // Assume TiffFieldInfo.Variable
                            FieldValue[] result = GetField(fip.Tag);
                            wc = result[0].ToShort();
                            wp = result[1].ToShortArray();
                            dir.tdir_count = wc;
                        }

                        if (!writeShortArray(ref dir, wp))
                            return false;
                    }
                    else
                    {
                        if (wc == 1)
                        {
                            FieldValue[] result = GetField(fip.Tag);
                            short sv = result[0].ToShort();
                            dir.tdir_offset = insertData(dir.tdir_type, sv);
                        }
                        else
                        {
                            FieldValue[] result = GetField(fip.Tag);
                            short[] wp = result[0].ToShortArray();
                            if (!writeShortArray(ref dir, wp))
                                return false;
                        }
                    }
                    break;
                case TiffType.Long:
                case TiffType.SLong:
                case TiffType.IFD:
                    if (fip.PassCount)
                    {
                        int[] lp;
                        int wc2;
                        if (wc == TiffFieldInfo.Variable2)
                        {
                            FieldValue[] result = GetField(fip.Tag);
                            wc2 = result[0].ToInt();
                            lp = result[1].ToIntArray();
                            dir.tdir_count = wc2;
                        }
                        else
                        {
                            // Assume TiffFieldInfo.Variable
                            FieldValue[] result = GetField(fip.Tag);
                            wc = result[0].ToShort();
                            lp = result[1].ToIntArray();
                            dir.tdir_count = wc;
                        }

                        if (!writeLongArray(ref dir, lp))
                            return false;
                    }
                    else
                    {
                        if (wc == 1)
                        {
                            // XXX handle Long->Short conversion
                            FieldValue[] result = GetField(fip.Tag);
                            dir.tdir_offset = result[0].ToUInt();
                        }
                        else
                        {
                            int[] lp;
                            FieldValue[] result = GetField(fip.Tag);
                            lp = result[0].ToIntArray();
                            if (!writeLongArray(ref dir, lp))
                                return false;
                        }
                    }
                    break;
                case TiffType.Rational:
                case TiffType.SRational:
                    if (fip.PassCount)
                    {
                        float[] fp;
                        int wc2;
                        if (wc == TiffFieldInfo.Variable2)
                        {
                            FieldValue[] result = GetField(fip.Tag);
                            wc2 = result[0].ToInt();
                            fp = result[1].ToFloatArray();
                            dir.tdir_count = wc2;
                        }
                        else
                        {
                            // Assume TiffFieldInfo.Variable
                            FieldValue[] result = GetField(fip.Tag);
                            wc = result[0].ToShort();
                            fp = result[1].ToFloatArray();
                            dir.tdir_count = wc;
                        }

                        if (!writeRationalArray(ref dir, fp))
                            return false;
                    }
                    else
                    {
                        if (wc == 1)
                        {
                            float[] fv = new float[1];
                            FieldValue[] result = GetField(fip.Tag);
                            fv[0] = result[0].ToFloat();
                            if (!writeRationalArray(ref dir, fv))
                                return false;
                        }
                        else
                        {
                            FieldValue[] result = GetField(fip.Tag);
                            float[] fp = result[0].ToFloatArray();
                            if (!writeRationalArray(ref dir, fp))
                                return false;
                        }
                    }
                    break;
                case TiffType.Float:
                    if (fip.PassCount)
                    {
                        float[] fp;
                        int wc2;
                        if (wc == TiffFieldInfo.Variable2)
                        {
                            FieldValue[] result = GetField(fip.Tag);
                            wc2 = result[0].ToInt();
                            fp = result[1].ToFloatArray();
                            dir.tdir_count = wc2;
                        }
                        else
                        {
                            // Assume TiffFieldInfo.Variable
                            FieldValue[] result = GetField(fip.Tag);
                            wc = result[0].ToShort();
                            fp = result[1].ToFloatArray();
                            dir.tdir_count = wc;
                        }

                        if (!writeFloatArray(ref dir, fp))
                            return false;
                    }
                    else
                    {
                        if (wc == 1)
                        {
                            float[] fv = new float[1];
                            FieldValue[] result = GetField(fip.Tag);
                            fv[0] = result[0].ToFloat();
                            if (!writeFloatArray(ref dir, fv))
                                return false;
                        }
                        else
                        {
                            FieldValue[] result = GetField(fip.Tag);
                            float[] fp = result[0].ToFloatArray();
                            if (!writeFloatArray(ref dir, fp))
                                return false;
                        }
                    }
                    break;
                case TiffType.Double:
                    if (fip.PassCount)
                    {
                        double[] dp;
                        int wc2;
                        if (wc == TiffFieldInfo.Variable2)
                        {
                            FieldValue[] result = GetField(fip.Tag);
                            wc2 = result[0].ToInt();
                            dp = result[1].ToDoubleArray();
                            dir.tdir_count = wc2;
                        }
                        else
                        {
                            // Assume TiffFieldInfo.Variable
                            FieldValue[] result = GetField(fip.Tag);
                            wc = result[0].ToShort();
                            dp = result[1].ToDoubleArray();
                            dir.tdir_count = wc;
                        }

                        if (!writeDoubleArray(ref dir, dp))
                            return false;
                    }
                    else
                    {
                        if (wc == 1)
                        {
                            double[] dv = new double[1];
                            FieldValue[] result = GetField(fip.Tag);
                            dv[0] = result[0].ToDouble();
                            if (!writeDoubleArray(ref dir, dv))
                                return false;
                        }
                        else
                        {
                            FieldValue[] result = GetField(fip.Tag);
                            double[] dp = result[0].ToDoubleArray();
                            if (!writeDoubleArray(ref dir, dp))
                                return false;
                        }
                    }
                    break;
                case TiffType.ASCII:
                    {
                        FieldValue[] result = GetField(fip.Tag);

                        string cp;
                        if (fip.PassCount)
                            cp = result[1].ToString();
                        else
                            cp = result[0].ToString();

                        // add zero ('\0') at the end of the byte array
                        byte[] stringBytes = Latin1Encoding.GetBytes(cp);
                        byte[] totalBytes = new byte[stringBytes.Length + 1];
                        Buffer.BlockCopy(stringBytes, 0, totalBytes, 0, stringBytes.Length);

                        dir.tdir_count = totalBytes.Length;
                        if (!writeByteArray(ref dir, totalBytes))
                            return false;
                    }
                    break;

                case TiffType.Byte:
                case TiffType.SByte:
                    if (fip.PassCount)
                    {
                        byte[] cp;
                        int wc2;
                        if (wc == TiffFieldInfo.Variable2)
                        {
                            FieldValue[] result = GetField(fip.Tag);
                            wc2 = result[0].ToInt();
                            cp = result[1].ToByteArray();
                            dir.tdir_count = wc2;
                        }
                        else
                        {
                            // Assume TiffFieldInfo.Variable
                            FieldValue[] result = GetField(fip.Tag);
                            wc = result[0].ToShort();
                            cp = result[1].ToByteArray();
                            dir.tdir_count = wc;
                        }

                        if (!writeByteArray(ref dir, cp))
                            return false;
                    }
                    else
                    {
                        if (wc == 1)
                        {
                            byte[] cv = new byte[1];
                            FieldValue[] result = GetField(fip.Tag);
                            cv[0] = result[0].ToByte();
                            if (!writeByteArray(ref dir, cv))
                                return false;
                        }
                        else
                        {
                            FieldValue[] result = GetField(fip.Tag);
                            byte[] cp = result[0].ToByteArray();
                            if (!writeByteArray(ref dir, cp))
                                return false;
                        }
                    }
                    break;

                case TiffType.Undefined:
                    {
                        byte[] cp;
                        int wc2;
                        if (wc == TiffFieldInfo.Variable)
                        {
                            FieldValue[] result = GetField(fip.Tag);
                            wc = result[0].ToShort();
                            cp = result[1].ToByteArray();
                            dir.tdir_count = wc;
                        }
                        else if (wc == TiffFieldInfo.Variable2)
                        {
                            FieldValue[] result = GetField(fip.Tag);
                            wc2 = result[0].ToInt();
                            cp = result[1].ToByteArray();
                            dir.tdir_count = wc2;
                        }
                        else
                        {
                            FieldValue[] result = GetField(fip.Tag);
                            cp = result[0].ToByteArray();
                        }

                        if (!writeByteArray(ref dir, cp))
                            return false;
                    }
                    break;

                case TiffType.NoType:
                    break;
            }

            return true;
        }
Ejemplo n.º 10
0
        internal static TiffFieldInfo[] Realloc(TiffFieldInfo[] buffer, int elementCount, int newElementCount)
        {
            TiffFieldInfo[] newBuffer = new TiffFieldInfo[newElementCount];

            if (buffer != null)
            {
                int copyLength = Math.Min(elementCount, newElementCount);
                Array.Copy(buffer, newBuffer, copyLength);
            }

            return newBuffer;
        }