Represents a TIFF field information.
TiffFieldInfo describes a field. It provides information about field name, type, number of values etc.
Ejemplo n.º 1
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.º 2
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);
        }
Ejemplo n.º 3
0
        private int fetchFailed(TiffDirEntry dir)
        {
            string format = "Error fetching data for field \"{0}\"";

            TiffFieldInfo fi = FieldWithTag(dir.tdir_tag);

            if (fi.Bit == FieldBit.Custom)
            {
                // According to the TIFF standard, private (custom) tags can be safely
                // ignored when reading an image from a TIFF file.
                WarningExt(this, m_clientdata, m_name, format, fi.Name);
            }
            else
            {
                ErrorExt(this, m_clientdata, m_name, format, fi.Name);
            }

            return(0);
        }
Ejemplo n.º 4
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.º 5
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 = 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 = Realloc(m_fieldinfo, m_nfields, m_nfields + 1);
                    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.º 6
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";

            MergeFieldInfo(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.º 7
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(string, string)"/> or
        /// <see cref="ClientOpen(string, string, object, BitMiracle.LibTiff.Classic.TiffStream)"/> 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];
                bool tagIgnored = false;
                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;
                        tagIgnored = true;
                        break;
                    }
                }

                if (tagIgnored)
                    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 ((OFileType)extractData(dir[i]))
                        {
                            case OFileType.REDUCEDIMAGE:
                                ft = FileType.REDUCEDIMAGE;
                                break;
                            case OFileType.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 = (ushort)((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;
        }
        /// <summary>
        /// Gets the value(s) of a tag in an open TIFF file.
        /// </summary>
        /// <param name="tif">An instance of the <see cref="Tiff"/> class.</param>
        /// <param name="tag">The tag.</param>
        /// <returns>The value(s) of a tag in an open TIFF file/stream as array of
        /// <see cref="FieldValue"/> objects or <c>null</c> if there is no such tag set.</returns>
        /// <seealso cref="Tiff.GetField"/>
        public virtual FieldValue[] GetField(Tiff tif, TiffTag tag)
        {
            TiffDirectory td = tif.m_dir;

            FieldValue[] result = null;

            switch (tag)
            {
            case TiffTag.SUBFILETYPE:
                result = new FieldValue[1];
                result[0].Set(td.td_subfiletype);
                break;

            case TiffTag.IMAGEWIDTH:
                result = new FieldValue[1];
                result[0].Set(td.td_imagewidth);
                break;

            case TiffTag.IMAGELENGTH:
                result = new FieldValue[1];
                result[0].Set(td.td_imagelength);
                break;

            case TiffTag.BITSPERSAMPLE:
                result = new FieldValue[1];
                result[0].Set(td.td_bitspersample);
                break;

            case TiffTag.COMPRESSION:
                result = new FieldValue[1];
                result[0].Set(td.td_compression);
                break;

            case TiffTag.PHOTOMETRIC:
                result = new FieldValue[1];
                result[0].Set(td.td_photometric);
                break;

            case TiffTag.THRESHHOLDING:
                result = new FieldValue[1];
                result[0].Set(td.td_threshholding);
                break;

            case TiffTag.FILLORDER:
                result = new FieldValue[1];
                result[0].Set(td.td_fillorder);
                break;

            case TiffTag.ORIENTATION:
                result = new FieldValue[1];
                result[0].Set(td.td_orientation);
                break;

            case TiffTag.SAMPLESPERPIXEL:
                result = new FieldValue[1];
                result[0].Set(td.td_samplesperpixel);
                break;

            case TiffTag.ROWSPERSTRIP:
                result = new FieldValue[1];
                result[0].Set(td.td_rowsperstrip);
                break;

            case TiffTag.MINSAMPLEVALUE:
                result = new FieldValue[1];
                result[0].Set(td.td_minsamplevalue);
                break;

            case TiffTag.MAXSAMPLEVALUE:
                result = new FieldValue[1];
                result[0].Set(td.td_maxsamplevalue);
                break;

            case TiffTag.SMINSAMPLEVALUE:
                result = new FieldValue[1];
                result[0].Set(td.td_sminsamplevalue);
                break;

            case TiffTag.SMAXSAMPLEVALUE:
                result = new FieldValue[1];
                result[0].Set(td.td_smaxsamplevalue);
                break;

            case TiffTag.XRESOLUTION:
                result = new FieldValue[1];
                result[0].Set(td.td_xresolution);
                break;

            case TiffTag.YRESOLUTION:
                result = new FieldValue[1];
                result[0].Set(td.td_yresolution);
                break;

            case TiffTag.PLANARCONFIG:
                result = new FieldValue[1];
                result[0].Set(td.td_planarconfig);
                break;

            case TiffTag.XPOSITION:
                result = new FieldValue[1];
                result[0].Set(td.td_xposition);
                break;

            case TiffTag.YPOSITION:
                result = new FieldValue[1];
                result[0].Set(td.td_yposition);
                break;

            case TiffTag.RESOLUTIONUNIT:
                result = new FieldValue[1];
                result[0].Set(td.td_resolutionunit);
                break;

            case TiffTag.PAGENUMBER:
                result = new FieldValue[2];
                result[0].Set(td.td_pagenumber[0]);
                result[1].Set(td.td_pagenumber[1]);
                break;

            case TiffTag.HALFTONEHINTS:
                result = new FieldValue[2];
                result[0].Set(td.td_halftonehints[0]);
                result[1].Set(td.td_halftonehints[1]);
                break;

            case TiffTag.COLORMAP:
                result = new FieldValue[3];
                result[0].Set(td.td_colormap[0]);
                result[1].Set(td.td_colormap[1]);
                result[2].Set(td.td_colormap[2]);
                break;

            case TiffTag.STRIPOFFSETS:
            case TiffTag.TILEOFFSETS:
                result = new FieldValue[1];
                result[0].Set(td.td_stripoffset);
                break;

            case TiffTag.STRIPBYTECOUNTS:
            case TiffTag.TILEBYTECOUNTS:
                result = new FieldValue[1];
                result[0].Set(td.td_stripbytecount);
                break;

            case TiffTag.MATTEING:
                result = new FieldValue[1];
                result[0].Set((td.td_extrasamples == 1 && td.td_sampleinfo[0] == ExtraSample.ASSOCALPHA));
                break;

            case TiffTag.EXTRASAMPLES:
                result = new FieldValue[2];
                result[0].Set(td.td_extrasamples);
                result[1].Set(td.td_sampleinfo);
                break;

            case TiffTag.TILEWIDTH:
                result = new FieldValue[1];
                result[0].Set(td.td_tilewidth);
                break;

            case TiffTag.TILELENGTH:
                result = new FieldValue[1];
                result[0].Set(td.td_tilelength);
                break;

            case TiffTag.TILEDEPTH:
                result = new FieldValue[1];
                result[0].Set(td.td_tiledepth);
                break;

            case TiffTag.DATATYPE:
                switch (td.td_sampleformat)
                {
                case SampleFormat.UINT:
                    result = new FieldValue[1];
                    result[0].Set(DATATYPE_UINT);
                    break;

                case SampleFormat.INT:
                    result = new FieldValue[1];
                    result[0].Set(DATATYPE_INT);
                    break;

                case SampleFormat.IEEEFP:
                    result = new FieldValue[1];
                    result[0].Set(DATATYPE_IEEEFP);
                    break;

                case SampleFormat.VOID:
                    result = new FieldValue[1];
                    result[0].Set(DATATYPE_VOID);
                    break;
                }
                break;

            case TiffTag.SAMPLEFORMAT:
                result = new FieldValue[1];
                result[0].Set(td.td_sampleformat);
                break;

            case TiffTag.IMAGEDEPTH:
                result = new FieldValue[1];
                result[0].Set(td.td_imagedepth);
                break;

            case TiffTag.SUBIFD:
                result = new FieldValue[2];
                result[0].Set(td.td_nsubifd);
                result[1].Set(td.td_subifd);
                break;

            case TiffTag.YCBCRPOSITIONING:
                result = new FieldValue[1];
                result[0].Set(td.td_ycbcrpositioning);
                break;

            case TiffTag.YCBCRSUBSAMPLING:
                result = new FieldValue[2];
                result[0].Set(td.td_ycbcrsubsampling[0]);
                result[1].Set(td.td_ycbcrsubsampling[1]);
                break;

            case TiffTag.TRANSFERFUNCTION:
                result = new FieldValue[3];
                result[0].Set(td.td_transferfunction[0]);
                if (td.td_samplesperpixel - td.td_extrasamples > 1)
                {
                    result[1].Set(td.td_transferfunction[1]);
                    result[2].Set(td.td_transferfunction[2]);
                }
                break;

            case TiffTag.REFERENCEBLACKWHITE:
                if (td.td_refblackwhite != null)
                {
                    result = new FieldValue[1];
                    result[0].Set(td.td_refblackwhite);
                }
                break;

            case TiffTag.INKNAMES:
                result = new FieldValue[1];
                result[0].Set(td.td_inknames);
                break;

            default:
                // 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 get a
                // tag that is not valid for the image's codec then we'll
                // arrive here.
                TiffFieldInfo fip = tif.FindFieldInfo(tag, TiffType.ANY);
                if (fip == null || fip.Bit != FieldBit.Custom)
                {
                    Tiff.ErrorExt(tif, tif.m_clientdata, "_TIFFVGetField",
                                  "{0}: Invalid {1}tag \"{2}\" (not supported by codec)",
                                  tif.m_name, Tiff.isPseudoTag(tag) ? "pseudo-" : string.Empty,
                                  fip != null ? fip.Name : "Unknown");
                    result = null;
                    break;
                }

                // Do we have a custom value?
                result = null;
                for (int i = 0; i < td.td_customValueCount; i++)
                {
                    TiffTagValue tv = td.td_customValues[i];
                    if (tv.info.Tag != tag)
                    {
                        continue;
                    }

                    if (fip.PassCount)
                    {
                        result = new FieldValue[2];

                        if (fip.ReadCount == TiffFieldInfo.Variable2)
                        {
                            result[0].Set(tv.count);
                        }
                        else
                        {
                            // Assume TiffFieldInfo.Variable
                            result[0].Set(tv.count);
                        }

                        result[1].Set(tv.value);
                    }
                    else
                    {
                        if ((fip.Type == TiffType.ASCII ||
                             fip.ReadCount == TiffFieldInfo.Variable ||
                             fip.ReadCount == TiffFieldInfo.Variable2 ||
                             fip.ReadCount == TiffFieldInfo.Spp ||
                             tv.count > 1) && fip.Tag != TiffTag.PAGENUMBER &&
                            fip.Tag != TiffTag.HALFTONEHINTS &&
                            fip.Tag != TiffTag.YCBCRSUBSAMPLING &&
                            fip.Tag != TiffTag.DOTRANGE)
                        {
                            result = new FieldValue[1];
                            byte[] value = tv.value;

                            if (fip.Type == TiffType.ASCII &&
                                tv.value.Length > 0 &&
                                tv.value[tv.value.Length - 1] == 0)
                            {
                                // cut unwanted zero at the end
                                value = new byte[Math.Max(tv.value.Length - 1, 0)];
                                Buffer.BlockCopy(tv.value, 0, value, 0, value.Length);
                            }

                            result[0].Set(value);
                        }
                        else
                        {
                            result = new FieldValue[tv.count];
                            byte[] val    = tv.value;
                            int    valPos = 0;
                            for (int j = 0; j < tv.count; j++, valPos += Tiff.dataSize(tv.info.Type))
                            {
                                switch (fip.Type)
                                {
                                case TiffType.BYTE:
                                case TiffType.UNDEFINED:
                                case TiffType.SBYTE:
                                    result[j].Set(val[valPos]);
                                    break;

                                case TiffType.SHORT:
                                case TiffType.SSHORT:
                                    result[j].Set(BitConverter.ToInt16(val, valPos));
                                    break;

                                case TiffType.LONG:
                                case TiffType.IFD:
                                case TiffType.SLONG:
                                    result[j].Set(BitConverter.ToInt32(val, valPos));
                                    break;

                                case TiffType.RATIONAL:
                                case TiffType.SRATIONAL:
                                case TiffType.FLOAT:
                                    result[j].Set(BitConverter.ToSingle(val, valPos));
                                    break;

                                case TiffType.DOUBLE:
                                    result[j].Set(BitConverter.ToDouble(val, valPos));
                                    break;

                                default:
                                    result = null;
                                    break;
                                }
                            }
                        }
                    }
                    break;
                }
                break;
            }

            return(result);
        }
        /// <summary>
        /// Sets the value(s) of a tag in a TIFF file/stream open for writing.
        /// </summary>
        /// <param name="tif">An instance of the <see cref="Tiff"/> class.</param>
        /// <param name="tag">The tag.</param>
        /// <param name="value">The tag value(s).</param>
        /// <returns>
        /// <c>true</c> if tag value(s) were set successfully; otherwise, <c>false</c>.
        /// </returns>
        /// <seealso cref="Tiff.SetField"/>
        public virtual bool SetField(Tiff tif, TiffTag tag, FieldValue[] value)
        {
            const string module = "vsetfield";

            TiffDirectory td     = tif.m_dir;
            bool          status = true;
            int           v32    = 0;
            int           v      = 0;

            bool end        = false;
            bool badvalue   = false;
            bool badvalue32 = false;

            switch (tag)
            {
            case TiffTag.SUBFILETYPE:
                td.td_subfiletype = (FileType)value[0].ToByte();
                break;

            case TiffTag.IMAGEWIDTH:
                td.td_imagewidth = value[0].ToInt();
                break;

            case TiffTag.IMAGELENGTH:
                td.td_imagelength = value[0].ToInt();
                break;

            case TiffTag.BITSPERSAMPLE:
                td.td_bitspersample = value[0].ToShort();
                // 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 behavior in the setup method if it wants to roll the post
                // decoding work in with its normal work.
                if ((tif.m_flags & TiffFlags.SWAB) == TiffFlags.SWAB)
                {
                    switch (td.td_bitspersample)
                    {
                    case 16:
                        tif.m_postDecodeMethod = Tiff.PostDecodeMethodType.pdmSwab16Bit;
                        break;

                    case 24:
                        tif.m_postDecodeMethod = Tiff.PostDecodeMethodType.pdmSwab24Bit;
                        break;

                    case 32:
                        tif.m_postDecodeMethod = Tiff.PostDecodeMethodType.pdmSwab32Bit;
                        break;

                    case 64:
                        tif.m_postDecodeMethod = Tiff.PostDecodeMethodType.pdmSwab64Bit;
                        break;

                    case 128:
                        // two 64's
                        tif.m_postDecodeMethod = Tiff.PostDecodeMethodType.pdmSwab64Bit;
                        break;
                    }
                }
                break;

            case TiffTag.COMPRESSION:
                v = value[0].ToInt() & 0xffff;
                Compression comp = (Compression)v;
                // If we're changing the compression scheme, then notify the previous module
                // so that it can cleanup any state it's setup.
                if (tif.fieldSet(FieldBit.Compression))
                {
                    if (td.td_compression == comp)
                    {
                        break;
                    }

                    tif.m_currentCodec.Cleanup();
                    tif.m_flags &= ~TiffFlags.CODERSETUP;
                }
                // Setup new compression scheme.
                status = tif.setCompressionScheme(comp);
                if (status)
                {
                    td.td_compression = comp;
                }
                else
                {
                    status = false;
                }
                break;

            case TiffTag.PHOTOMETRIC:
                td.td_photometric = (Photometric)value[0].ToInt();
                break;

            case TiffTag.THRESHHOLDING:
                td.td_threshholding = (Threshold)value[0].ToByte();
                break;

            case TiffTag.FILLORDER:
                v = value[0].ToInt();
                FillOrder fo = (FillOrder)v;
                if (fo != FillOrder.LSB2MSB && fo != FillOrder.MSB2LSB)
                {
                    badvalue = true;
                    break;
                }

                td.td_fillorder = fo;
                break;

            case TiffTag.ORIENTATION:
                v = value[0].ToInt();
                Orientation or = (Orientation)v;
                if (or < Orientation.TOPLEFT || Orientation.LEFTBOT < or)
                {
                    badvalue = true;
                    break;
                }
                else
                {
                    td.td_orientation = or;
                }
                break;

            case TiffTag.SAMPLESPERPIXEL:
                // XXX should cross check - e.g. if pallette, then 1
                v = value[0].ToInt();
                if (v == 0)
                {
                    badvalue = true;
                    break;
                }

                td.td_samplesperpixel = (short)v;
                break;

            case TiffTag.ROWSPERSTRIP:
                v32 = value[0].ToInt();
                if (v32 == 0)
                {
                    badvalue32 = true;
                    break;
                }

                td.td_rowsperstrip = v32;
                if (!tif.fieldSet(FieldBit.TileDimensions))
                {
                    td.td_tilelength = v32;
                    td.td_tilewidth  = td.td_imagewidth;
                }
                break;

            case TiffTag.MINSAMPLEVALUE:
                td.td_minsamplevalue = value[0].ToUShort();
                break;

            case TiffTag.MAXSAMPLEVALUE:
                td.td_maxsamplevalue = value[0].ToUShort();
                break;

            case TiffTag.SMINSAMPLEVALUE:
                td.td_sminsamplevalue = value[0].ToDouble();
                break;

            case TiffTag.SMAXSAMPLEVALUE:
                td.td_smaxsamplevalue = value[0].ToDouble();
                break;

            case TiffTag.XRESOLUTION:
                td.td_xresolution = value[0].ToFloat();
                break;

            case TiffTag.YRESOLUTION:
                td.td_yresolution = value[0].ToFloat();
                break;

            case TiffTag.PLANARCONFIG:
                v = value[0].ToInt();
                PlanarConfig pc = (PlanarConfig)v;
                if (pc != PlanarConfig.CONTIG && pc != PlanarConfig.SEPARATE)
                {
                    badvalue = true;
                    break;
                }
                td.td_planarconfig = pc;
                break;

            case TiffTag.XPOSITION:
                td.td_xposition = value[0].ToFloat();
                break;

            case TiffTag.YPOSITION:
                td.td_yposition = value[0].ToFloat();
                break;

            case TiffTag.RESOLUTIONUNIT:
                v = value[0].ToInt();
                ResUnit ru = (ResUnit)v;
                if (ru < ResUnit.NONE || ResUnit.CENTIMETER < ru)
                {
                    badvalue = true;
                    break;
                }

                td.td_resolutionunit = ru;
                break;

            case TiffTag.PAGENUMBER:
                td.td_pagenumber[0] = value[0].ToShort();
                td.td_pagenumber[1] = value[1].ToShort();
                break;

            case TiffTag.HALFTONEHINTS:
                td.td_halftonehints[0] = value[0].ToShort();
                td.td_halftonehints[1] = value[1].ToShort();
                break;

            case TiffTag.COLORMAP:
                v32 = 1 << td.td_bitspersample;
                Tiff.setShortArray(out td.td_colormap[0], value[0].ToShortArray(), v32);
                Tiff.setShortArray(out td.td_colormap[1], value[1].ToShortArray(), v32);
                Tiff.setShortArray(out td.td_colormap[2], value[2].ToShortArray(), v32);
                break;

            case TiffTag.EXTRASAMPLES:
                if (!setExtraSamples(td, ref v, value))
                {
                    badvalue = true;
                    break;
                }

                break;

            case TiffTag.MATTEING:
                if (value[0].ToShort() != 0)
                {
                    td.td_extrasamples = 1;
                }
                else
                {
                    td.td_extrasamples = 0;
                }

                if (td.td_extrasamples != 0)
                {
                    td.td_sampleinfo    = new ExtraSample[1];
                    td.td_sampleinfo[0] = ExtraSample.ASSOCALPHA;
                }
                break;

            case TiffTag.TILEWIDTH:
                v32 = value[0].ToInt();
                if ((v32 % 16) != 0)
                {
                    if (tif.m_mode != Tiff.O_RDONLY)
                    {
                        badvalue32 = true;
                        break;
                    }

                    Tiff.WarningExt(tif, tif.m_clientdata, tif.m_name,
                                    "Nonstandard tile width {0}, convert file", v32);
                }
                td.td_tilewidth = v32;
                tif.m_flags    |= TiffFlags.ISTILED;
                break;

            case TiffTag.TILELENGTH:
                v32 = value[0].ToInt();
                if ((v32 % 16) != 0)
                {
                    if (tif.m_mode != Tiff.O_RDONLY)
                    {
                        badvalue32 = true;
                        break;
                    }

                    Tiff.WarningExt(tif, tif.m_clientdata, tif.m_name,
                                    "Nonstandard tile length {0}, convert file", v32);
                }
                td.td_tilelength = v32;
                tif.m_flags     |= TiffFlags.ISTILED;
                break;

            case TiffTag.TILEDEPTH:
                v32 = value[0].ToInt();
                if (v32 == 0)
                {
                    badvalue32 = true;
                    break;
                }

                td.td_tiledepth = v32;
                break;

            case TiffTag.DATATYPE:
                v = value[0].ToInt();
                SampleFormat sf = SampleFormat.VOID;
                switch (v)
                {
                case DATATYPE_VOID:
                    sf = SampleFormat.VOID;
                    break;

                case DATATYPE_INT:
                    sf = SampleFormat.INT;
                    break;

                case DATATYPE_UINT:
                    sf = SampleFormat.UINT;
                    break;

                case DATATYPE_IEEEFP:
                    sf = SampleFormat.IEEEFP;
                    break;

                default:
                    badvalue = true;
                    break;
                }

                if (!badvalue)
                {
                    td.td_sampleformat = sf;
                }

                break;

            case TiffTag.SAMPLEFORMAT:
                v  = value[0].ToInt();
                sf = (SampleFormat)v;
                if (sf < SampleFormat.UINT || SampleFormat.COMPLEXIEEEFP < sf)
                {
                    badvalue = true;
                    break;
                }

                td.td_sampleformat = sf;

                // Try to fix up the SWAB function for complex data.
                if (td.td_sampleformat == SampleFormat.COMPLEXINT &&
                    td.td_bitspersample == 32 && tif.m_postDecodeMethod == Tiff.PostDecodeMethodType.pdmSwab32Bit)
                {
                    tif.m_postDecodeMethod = Tiff.PostDecodeMethodType.pdmSwab16Bit;
                }
                else if ((td.td_sampleformat == SampleFormat.COMPLEXINT ||
                          td.td_sampleformat == SampleFormat.COMPLEXIEEEFP) &&
                         td.td_bitspersample == 64 && tif.m_postDecodeMethod == Tiff.PostDecodeMethodType.pdmSwab64Bit)
                {
                    tif.m_postDecodeMethod = Tiff.PostDecodeMethodType.pdmSwab32Bit;
                }
                break;

            case TiffTag.IMAGEDEPTH:
                td.td_imagedepth = value[0].ToInt();
                break;

            case TiffTag.SUBIFD:
                if ((tif.m_flags & TiffFlags.INSUBIFD) != TiffFlags.INSUBIFD)
                {
                    td.td_nsubifd = value[0].ToInt();
                    Tiff.setLong8Array(out td.td_subifd, value[1].TolongArray(), td.td_nsubifd);
                }
                else
                {
                    Tiff.ErrorExt(tif, tif.m_clientdata, module,
                                  "{0}: Sorry, cannot nest SubIFDs", tif.m_name);
                    status = false;
                }
                break;

            case TiffTag.YCBCRPOSITIONING:
                td.td_ycbcrpositioning = (YCbCrPosition)value[0].ToShort();
                break;

            case TiffTag.YCBCRSUBSAMPLING:
                td.td_ycbcrsubsampling[0] = value[0].ToShort();
                td.td_ycbcrsubsampling[1] = value[1].ToShort();
                break;

            case TiffTag.TRANSFERFUNCTION:
                v = ((td.td_samplesperpixel - td.td_extrasamples) > 1 ? 3 : 1);
                for (int i = 0; i < v; i++)
                {
                    Tiff.setShortArray(out td.td_transferfunction[i], value[0].ToShortArray(), 1 << td.td_bitspersample);
                }
                break;

            case TiffTag.REFERENCEBLACKWHITE:
                // XXX should check for null range
                Tiff.setFloatArray(out td.td_refblackwhite, value[0].ToFloatArray(), 6);
                break;

            case TiffTag.INKNAMES:
                v = value[0].ToInt();
                string s = value[1].ToString();
                v      = checkInkNamesString(tif, v, s);
                status = v > 0;
                if (v > 0)
                {
                    setNString(out td.td_inknames, s, v);
                    td.td_inknameslen = v;
                }
                break;

            default:
                // 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.
                TiffFieldInfo fip = tif.FindFieldInfo(tag, TiffType.ANY);
                if (fip == null || fip.Bit != FieldBit.Custom)
                {
                    Tiff.ErrorExt(tif, tif.m_clientdata, module,
                                  "{0}: Invalid {1}tag \"{2}\" (not supported by codec)",
                                  tif.m_name, Tiff.isPseudoTag(tag) ? "pseudo-" : string.Empty,
                                  fip != null ? fip.Name : "Unknown");
                    status = false;
                    break;
                }

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

                // Grow the custom list if the entry was not found.
                if (tvIndex == -1)
                {
                    td.td_customValueCount++;
                    TiffTagValue[] new_customValues = Tiff.Realloc(
                        td.td_customValues, td.td_customValueCount - 1, td.td_customValueCount);
                    td.td_customValues = new_customValues;

                    tvIndex = td.td_customValueCount - 1;
                    td.td_customValues[tvIndex].info  = fip;
                    td.td_customValues[tvIndex].value = null;
                    td.td_customValues[tvIndex].count = 0;
                }

                // Set custom value ... save a copy of the custom tag value.
                int tv_size = Tiff.dataSize(fip.Type);
                if (tv_size == 0)
                {
                    status = false;
                    Tiff.ErrorExt(tif, tif.m_clientdata, module,
                                  "{0}: Bad field type {1} for \"{2}\"",
                                  tif.m_name, fip.Type, fip.Name);
                    end = true;
                    break;
                }

                int paramIndex = 0;
                if (fip.PassCount)
                {
                    if (fip.WriteCount == TiffFieldInfo.Variable2)
                    {
                        td.td_customValues[tvIndex].count = value[paramIndex++].ToInt();
                    }
                    else
                    {
                        td.td_customValues[tvIndex].count = value[paramIndex++].ToInt();
                    }
                }
                else if (fip.WriteCount == TiffFieldInfo.Variable ||
                         fip.WriteCount == TiffFieldInfo.Variable2)
                {
                    td.td_customValues[tvIndex].count = 1;
                }
                else if (fip.WriteCount == TiffFieldInfo.Spp)
                {
                    td.td_customValues[tvIndex].count = td.td_samplesperpixel;
                }
                else
                {
                    td.td_customValues[tvIndex].count = fip.WriteCount;
                }

                if (fip.Type == TiffType.ASCII)
                {
                    string ascii;
                    Tiff.setString(out ascii, value[paramIndex++].ToString());
                    td.td_customValues[tvIndex].value = Tiff.Latin1Encoding.GetBytes(ascii);
                }
                else
                {
                    td.td_customValues[tvIndex].value = new byte[tv_size * td.td_customValues[tvIndex].count];
                    if ((fip.PassCount ||
                         fip.WriteCount == TiffFieldInfo.Variable ||
                         fip.WriteCount == TiffFieldInfo.Variable2 ||
                         fip.WriteCount == TiffFieldInfo.Spp ||
                         td.td_customValues[tvIndex].count > 1) &&
                        fip.Tag != TiffTag.PAGENUMBER &&
                        fip.Tag != TiffTag.HALFTONEHINTS &&
                        fip.Tag != TiffTag.YCBCRSUBSAMPLING &&
                        fip.Tag != TiffTag.DOTRANGE)
                    {
                        byte[] apBytes = value[paramIndex++].GetBytes();
                        Buffer.BlockCopy(apBytes, 0, td.td_customValues[tvIndex].value, 0, Math.Min(apBytes.Length, td.td_customValues[tvIndex].value.Length));
                    }
                    else
                    {
                        // XXX: The following loop required to handle
                        // PAGENUMBER, HALFTONEHINTS,
                        // YCBCRSUBSAMPLING and DOTRANGE tags.
                        // These tags are actually arrays and should be
                        // passed as arrays to SetField() function, but
                        // actually passed as a list of separate values.
                        // This behavior must be changed in the future!

                        // Upd: This loop also processes some EXIF tags with
                        // UNDEFINED type (like EXIF_FILESOURCE or EXIF_SCENETYPE)
                        // In this case input value is string-based, so
                        // in TiffType.UNDEFINED case we use FieldValue.GetBytes()[0]
                        // construction instead of direct call of FieldValue.ToByte() method.
                        byte[] val    = td.td_customValues[tvIndex].value;
                        int    valPos = 0;
                        for (int i = 0; i < td.td_customValues[tvIndex].count; i++, valPos += tv_size)
                        {
                            switch (fip.Type)
                            {
                            case TiffType.BYTE:
                            case TiffType.UNDEFINED:
                                val[valPos] = value[paramIndex + i].GetBytes()[0];
                                break;

                            case TiffType.SBYTE:
                                val[valPos] = value[paramIndex + i].ToByte();
                                break;

                            case TiffType.SHORT:
                                Buffer.BlockCopy(BitConverter.GetBytes(value[paramIndex + i].ToShort()), 0, val, valPos, tv_size);
                                break;

                            case TiffType.SSHORT:
                                Buffer.BlockCopy(BitConverter.GetBytes(value[paramIndex + i].ToShort()), 0, val, valPos, tv_size);
                                break;

                            case TiffType.LONG:
                            case TiffType.IFD:
                                Buffer.BlockCopy(BitConverter.GetBytes(value[paramIndex + i].ToInt()), 0, val, valPos, tv_size);
                                break;

                            case TiffType.SLONG:
                                Buffer.BlockCopy(BitConverter.GetBytes(value[paramIndex + i].ToInt()), 0, val, valPos, tv_size);
                                break;

                            case TiffType.RATIONAL:
                            case TiffType.SRATIONAL:
                            case TiffType.FLOAT:
                                Buffer.BlockCopy(BitConverter.GetBytes(value[paramIndex + i].ToFloat()), 0, val, valPos, tv_size);
                                break;

                            case TiffType.DOUBLE:
                                Buffer.BlockCopy(BitConverter.GetBytes(value[paramIndex + i].ToDouble()), 0, val, valPos, tv_size);
                                break;

                            default:
                                Array.Clear(val, valPos, tv_size);
                                status = false;
                                break;
                            }
                        }
                    }
                }
                break;
            }

            if (!end && !badvalue && !badvalue32)
            {
                if (status)
                {
                    tif.setFieldBit(tif.FieldWithTag(tag).Bit);
                    tif.m_flags |= TiffFlags.DIRTYDIRECT;
                }
            }

            if (badvalue)
            {
                Tiff.ErrorExt(tif, tif.m_clientdata, module,
                              "{0}: Bad value {1} for \"{2}\" tag",
                              tif.m_name, v, tif.FieldWithTag(tag).Name);
                return(false);
            }

            if (badvalue32)
            {
                Tiff.ErrorExt(tif, tif.m_clientdata, module,
                              "{0}: Bad value {1} for \"{2}\" tag",
                              tif.m_name, v32, tif.FieldWithTag(tag).Name);
                return(false);
            }

            return(status);
        }
Ejemplo n.º 10
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.º 11
0
        // Helper methods
        private static void TagExtender(Tiff tif)
        {
            TiffFieldInfo[] tiffFieldInfo = new TiffFieldInfo[1];
            tiffFieldInfo[0] = new TiffFieldInfo((TiffTag)TagToWrite, -1, -1, TiffType.ASCII, FieldBit.Custom, true, false, "Tag." + TagToWrite);

            tif.MergeFieldInfo(tiffFieldInfo, tiffFieldInfo.Length);
        }
Ejemplo n.º 12
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.º 13
0
        /// <summary>
        /// Writes custom directory. See ticket #51.
        /// </summary>
        /// <param name="pdiroff">Output directory offset.</param>
        /// <returns><c>true</c> if succeeded; otherwise, <c>false</c></returns>
        private bool WriteCustomDirectory(out long pdiroff)
        {
            pdiroff = -1;

            if (m_mode == O_RDONLY)
            {
                return(true);
            }

            // Size the directory so that we can calculate offsets for the data
            // items that aren't kept in-place in each field.
            int nfields = 0;

            for (int b = 0; b <= FieldBit.Last; b++)
            {
                if (fieldSet(b) && b != FieldBit.Custom)
                {
                    nfields += (b < FieldBit.SubFileType ? 2 : 1);
                }
            }

            nfields += m_dir.td_customValueCount;
            int dirsize = nfields * TiffDirEntry.SizeInBytes(m_header.tiff_version == TIFF_BIGTIFF_VERSION);

            TiffDirEntry[] data = new TiffDirEntry[nfields];

            // Put the directory at the end of the file.
            m_diroff  = (ulong)((seekFile(0, SeekOrigin.End) + 1) & ~1);
            m_dataoff = m_diroff + sizeof(short) + (ulong)dirsize + sizeof(int);
            if ((m_dataoff & 1) != 0)
            {
                m_dataoff++;
            }

            seekFile((long)m_dataoff, SeekOrigin.Begin);

            // Setup external form of directory entries and write data items.
            int[] fields = new int[FieldBit.SetLongs];
            Buffer.BlockCopy(m_dir.td_fieldsset, 0, fields, 0, FieldBit.SetLongs * sizeof(int));

            for (int fi = 0, nfi = m_nfields; nfi > 0; nfi--, fi++)
            {
                TiffFieldInfo fip = m_fieldinfo[fi];

                // 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.Bit == FieldBit.Custom)
                {
                    bool is_set = false;
                    for (int ci = 0; ci < m_dir.td_customValueCount; ci++)
                    {
                        is_set |= (m_dir.td_customValues[ci].info == fip);
                    }

                    if (!is_set)
                    {
                        continue;
                    }
                }
                else if (!fieldSet(fields, fip.Bit))
                {
                    continue;
                }

                if (fip.Bit != FieldBit.Custom)
                {
                    resetFieldBit(fields, fip.Bit);
                }
            }

            // Write directory.

            short dircount = (short)nfields;

            pdiroff = (long)m_nextdiroff;
            if ((m_flags & TiffFlags.SWAB) == TiffFlags.SWAB)
            {
                // 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.
                for (int i = 0; i < dircount; i++)
                {
                    TiffDirEntry dirEntry = data[i];

                    short temp = (short)dirEntry.tdir_tag;
                    SwabShort(ref temp);
                    dirEntry.tdir_tag = (TiffTag)(ushort)temp;

                    temp = (short)dirEntry.tdir_type;
                    SwabShort(ref temp);
                    dirEntry.tdir_type = (TiffType)temp;
                    SwabLong(ref dirEntry.tdir_count);
                    SwabBigTiffValue(ref dirEntry.tdir_offset, m_header.tiff_version == TIFF_BIGTIFF_VERSION, false);
                }

                dircount = (short)nfields;
                SwabShort(ref dircount);

                int tempOff = (int)pdiroff;
                SwabLong(ref tempOff);
                pdiroff = tempOff;
            }

            seekFile((long)m_diroff, SeekOrigin.Begin);
            if (!writeShortOK(dircount))
            {
                ErrorExt(this, m_clientdata, m_name, "Error writing directory count");
                return(false);
            }

            if (!writeDirEntryOK(data, dirsize / TiffDirEntry.SizeInBytes(m_header.tiff_version == TIFF_BIGTIFF_VERSION), m_header.tiff_version == TIFF_BIGTIFF_VERSION))
            {
                ErrorExt(this, m_clientdata, m_name, "Error writing directory contents");
                return(false);
            }

            if (!writeIntOK((int)pdiroff))
            {
                ErrorExt(this, m_clientdata, m_name, "Error writing directory link");
                return(false);
            }

            return(true);
        }
Ejemplo n.º 14
0
        /// <summary>
        /// Fetches a tag that is not handled by special case code.
        /// </summary>
        private bool fetchNormalTag(TiffDirEntry dir)
        {
            bool          ok  = false;
            TiffFieldInfo fip = FieldWithTag(dir.tdir_tag);

            if (dir.tdir_count > 1)
            {
                switch (dir.tdir_type)
                {
                case TiffType.BYTE:
                case TiffType.SBYTE:
                    byte[] bytes = new byte [dir.tdir_count];
                    ok = fetchByteArray(dir, bytes);
                    if (ok)
                    {
                        if (fip.PassCount)
                        {
                            ok = SetField(dir.tdir_tag, dir.tdir_count, bytes);
                        }
                        else
                        {
                            ok = SetField(dir.tdir_tag, bytes);
                        }
                    }
                    break;

                case TiffType.SHORT:
                case TiffType.SSHORT:
                    short[] shorts = new short [dir.tdir_count];
                    ok = fetchShortArray(dir, shorts);
                    if (ok)
                    {
                        if (fip.PassCount)
                        {
                            ok = SetField(dir.tdir_tag, dir.tdir_count, shorts);
                        }
                        else
                        {
                            ok = SetField(dir.tdir_tag, shorts);
                        }
                    }
                    break;

                case TiffType.LONG:
                case TiffType.SLONG:
                    int[] ints = new int [dir.tdir_count];
                    ok = fetchLongArray(dir, ints);
                    if (ok)
                    {
                        if (fip.PassCount)
                        {
                            ok = SetField(dir.tdir_tag, dir.tdir_count, ints);
                        }
                        else
                        {
                            ok = SetField(dir.tdir_tag, ints);
                        }
                    }
                    break;

                case TiffType.RATIONAL:
                case TiffType.SRATIONAL:
                    float[] rs = new float [dir.tdir_count];
                    ok = fetchRationalArray(dir, rs);
                    if (ok)
                    {
                        if (fip.PassCount)
                        {
                            ok = SetField(dir.tdir_tag, dir.tdir_count, rs);
                        }
                        else
                        {
                            ok = SetField(dir.tdir_tag, rs);
                        }
                    }
                    break;

                case TiffType.FLOAT:
                    float[] fs = new float [dir.tdir_count];
                    ok = fetchFloatArray(dir, fs);
                    if (ok)
                    {
                        if (fip.PassCount)
                        {
                            ok = SetField(dir.tdir_tag, dir.tdir_count, fs);
                        }
                        else
                        {
                            ok = SetField(dir.tdir_tag, fs);
                        }
                    }
                    break;

                case TiffType.DOUBLE:
                    double[] ds = new double [dir.tdir_count];
                    ok = fetchDoubleArray(dir, ds);
                    if (ok)
                    {
                        if (fip.PassCount)
                        {
                            ok = SetField(dir.tdir_tag, dir.tdir_count, ds);
                        }
                        else
                        {
                            ok = SetField(dir.tdir_tag, ds);
                        }
                    }
                    break;

                case TiffType.ASCII:
                case TiffType.UNDEFINED:
                    // bit of a cheat...

                    // Some vendors write strings w/o the trailing null
                    // byte, so always append one just in case.
                    string cp;
                    ok = fetchString(dir, out cp) != 0;
                    if (ok)
                    {
                        if (fip.PassCount)
                        {
                            ok = SetField(dir.tdir_tag, dir.tdir_count, cp);
                        }
                        else
                        {
                            ok = SetField(dir.tdir_tag, cp);
                        }
                    }
                    break;
                }
            }
            else if (checkDirCount(dir, 1))
            {
                int v32 = 0;
                // singleton value
                switch (dir.tdir_type)
                {
                case TiffType.BYTE:
                case TiffType.SBYTE:
                case TiffType.SHORT:
                case TiffType.SSHORT:
                    // If the tag is also acceptable as a LONG or SLONG
                    // then SetField will expect an int parameter
                    // passed to it.
                    //
                    // NB: We use FieldWithTag here knowing that
                    //     it returns us the first entry in the table
                    //     for the tag and that that entry is for the
                    //     widest potential data type the tag may have.
                    TiffType type = fip.Type;
                    if (type != TiffType.LONG && type != TiffType.SLONG)
                    {
                        short v = (short)extractData(dir);
                        if (fip.PassCount)
                        {
                            short[] a = new short[1];
                            a[0] = v;
                            ok   = SetField(dir.tdir_tag, 1, a);
                        }
                        else
                        {
                            ok = SetField(dir.tdir_tag, v);
                        }

                        break;
                    }

                    v32 = extractData(dir);
                    if (fip.PassCount)
                    {
                        int[] a = new int[1];
                        a[0] = (int)v32;
                        ok   = SetField(dir.tdir_tag, 1, a);
                    }
                    else
                    {
                        ok = SetField(dir.tdir_tag, v32);
                    }

                    break;

                case TiffType.LONG:
                case TiffType.SLONG:
                case TiffType.IFD:
                    v32 = extractData(dir);
                    if (fip.PassCount)
                    {
                        int[] a = new int[1];
                        a[0] = (int)v32;
                        ok   = SetField(dir.tdir_tag, 1, a);
                    }
                    else
                    {
                        ok = SetField(dir.tdir_tag, v32);
                    }

                    break;

                case TiffType.RATIONAL:
                case TiffType.SRATIONAL:
                case TiffType.FLOAT:
                    float f = (dir.tdir_type == TiffType.FLOAT ? fetchFloat(dir): fetchRational(dir));
                    if (fip.PassCount)
                    {
                        float[] a = new float[1];
                        a[0] = f;
                        ok   = SetField(dir.tdir_tag, 1, a);
                    }
                    else
                    {
                        ok = SetField(dir.tdir_tag, f);
                    }

                    break;

                case TiffType.DOUBLE:
                    double[] ds = new double[1];
                    ok = fetchDoubleArray(dir, ds);
                    if (ok)
                    {
                        if (fip.PassCount)
                        {
                            ok = SetField(dir.tdir_tag, 1, ds);
                        }
                        else
                        {
                            ok = SetField(dir.tdir_tag, ds[0]);
                        }
                    }
                    break;

                case TiffType.ASCII:
                case TiffType.UNDEFINED:
                    // bit of a cheat...
                    string c;
                    ok = fetchString(dir, out c) != 0;
                    if (ok)
                    {
                        if (fip.PassCount)
                        {
                            ok = SetField(dir.tdir_tag, 1, c);
                        }
                        else
                        {
                            ok = SetField(dir.tdir_tag, c);
                        }
                    }
                    break;
                }
            }

            return(ok);
        }
Ejemplo n.º 15
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();
                }

                byte[] stringBytes = Latin1Encoding.GetBytes(cp);

                // If this last character is a '\0' null char
                if (stringBytes.Length != 0 && stringBytes[stringBytes.Length - 1] == 0)
                {
                    dir.tdir_count = stringBytes.Length;
                    if (!writeByteArray(ref dir, stringBytes))
                    {
                        return(false);
                    }
                }
                else
                {
                    // add zero ('\0') at the end of the byte array
                    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.º 16
0
 private void setupFieldInfo(TiffFieldInfo[] info, int n)
 {
     m_nfields = 0;
     MergeFieldInfo(info, n);
 }
Ejemplo n.º 17
0
        /// <summary>
        /// Writes the contents of the current directory to the specified file.
        /// </summary>
        /// <remarks>This routine doesn't handle overwriting a directory with
        /// auxiliary storage that's been changed.</remarks>
        private bool writeDirectory(bool done)
        {
            if (m_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 ((m_flags & TiffFlags.POSTENCODE) == TiffFlags.POSTENCODE)
                {
                    m_flags &= ~TiffFlags.POSTENCODE;
                    if (!m_currentCodec.PostEncode())
                    {
                        ErrorExt(this, m_clientdata, m_name, "Error post-encoding before directory write");
                        return(false);
                    }
                }

                // shutdown encoder
                m_currentCodec.Close();

                // Flush any data that might have been written by the
                // compression close+cleanup routines.
                if (m_rawcc > 0 && (m_flags & TiffFlags.BEENWRITING) == TiffFlags.BEENWRITING && !flushData1())
                {
                    ErrorExt(this, m_clientdata, m_name, "Error flushing data before directory write");
                    return(false);
                }

                if ((m_flags & TiffFlags.MYBUFFER) == TiffFlags.MYBUFFER && m_rawdata != null)
                {
                    m_rawdata     = null;
                    m_rawcc       = 0;
                    m_rawdatasize = 0;
                }

                m_flags &= ~(TiffFlags.BEENWRITING | TiffFlags.BUFFERSETUP);
            }

            // Size the directory so that we can calculate offsets for the data
            // items that aren't kept in-place in each field.
            int nfields = 0;

            for (int b = 0; b <= FieldBit.Last; b++)
            {
                if (fieldSet(b) && b != FieldBit.Custom)
                {
                    nfields += (b < FieldBit.SubFileType ? 2 : 1);
                }
            }

            nfields += m_dir.td_customValueCount;
            int dirsize = nfields * TiffDirEntry.SizeInBytes;

            TiffDirEntry[] data = new TiffDirEntry [nfields];
            for (int i = 0; i < nfields; i++)
            {
                data[i] = new TiffDirEntry();
            }

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

            m_dataoff = m_diroff + sizeof(short) + (uint)dirsize + sizeof(int);
            if ((m_dataoff & 1) != 0)
            {
                m_dataoff++;
            }

            seekFile(m_dataoff, SeekOrigin.Begin);
            m_curdir++;
            int dir = 0;

            // Setup external form of directory entries and write data items.
            int[] fields = new int[FieldBit.SetLongs];
            Buffer.BlockCopy(m_dir.td_fieldsset, 0, fields, 0, FieldBit.SetLongs * sizeof(int));

            // Write out ExtraSamples tag only if extra samples are present in the data.
            if (fieldSet(fields, FieldBit.ExtraSamples) && m_dir.td_extrasamples == 0)
            {
                resetFieldBit(fields, FieldBit.ExtraSamples);
                nfields--;
                dirsize -= TiffDirEntry.SizeInBytes;
            } // XXX

            for (int fi = 0, nfi = m_nfields; nfi > 0; nfi--, fi++)
            {
                TiffFieldInfo fip = m_fieldinfo[fi];

                // 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.Bit == FieldBit.Custom)
                {
                    bool is_set = false;
                    for (int ci = 0; ci < m_dir.td_customValueCount; ci++)
                    {
                        is_set |= (m_dir.td_customValues[ci].info == fip);
                    }

                    if (!is_set)
                    {
                        continue;
                    }
                }
                else if (!fieldSet(fields, fip.Bit))
                {
                    continue;
                }

                // Handle other fields.

                TiffTag tag = (TiffTag)FieldBit.Ignore;
                switch (fip.Bit)
                {
                case FieldBit.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() ? TiffTag.TILEOFFSETS : TiffTag.STRIPOFFSETS;
                    if (tag != fip.Tag)
                    {
                        continue;
                    }

                    data[dir].tdir_tag   = tag;
                    data[dir].tdir_type  = TiffType.LONG;
                    data[dir].tdir_count = m_dir.td_nstrips;
                    if (!writeLongArray(ref data[dir], m_dir.td_stripoffset))
                    {
                        return(false);
                    }

                    break;

                case FieldBit.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() ? TiffTag.TILEBYTECOUNTS: TiffTag.STRIPBYTECOUNTS;
                    if (tag != fip.Tag)
                    {
                        continue;
                    }

                    data[dir].tdir_tag   = tag;
                    data[dir].tdir_type  = TiffType.LONG;
                    data[dir].tdir_count = m_dir.td_nstrips;
                    if (!writeLongArray(ref data[dir], m_dir.td_stripbytecount))
                    {
                        return(false);
                    }

                    break;

                case FieldBit.RowsPerStrip:
                    setupShortLong(TiffTag.ROWSPERSTRIP, ref data[dir], m_dir.td_rowsperstrip);
                    break;

                case FieldBit.ColorMap:
                    if (!writeShortTable(TiffTag.COLORMAP, ref data[dir], 3, m_dir.td_colormap))
                    {
                        return(false);
                    }

                    break;

                case FieldBit.ImageDimensions:
                    setupShortLong(TiffTag.IMAGEWIDTH, ref data[dir++], m_dir.td_imagewidth);
                    setupShortLong(TiffTag.IMAGELENGTH, ref data[dir], m_dir.td_imagelength);
                    break;

                case FieldBit.TileDimensions:
                    setupShortLong(TiffTag.TILEWIDTH, ref data[dir++], m_dir.td_tilewidth);
                    setupShortLong(TiffTag.TILELENGTH, ref data[dir], m_dir.td_tilelength);
                    break;

                case FieldBit.Compression:
                    setupShort(TiffTag.COMPRESSION, ref data[dir], (short)m_dir.td_compression);
                    break;

                case FieldBit.Photometric:
                    setupShort(TiffTag.PHOTOMETRIC, ref data[dir], (short)m_dir.td_photometric);
                    break;

                case FieldBit.Position:
                    if (!writeRationalPair(data, dir, TiffType.RATIONAL, TiffTag.XPOSITION, m_dir.td_xposition, TiffTag.YPOSITION, m_dir.td_yposition))
                    {
                        return(false);
                    }

                    dir++;
                    break;

                case FieldBit.Resolution:
                    if (!writeRationalPair(data, dir, TiffType.RATIONAL, TiffTag.XRESOLUTION, m_dir.td_xresolution, TiffTag.YRESOLUTION, m_dir.td_yresolution))
                    {
                        return(false);
                    }

                    dir++;
                    break;

                case FieldBit.BitsPerSample:
                case FieldBit.MinSampleValue:
                case FieldBit.MaxSampleValue:
                case FieldBit.SampleFormat:
                    if (!writePerSampleShorts(fip.Tag, ref data[dir]))
                    {
                        return(false);
                    }

                    break;

                case FieldBit.SMinSampleValue:
                case FieldBit.SMaxSampleValue:
                    if (!writePerSampleAnys(sampleToTagType(), fip.Tag, ref data[dir]))
                    {
                        return(false);
                    }

                    break;

                case FieldBit.PageNumber:
                case FieldBit.HalftoneHints:
                case FieldBit.YCbCrSubsampling:
                    if (!setupShortPair(fip.Tag, ref data[dir]))
                    {
                        return(false);
                    }

                    break;

                case FieldBit.InkNames:
                    if (!writeInkNames(ref data[dir]))
                    {
                        return(false);
                    }

                    break;

                case FieldBit.TransferFunction:
                    if (!writeTransferFunction(ref data[dir]))
                    {
                        return(false);
                    }

                    break;

                case FieldBit.SubIFD:
                    // XXX: Always write this field using LONG type
                    // for backward compatibility.
                    data[dir].tdir_tag   = fip.Tag;
                    data[dir].tdir_type  = TiffType.LONG;
                    data[dir].tdir_count = m_dir.td_nsubifd;
                    if (!writeLongArray(ref data[dir], m_dir.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 (data[dir].tdir_count > 0)
                    {
                        m_flags  |= TiffFlags.INSUBIFD;
                        m_nsubifd = (short)data[dir].tdir_count;
                        if (data[dir].tdir_count > 1)
                        {
                            m_subifdoff = data[dir].tdir_offset;
                        }
                        else
                        {
                            m_subifdoff = m_diroff + sizeof(short) +
                                          (uint)dir * TiffDirEntry.SizeInBytes +
                                          sizeof(short) * 2 + sizeof(int);
                        }
                    }
                    break;

                default:
                    // XXX: Should be fixed and removed.
                    if (fip.Tag == TiffTag.DOTRANGE)
                    {
                        if (!setupShortPair(fip.Tag, ref data[dir]))
                        {
                            return(false);
                        }
                    }
                    else if (!writeNormalTag(ref data[dir], fip))
                    {
                        return(false);
                    }

                    break;
                }

                dir++;

                if (fip.Bit != FieldBit.Custom)
                {
                    resetFieldBit(fields, fip.Bit);
                }
            }

            // Write directory.

            short dircount = (short)nfields;
            uint  diroff   = m_nextdiroff;

            if ((m_flags & TiffFlags.SWAB) == TiffFlags.SWAB)
            {
                // 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.
                for (dir = 0; dircount != 0; dir++, dircount--)
                {
                    short temp = (short)data[dir].tdir_tag;
                    SwabShort(ref temp);
                    data[dir].tdir_tag = (TiffTag)(ushort)temp;

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

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

                dircount = (short)nfields;
                SwabShort(ref dircount);
                SwabUInt(ref diroff);
            }

            seekFile(m_diroff, SeekOrigin.Begin);
            if (!writeShortOK(dircount))
            {
                ErrorExt(this, m_clientdata, m_name, "Error writing directory count");
                return(false);
            }

            if (!writeDirEntryOK(data, dirsize / TiffDirEntry.SizeInBytes))
            {
                ErrorExt(this, m_clientdata, m_name, "Error writing directory contents");
                return(false);
            }

            if (!writeIntOK((int)diroff))
            {
                ErrorExt(this, m_clientdata, m_name, "Error writing directory link");
                return(false);
            }

            if (done)
            {
                FreeDirectory();
                m_flags &= ~TiffFlags.DIRTYDIRECT;
                m_currentCodec.Cleanup();

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

            return(true);
        }
Ejemplo n.º 18
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");
        }