private static void readDirEntry(TiffDirEntry[] dir, ulong dircount, byte[] bytes, int offset, bool isBigTiff) { int pos = offset; for (ulong i = 0; i < dircount; i++) { TiffDirEntry entry = new TiffDirEntry(); entry.tdir_tag = (TiffTag)(ushort)readShort(bytes, pos); pos += sizeof(short); entry.tdir_type = (TiffType)readShort(bytes, pos); pos += sizeof(short); if (isBigTiff) { entry.tdir_count = (int)readULong(bytes, pos); pos += sizeof(ulong); entry.tdir_offset = readULong(bytes, pos); pos += sizeof(ulong); } else { entry.tdir_count = (int)readInt(bytes, pos); pos += sizeof(int); entry.tdir_offset = (ulong)(uint)readInt(bytes, pos); pos += sizeof(int); } dir[i] = entry; } }
/// <summary> /// Fetches an array of FLOAT values. /// </summary> private bool fetchFloatArray(TiffDirEntry dir, float[] v) { if (dir.tdir_count == 1) { v[0] = BitConverter.ToSingle(BitConverter.GetBytes(dir.tdir_offset), 0); return(true); } int w = DataWidth(dir.tdir_type); int cc = dir.tdir_count * w; byte[] b = new byte [cc]; int read = fetchData(dir, b); if (read != 0) { int byteOffset = 0; for (int i = 0; i < read / 4; i++) { v[i] = BitConverter.ToSingle(b, byteOffset); byteOffset += 4; } } return(read != 0); }
/// <summary> /// Setups a SHORT directory entry /// </summary> private void setupShort(TiffTag tag, ref TiffDirEntry dir, short v) { dir.tdir_tag = tag; dir.tdir_count = 1; dir.tdir_type = TiffType.SHORT; dir.tdir_offset = insertData(TiffType.SHORT, v); }
/* * Fetch and set the SubjectDistance EXIF tag. */ private bool fetchSubjectDistance(TiffDirEntry dir) { if (dir.tdir_count != 1 || dir.tdir_type != TiffType.RATIONAL) { Tiff.WarningExt(this, m_clientdata, m_name, "incorrect count or type for SubjectDistance, tag ignored"); return(false); } bool ok = false; byte[] b = new byte[2 * sizeof(int)]; int read = fetchData(dir, b); if (read != 0) { int[] l = new int[2]; l[0] = readInt(b, 0); l[1] = readInt(b, sizeof(int)); float v; if (cvtRational(dir, l[0], l[1], out v)) { /* * XXX: Numerator -1 means that we have infinite * distance. Indicate that with a negative floating point * SubjectDistance value. */ ok = SetField(dir.tdir_tag, (l[0] != -1) ? v : -v); } } return(ok); }
/// <summary> /// Setup a directory entry of an array of SHORT or SSHORT and write /// the associated indirect values. /// </summary> private bool writeShortArray(ref TiffDirEntry dir, short[] v) { if (dir.tdir_count <= 2) { if (m_header.tiff_magic == TIFF_BIGENDIAN) { dir.tdir_offset = (uint)(v[0] << 16); if (dir.tdir_count == 2) { dir.tdir_offset |= (uint)(v[1] & 0xffff); } } else { dir.tdir_offset = (uint)(v[0] & 0xffff); if (dir.tdir_count == 2) { dir.tdir_offset |= (uint)(v[1] << 16); } } return(true); } return(writeData(ref dir, v, dir.tdir_count)); }
private bool writeTransferFunction(ref TiffDirEntry dir) { // Check if the table can be written as a single column, or if it // must be written as 3 columns. Note that we write a 3-column tag // if there are 2 samples/pixel and a single column of data // won't suffice--hmm. int u = m_dir.td_samplesperpixel - m_dir.td_extrasamples; int ncols = 1; bool reCheck = false; int n = 1 << m_dir.td_bitspersample; if (u < 0 || u > 2) { if (Compare(m_dir.td_transferfunction[0], m_dir.td_transferfunction[2], n) != 0) { ncols = 3; } else { reCheck = true; } } if (u == 2 || reCheck) { if (Compare(m_dir.td_transferfunction[0], m_dir.td_transferfunction[1], n) != 0) { ncols = 3; } } return(writeShortTable(TiffTag.TRANSFERFUNCTION, ref dir, ncols, m_dir.td_transferfunction)); }
/// <summary> /// Fetch an array of RATIONAL or SRATIONAL values. /// </summary> private bool fetchRationalArray(TiffDirEntry dir, float[] v) { Debug.Assert(sizeof(float) == sizeof(int)); bool ok = false; byte[] l = new byte [dir.tdir_count * DataWidth(dir.tdir_type)]; if (fetchData(dir, l) != 0) { int offset = 0; int[] pair = new int[2]; for (int i = 0; i < dir.tdir_count; i++) { pair[0] = readInt(l, offset); offset += sizeof(int); pair[1] = readInt(l, offset); offset += sizeof(int); ok = cvtRational(dir, pair[0], pair[1], out v[i]); if (!ok) { break; } } } return(ok); }
/* * Fetch a pair of SHORT or BYTE values. Some tags may have either BYTE * or SHORT type and this function works with both ones. */ private bool fetchShortPair(TiffDirEntry dir) { /* * Prevent overflowing arrays below by performing a sanity * check on tdir_count, this should never be greater than two. */ if (dir.tdir_count > 2) { WarningExt(this, m_clientdata, m_name, "unexpected count for field \"{0}\", {1}, expected 2; ignored", FieldWithTag(dir.tdir_tag).Name, dir.tdir_count); return(false); } switch (dir.tdir_type) { case TiffType.BYTE: case TiffType.SBYTE: byte[] bytes = new byte[4]; return(fetchByteArray(dir, bytes) && SetField(dir.tdir_tag, bytes[0], bytes[1])); case TiffType.SHORT: case TiffType.SSHORT: short[] shorts = new short[2]; return(fetchShortArray(dir, shorts) && SetField(dir.tdir_tag, shorts[0], shorts[1])); } return(false); }
private bool writeInkNames(ref TiffDirEntry dir) { dir.tdir_tag = TiffTag.INKNAMES; dir.tdir_type = TiffType.ASCII; byte[] bytes = Latin1Encoding.GetBytes(m_dir.td_inknames); dir.tdir_count = bytes.Length; return(writeByteArray(ref dir, bytes)); }
/// <summary> /// Fetches an array of BYTE or SBYTE values. /// </summary> private bool fetchByteArray(TiffDirEntry dir, byte[] v) { if (dir.tdir_count <= 4) { // Extract data from offset field. int count = dir.tdir_count; if (m_header.tiff_magic == TIFF_BIGENDIAN) { if (count == 4) { v[3] = (byte)(dir.tdir_offset & 0xff); } if (count >= 3) { v[2] = (byte)((dir.tdir_offset >> 8) & 0xff); } if (count >= 2) { v[1] = (byte)((dir.tdir_offset >> 16) & 0xff); } if (count >= 1) { v[0] = (byte)(dir.tdir_offset >> 24); } } else { if (count == 4) { v[3] = (byte)(dir.tdir_offset >> 24); } if (count >= 3) { v[2] = (byte)((dir.tdir_offset >> 16) & 0xff); } if (count >= 2) { v[1] = (byte)((dir.tdir_offset >> 8) & 0xff); } if (count >= 1) { v[0] = (byte)(dir.tdir_offset & 0xff); } } return(true); } return(fetchData(dir, v) != 0); }
/// <summary> /// Fetches a contiguous directory item. /// </summary> private int fetchData(TiffDirEntry dir, byte[] buffer) { int width = DataWidth(dir.tdir_type); int count = (int)dir.tdir_count * width; // Check for overflow. if (dir.tdir_count == 0 || width == 0 || (count / width) != dir.tdir_count) { fetchFailed(dir); } if (!seekOK(dir.tdir_offset)) { fetchFailed(dir); } if (!readOK(buffer, count)) { fetchFailed(dir); } if ((m_flags & TiffFlags.SWAB) == TiffFlags.SWAB) { switch (dir.tdir_type) { case TiffType.SHORT: case TiffType.SSHORT: short[] s = ByteArrayToShorts(buffer, 0, count); SwabArrayOfShort(s, dir.tdir_count); ShortsToByteArray(s, 0, dir.tdir_count, buffer, 0); break; case TiffType.LONG: case TiffType.SLONG: case TiffType.FLOAT: case TiffType.IFD: int[] l = ByteArrayToInts(buffer, 0, count); SwabArrayOfLong(l, dir.tdir_count); IntsToByteArray(l, 0, dir.tdir_count, buffer, 0); break; case TiffType.RATIONAL: case TiffType.SRATIONAL: int[] r = ByteArrayToInts(buffer, 0, count); SwabArrayOfLong(r, 2 * dir.tdir_count); IntsToByteArray(r, 0, 2 * dir.tdir_count, buffer, 0); break; case TiffType.DOUBLE: swab64BitData(buffer, 0, count); break; } } return(count); }
/// <summary> /// Setup a directory entry of an array of LONG or SLONG and write the /// associated indirect values. /// </summary> private bool writeLongArray(ref TiffDirEntry dir, int[] v) { if (dir.tdir_count == 1) { dir.tdir_offset = (uint)v[0]; return(true); } return(writeData(ref dir, v, dir.tdir_count)); }
private bool writeFloatArray(ref TiffDirEntry dir, float[] v) { if (dir.tdir_count == 1) { dir.tdir_offset = BitConverter.ToUInt32(BitConverter.GetBytes(v[0]), 0); return(true); } return(writeData(ref dir, v, dir.tdir_count)); }
private bool writeData(ref TiffDirEntry dir, float[] cp, int cc) { int[] ints = new int[cc]; for (int i = 0; i < cc; i++) { byte[] result = BitConverter.GetBytes(cp[i]); ints[i] = BitConverter.ToInt32(result, 0); } return(writeData(ref dir, ints, cc)); }
/// <summary> /// Reads IFD structure from the specified offset. /// </summary> /// <returns>The number of fields in the directory or 0 if failed.</returns> private short fetchDirectory(uint diroff, out TiffDirEntry[] pdir, out uint nextdiroff) { const string module = "fetchDirectory"; m_diroff = diroff; nextdiroff = 0; short dircount; TiffDirEntry[] dir = null; pdir = null; if (!seekOK(m_diroff)) { ErrorExt(this, m_clientdata, module, "{0}: Seek error accessing TIFF directory", m_name); return(0); } if (!readShortOK(out dircount)) { ErrorExt(this, m_clientdata, module, "{0}: Can not read TIFF directory count", m_name); return(0); } if ((m_flags & TiffFlags.SWAB) == TiffFlags.SWAB) { SwabShort(ref dircount); } dir = new TiffDirEntry [dircount]; if (!readDirEntryOk(dir, dircount)) { ErrorExt(this, m_clientdata, module, "{0}: Can not read TIFF directory", m_name); return(0); } // Read offset to next directory for sequential scans. int temp; readIntOK(out temp); nextdiroff = (uint)temp; if ((m_flags & TiffFlags.SWAB) == TiffFlags.SWAB) { temp = (int)nextdiroff; SwabLong(ref temp); nextdiroff = (uint)temp; } pdir = dir; return(dircount); }
private int extractData(TiffDirEntry dir) { int type = (int)dir.tdir_type; if (m_header.tiff_magic == TIFF_BIGENDIAN) { return((int)((dir.tdir_offset >> m_typeshift[type]) & m_typemask[type])); } return((int)(dir.tdir_offset & m_typemask[type])); }
/* * Setup a pair of shorts that are returned by * value, rather than as a reference to an array. */ private bool setupShortPair(TiffTag tag, ref TiffDirEntry dir) { short[] v = new short[2]; FieldValue[] result = GetField(tag); v[0] = result[0].ToShort(); v[1] = result[1].ToShort(); dir.tdir_tag = tag; dir.tdir_type = TiffType.SHORT; dir.tdir_count = 2; return(writeShortArray(ref dir, v)); }
private bool writeData(ref TiffDirEntry dir, double[] buffer, int count) { if ((m_flags & TiffFlags.SWAB) == TiffFlags.SWAB) { SwabArrayOfDouble(buffer, count); } byte[] bytes = new byte[count * sizeof(double)]; Buffer.BlockCopy(buffer, 0, bytes, 0, bytes.Length); return(writeData(ref dir, bytes, count * sizeof(double))); }
private bool writeData(ref TiffDirEntry dir, short[] buffer, int count) { if ((m_flags & TiffFlags.SWAB) == TiffFlags.SWAB) { SwabArrayOfShort(buffer, count); } int byteCount = count * sizeof(short); byte[] bytes = new byte [byteCount]; ShortsToByteArray(buffer, 0, count, bytes, 0); return(writeData(ref dir, bytes, byteCount)); }
/// <summary> /// Fetches a set of offsets or lengths. /// </summary> /// <remarks>While this routine says "strips", in fact it's also used /// for tiles.</remarks> private bool fetchStripThing(TiffDirEntry dir, int nstrips, ref int[] lpp) { checkDirCount(dir, nstrips); // Allocate space for strip information. if (lpp == null) { lpp = new int [nstrips]; } else { Array.Clear(lpp, 0, lpp.Length); } bool status = false; if (dir.tdir_type == TiffType.SHORT) { // Handle short -> int expansion. short[] dp = new short[dir.tdir_count]; status = fetchShortArray(dir, dp); if (status) { for (int i = 0; i < nstrips && i < dir.tdir_count; i++) { lpp[i] = dp[i]; } } } else if (nstrips != dir.tdir_count) { // Special case to correct length int[] dp = new int[dir.tdir_count]; status = fetchLongArray(dir, dp); if (status) { for (int i = 0; i < nstrips && i < dir.tdir_count; i++) { lpp[i] = dp[i]; } } } else { status = fetchLongArray(dir, lpp); } return(status); }
/// <summary> /// Advance to next tiff directory within file /// </summary> /// <param name="nextdir">Start location of next directory to try and advance to /// This will be updated with location of next directory if found</param> /// <param name="off">Offset of the end of the directory, right before the offset of the following directory is given</param> /// <param name="dircount">Numbers of directories in this IFD</param> /// <returns>True if next directory was found and nextdir was updated</returns> private bool advanceDirectory(ref ulong nextdir, out long off, out ulong dircount) { off = 0; dircount = 0; const string module = "advanceDirectory"; //Number of directories in this header if (!seekOK((long)nextdir) || !readDirCountOK(out dircount, m_header.tiff_version == TIFF_BIGTIFF_VERSION)) { ErrorExt(this, m_clientdata, module, "{0}: Error fetching directory count", m_name); return(false); } if ((m_flags & TiffFlags.SWAB) == TiffFlags.SWAB) { SwabBigTiffValue(ref dircount, m_header.tiff_version == TIFF_BIGTIFF_VERSION, true); } //The location of the end of the directory off = (long)seekFile((long)dircount * TiffDirEntry.SizeInBytes(m_header.tiff_version == TIFF_BIGTIFF_VERSION), SeekOrigin.Current); if (m_header.tiff_version == TIFF_BIGTIFF_VERSION) { if (!readUlongOK(out nextdir)) { ErrorExt(this, m_clientdata, module, "{0}: Error fetching directory link", m_name); return(false); } } else { //Get start location of next directory uint tempNextDir; if (!readUIntOK(out tempNextDir)) { ErrorExt(this, m_clientdata, module, "{0}: Error fetching directory link", m_name); return(false); } nextdir = tempNextDir; } if ((m_flags & TiffFlags.SWAB) == TiffFlags.SWAB) { SwabBigTiffValue(ref nextdir, m_header.tiff_version == TIFF_BIGTIFF_VERSION, false); } return(true); }
/// <summary> /// Setups a directory entry with either a SHORT or LONG type /// according to the value. /// </summary> private void setupShortLong(TiffTag tag, ref TiffDirEntry dir, int v) { dir.tdir_tag = tag; dir.tdir_count = 1; if (v > 0xffffL) { dir.tdir_type = TiffType.LONG; dir.tdir_offset = (uint)v; } else { dir.tdir_type = TiffType.SHORT; dir.tdir_offset = insertData(TiffType.SHORT, v); } }
private bool writeRational(TiffType type, TiffTag tag, ref TiffDirEntry dir, float v) { dir.tdir_tag = tag; dir.tdir_type = type; dir.tdir_count = 1; float[] a = new float[1]; a[0] = v; if (!writeRationalArray(ref dir, a)) { return(false); } return(true); }
/// <summary> /// Writes a contiguous directory item. /// </summary> private bool writeData(ref TiffDirEntry dir, byte[] buffer, int count) { dir.tdir_offset = m_dataoff; count = (int)dir.tdir_count * DataWidth(dir.tdir_type); if (seekOK(dir.tdir_offset) && writeOK(buffer, 0, count)) { m_dataoff += (uint)((count + 1) & ~1); return(true); } ErrorExt(this, m_clientdata, m_name, "Error writing data for field \"{0}\"", FieldWithTag(dir.tdir_tag).Name); return(false); }
private bool writeData(ref TiffDirEntry dir, int[] cp, int cc) { if ((m_flags & TiffFlags.SWAB) == TiffFlags.SWAB) { SwabArrayOfLong(cp, cc); } int byteCount = cc * sizeof(int); byte[] bytes = new byte [byteCount]; IntsToByteArray(cp, 0, cc, bytes, 0); bool res = writeData(ref dir, bytes, byteCount); return(res); }
/* * Setup a directory entry that references a samples/pixel array of ``type'' * values and (potentially) write the associated indirect values. The source * data from GetField() for the specified tag must be returned as double. */ private bool writePerSampleAnys(TiffType type, TiffTag tag, ref TiffDirEntry dir) { double[] w = new double [m_dir.td_samplesperpixel]; FieldValue[] result = GetField(tag); double v = result[0].ToDouble(); for (short i = 0; i < m_dir.td_samplesperpixel; i++) { w[i] = v; } bool status = writeAnyArray(type, tag, ref dir, m_dir.td_samplesperpixel, w); return(status); }
/* * Convert numerator+denominator to float. */ private bool cvtRational(TiffDirEntry dir, int num, int denom, out float rv) { if (denom == 0) { ErrorExt(this, m_clientdata, m_name, "{0}: Rational with zero denominator (num = {1})", FieldWithTag(dir.tdir_tag).Name, num); rv = float.NaN; return(false); } else { rv = ((float)num / (float)denom); return(true); } }
/// <summary> /// Write/copy data associated with an ASCII or opaque tag value. /// </summary> private bool writeByteArray(ref TiffDirEntry dir, byte[] cp) { if (dir.tdir_count <= 4) { if (m_header.tiff_magic == TIFF_BIGENDIAN) { dir.tdir_offset = (uint)(cp[0] << 24); if (dir.tdir_count >= 2) { dir.tdir_offset |= (uint)(cp[1] << 16); } if (dir.tdir_count >= 3) { dir.tdir_offset |= (uint)(cp[2] << 8); } if (dir.tdir_count == 4) { dir.tdir_offset |= cp[3]; } } else { dir.tdir_offset = cp[0]; if (dir.tdir_count >= 2) { dir.tdir_offset |= (uint)(cp[1] << 8); } if (dir.tdir_count >= 3) { dir.tdir_offset |= (uint)(cp[2] << 16); } if (dir.tdir_count == 4) { dir.tdir_offset |= (uint)(cp[3] << 24); } } return(true); } return(writeData(ref dir, cp, dir.tdir_count)); }
/// <summary> /// Fetches and sets the RefBlackWhite tag. /// </summary> private bool fetchRefBlackWhite(TiffDirEntry dir) { // some OJPEG images specify Reference BlackWhite as array of longs // // so, we'll try to read value as float array and check them // if read was successfull and there is at least one value greater // then 1.0 then ok, return value just read. // // if read failed or all values are less then or equal to 1.0 then // try once again but read as long array this time. if (dir.tdir_type == TiffType.RATIONAL) { bool res = fetchNormalTag(dir); if (res) { for (int i = 0; i < m_dir.td_refblackwhite.Length; i++) { if (m_dir.td_refblackwhite[i] > 1) { return(true); } } } } // Handle LONG's for backward compatibility. dir.tdir_type = TiffType.LONG; int[] cp = new int [dir.tdir_count]; bool ok = fetchLongArray(dir, cp); dir.tdir_type = TiffType.RATIONAL; if (ok) { float[] fp = new float [dir.tdir_count]; for (int i = 0; i < dir.tdir_count; i++) { fp[i] = (float)cp[i]; } ok = SetField(dir.tdir_tag, fp); } return(ok); }
/// <summary> /// Fetch an array of SHORT or SSHORT values. /// </summary> private bool fetchShortArray(TiffDirEntry dir, short[] v) { if (dir.tdir_count <= 2) { int count = dir.tdir_count; if (m_header.tiff_magic == TIFF_BIGENDIAN) { if (count == 2) { v[1] = (short)(dir.tdir_offset & 0xffff); } if (count >= 1) { v[0] = (short)(dir.tdir_offset >> 16); } } else { if (count == 2) { v[1] = (short)(dir.tdir_offset >> 16); } if (count >= 1) { v[0] = (short)(dir.tdir_offset & 0xffff); } } return(true); } int cc = dir.tdir_count * sizeof(short); byte[] b = new byte[cc]; int read = fetchData(dir, b); if (read != 0) { Buffer.BlockCopy(b, 0, v, 0, b.Length); } return(read != 0); }