add support for reading first page of an uncompressed TIFF image (it's a start...)

This commit is contained in:
Michael Becker 2020-06-17 23:29:15 -04:00
parent 0151b48216
commit 1c842411ff
No known key found for this signature in database
GPG Key ID: 506F54899E2BFED7
15 changed files with 1449 additions and 0 deletions

View File

@ -0,0 +1,29 @@
<?xml version="1.0" encoding="utf-8" ?>
<UniversalEditor Version="4.0">
<Associations>
<Association>
<Filters>
<Filter Title="Tag Image File Format (TIFF) image">
<FileNameFilters>
<FileNameFilter>*.tif</FileNameFilter>
<FileNameFilter>*.tiff</FileNameFilter>
</FileNameFilters>
<MagicByteSequences>
<MagicByteSequence>
<MagicByte Type="String">II</MagicByte>
</MagicByteSequence>
<MagicByteSequence>
<MagicByte Type="String">MM</MagicByte>
</MagicByteSequence>
</MagicByteSequences>
</Filter>
</Filters>
<ObjectModels>
<ObjectModel TypeName="UniversalEditor.ObjectModels.Multimedia.Picture.Collection.PictureCollectionObjectModel" />
</ObjectModels>
<DataFormats>
<DataFormat TypeName="UniversalEditor.DataFormats.Multimedia.Picture.TIFF.TIFFDataFormat" />
</DataFormats>
</Association>
</Associations>
</UniversalEditor>

View File

@ -743,6 +743,7 @@
<Content Include="Editors\NewWorldComputing\Map\MapEditor.glade" />
<Content Include="Editors\Multimedia\PictureCollection\PictureCollectionEditor.glade" />
<Content Include="Editors\Multimedia\PictureCollection\Dialogs\AnimationPropertiesDialog.glade" />
<Content Include="Extensions\GraphicDesigner\Associations\Picture\TIFF.uexml" />
</ItemGroup>
<ItemGroup>
<Content Include="Configuration\Application.upl" />

View File

@ -0,0 +1,45 @@
//
// TIFFCompression.cs
//
// Author:
// Michael Becker <alcexhim@gmail.com>
//
// Copyright (c) 2020 Mike Becker's Software
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
using System;
namespace UniversalEditor.DataFormats.Multimedia.Picture.TIFF
{
public enum TIFFCompression : ushort
{
/// <summary>
/// No compression, but pack data into bytes as tightly as possible, leaving no unused bits (except at the end of a row). The component values are stored as an array of
/// type BYTE. Each scan line (row) is padded to the next BYTE boundary.
/// </summary>
None = 0x01,
/// <summary>
/// CCITT Group 3 1-Dimensional Modified Huffman run length encoding.
/// </summary>
RunLengthEncoding = 0x02,
Group3Fax = 0x03,
Group4Fax = 0x04,
LZW = 0x05,
JPEG = 0x06,
Deflate = 0x08,
/// <summary>
/// PackBits compression, a simple byte-oriented run length scheme.
/// </summary>
PackBits = 32773
}
}

View File

@ -0,0 +1,177 @@
//
// TIFFDataFormat.cs
//
// Author:
// Michael Becker <alcexhim@gmail.com>
//
// Copyright (c) 2020 Mike Becker's Software
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
using System;
using System.Collections.Generic;
using UniversalEditor.IO;
using UniversalEditor.ObjectModels.Multimedia.Picture;
using UniversalEditor.ObjectModels.Multimedia.Picture.Collection;
namespace UniversalEditor.DataFormats.Multimedia.Picture.TIFF
{
public class TIFFDataFormat : TIFFDataFormatBase
{
private static DataFormatReference _dfr = null;
protected override DataFormatReference MakeReferenceInternal()
{
if (_dfr == null)
{
_dfr = base.MakeReferenceInternal();
_dfr.Type = GetType();
_dfr.Capabilities.Clear();
_dfr.Capabilities.Add(typeof(PictureCollectionObjectModel), DataFormatCapabilities.All);
_dfr.ExportOptions.Add(new CustomOptionChoice("CompressionMethod", "Compression _method", true, new CustomOptionFieldChoice[]
{
new CustomOptionFieldChoice("None", TIFFCompression.None),
new CustomOptionFieldChoice("Run-length encoding", TIFFCompression.RunLengthEncoding),
new CustomOptionFieldChoice("Group 3 fax", TIFFCompression.Group3Fax),
new CustomOptionFieldChoice("Group 4 fax", TIFFCompression.Group4Fax),
new CustomOptionFieldChoice("LZW", TIFFCompression.LZW),
new CustomOptionFieldChoice("JPEG", TIFFCompression.JPEG),
new CustomOptionFieldChoice("Deflate", TIFFCompression.Deflate),
new CustomOptionFieldChoice("PackBits", TIFFCompression.PackBits)
}));
}
return _dfr;
}
public TIFFCompression CompressionMethod { get; set; } = TIFFCompression.None;
protected override void BeforeLoadInternal(Stack<ObjectModel> objectModels)
{
base.BeforeLoadInternal(objectModels);
objectModels.Push(new TIFFObjectModelBase());
}
protected override void AfterLoadInternal(Stack<ObjectModel> objectModels)
{
base.AfterLoadInternal(objectModels);
TIFFObjectModelBase tiff = (objectModels.Pop() as TIFFObjectModelBase);
PictureCollectionObjectModel picc = (objectModels.Pop() as PictureCollectionObjectModel);
Reader reader = Accessor.Reader;
for (int i = 0; i < tiff.ImageFileDirectories.Count; i++)
{
PictureObjectModel pic = new PictureObjectModel();
TIFFImageFileDirectory ifd = tiff.ImageFileDirectories[i];
TIFFImageFileDirectoryEntry entryWidth = ifd.Entries.GetByTag(TIFFTag.ImageWidth);
TIFFImageFileDirectoryEntry entryHeight = ifd.Entries.GetByTag(TIFFTag.ImageLength);
if (entryWidth == null || entryHeight == null)
{
Console.WriteLine("tiff: skipping invalid IFD which does not contain both ImageWidth and ImageLength fields");
continue;
}
long width = entryWidth.GetNumericValue(), height = entryHeight.GetNumericValue();
TIFFImageFileDirectoryEntry entryCompression = ifd.Entries.GetByTag(TIFFTag.Compression);
if (entryCompression != null)
{
CompressionMethod = (TIFFCompression)entryCompression.GetNumericValue();
}
pic.Width = (int)width;
pic.Height = (int)height;
TIFFImageFileDirectoryEntry entryRowsPerStrip = ifd.Entries.GetByTag(TIFFTag.RowsPerStrip);
// The number of rows in each strip (except possibly the last strip.)
// For example, if ImageLength is 24, and RowsPerStrip is 10, then there are 3 strips, with 10 rows in the first strip, 10 rows in the second strip,
// and 4 rows in the third strip. (The data in the last strip is not padded with 6 extra rows of dummy data.)
long rowsPerStrip = entryRowsPerStrip.GetNumericValue();
long rpsEvenLength = (long)((double)pic.Height / rowsPerStrip);
long remaining = (pic.Height - (rpsEvenLength * rowsPerStrip));
TIFFImageFileDirectoryEntry entryStripOffsets = ifd.Entries.GetByTag(TIFFTag.StripOffsets);
if (entryStripOffsets == null)
{
continue;
}
uint[] stripOffsets = (uint[])entryStripOffsets.Value;
// 288000 bytes in strip
// 288000 / 128 rows per strip = 2250 bytes per row
// 2250 / 750 (Width) = 3 bytes per pixel
int yoffset = 0;
for (uint j = 0; j < stripOffsets.Length; j++)
{
// for each strip
uint stripOffset = stripOffsets[j];
reader.Seek(stripOffset, SeekOrigin.Begin);
long rowcount = rowsPerStrip;
if (j == stripOffsets.Length - 1 && remaining > 0)
{
rowcount = remaining;
}
for (int y = 0; y < rowcount; y++)
{
for (int x = 0; x < pic.Width; x++)
{
byte pixelR = reader.ReadByte();
byte pixelG = reader.ReadByte();
byte pixelB = reader.ReadByte();
pic.SetPixel(MBS.Framework.Drawing.Color.FromRGBAByte(pixelR, pixelG, pixelB), x, yoffset + y);
}
}
yoffset += (int)rowcount;
reader.Align(4);
}
picc.Pictures.Add(pic);
}
}
protected override void BeforeSaveInternal(Stack<ObjectModel> objectModels)
{
base.BeforeSaveInternal(objectModels);
PictureCollectionObjectModel picc = (objectModels.Pop() as PictureCollectionObjectModel);
TIFFObjectModelBase tiff = new TIFFObjectModelBase();
for (int i = 0; i < picc.Pictures.Count; i++)
{
PictureObjectModel pic = picc.Pictures[i];
TIFFImageFileDirectory ifd = new TIFFImageFileDirectory();
ifd.Entries.Add(TIFFTag.ImageWidth, pic.Width);
ifd.Entries.Add(TIFFTag.ImageLength, pic.Height);
ifd.Entries.Add(TIFFTag.Compression, (ushort)CompressionMethod);
ifd.Entries.Add(TIFFTag.RowsPerStrip, 128);
tiff.ImageFileDirectories.Add(ifd);
}
objectModels.Push(tiff);
}
}
}

View File

@ -0,0 +1,482 @@
//
// TIFFDataFormatBase.cs
//
// Author:
// Michael Becker <alcexhim@gmail.com>
//
// Copyright (c) 2020 Mike Becker's Software
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
using System;
using System.Collections.Generic;
using UniversalEditor.Accessors;
using UniversalEditor.IO;
namespace UniversalEditor.DataFormats.Multimedia.Picture.TIFF
{
public class TIFFDataFormatBase : DataFormat
{
private static DataFormatReference _dfr = null;
protected override DataFormatReference MakeReferenceInternal()
{
if (_dfr == null)
{
_dfr = base.MakeReferenceInternal();
_dfr.Capabilities.Add(typeof(TIFFObjectModelBase), DataFormatCapabilities.All);
_dfr.ExportOptions.Add(new CustomOptionChoice("Endianness", "_Endianness", true, new CustomOptionFieldChoice[]
{
new CustomOptionFieldChoice("Little-endian", Endianness.LittleEndian),
new CustomOptionFieldChoice("Big-endian", Endianness.BigEndian)
}));
}
return _dfr;
}
public Endianness Endianness { get; set; } = Endianness.LittleEndian;
protected override void LoadInternal(ref ObjectModel objectModel)
{
TIFFObjectModelBase tiff = (objectModel as TIFFObjectModelBase);
if (tiff == null) throw new ObjectModelNotSupportedException();
Reader reader = Accessor.Reader;
string signature1 = reader.ReadFixedLengthString(2);
if (signature1 == "II")
{
reader.Endianness = Endianness.LittleEndian;
}
else if (signature1 == "MM")
{
reader.Endianness = Endianness.BigEndian;
}
else
{
throw new InvalidDataFormatException("file does not begin with either 'II' or 'MM'");
}
Endianness = reader.Endianness;
ushort signature2 = reader.ReadUInt16();
if (signature2 != 42)
{
throw new InvalidDataFormatException("incorrect answer to the ultimate question of life, the universe, and everything (expected 42)");
}
while (!reader.EndOfStream)
{
// The offset (in bytes) of the first IFD. The directory may be at any location in the
// file after the header but must begin on a word boundary.In particular, an Image
// File Directory may follow the image data it describes. Readers must follow the
// pointers wherever they may lead.
uint IFDoffset = reader.ReadUInt32();
if (IFDoffset == 0)
break;
reader.Seek(IFDoffset, SeekOrigin.Begin);
TIFFImageFileDirectory ifd = new TIFFImageFileDirectory();
ushort directoryEntryCount = reader.ReadUInt16();
ReadIFDEntries(reader, ifd, directoryEntryCount);
tiff.ImageFileDirectories.Add(ifd);
}
}
private void ReadIFDEntries(Reader reader, TIFFImageFileDirectory ifd, ushort count)
{
// There must be at least 1 IFD in a TIFF file and each IFD must have at least one entry.
for (ushort i = 0; i < count; i++)
{
ifd.Entries.Add(ReadIFDEntry(reader));
}
}
private TIFFImageFileDirectoryEntry ReadIFDEntry(Reader reader)
{
// An Image File Directory (IFD) consists of a 2-byte count of the number of directory
// entries(i.e., the number of fields), followed by a sequence of 12 - byte field
// entries, followed by a 4 - byte offset of the next IFD(or 0 if none). (Do not forget to
// write the 4 bytes of 0 after the last IFD.)
TIFFImageFileDirectoryEntry entry = new TIFFImageFileDirectoryEntry();
entry.Tag = (TIFFTag)reader.ReadUInt16();
entry.Type = (TIFFDataType)reader.ReadUInt16();
entry.Count = reader.ReadUInt32();
entry.OffsetOrValue = reader.ReadUInt32();
byte[] value = BitConverter.GetBytes(entry.OffsetOrValue);
long ofs = reader.Accessor.Position;
switch (entry.Type)
{
case TIFFDataType.Ascii:
{
if (entry.Count <= 4)
{
entry.Value = System.Text.Encoding.Default.GetString(value);
}
else
{
reader.Accessor.Position = entry.OffsetOrValue;
entry.Value = reader.ReadFixedLengthString((int)entry.Count);
}
break;
}
case TIFFDataType.Undefined:
{
if (entry.Count <= 4)
{
entry.Value = value;
}
else
{
reader.Accessor.Position = entry.OffsetOrValue;
entry.Value = reader.ReadBytes((int)entry.Count);
}
break;
}
case TIFFDataType.Byte:
case TIFFDataType.SignedByte:
{
if (entry.Count == 1)
{
entry.Value = value[0];
break;
}
else if (entry.Count <= 4)
{
byte[] val = new byte[entry.Count];
for (int i = 0; i < entry.Count; i++)
{
val[i] = value[i];
}
entry.Value = val;
}
else
{
reader.Accessor.Position = entry.OffsetOrValue;
entry.Value = reader.ReadBytes((int)entry.Count);
}
break;
}
case TIFFDataType.Short:
{
if (entry.Count == 1)
{
entry.Value = BitConverter.ToUInt16(value, 0);
}
else if (entry.Count == 2)
{
entry.Value = new ushort[] { BitConverter.ToUInt16(value, 0), BitConverter.ToUInt16(value, 2) };
}
else
{
reader.Accessor.Position = entry.OffsetOrValue;
entry.Value = reader.ReadUInt16Array((int)entry.Count);
}
break;
}
case TIFFDataType.SignedShort:
{
if (entry.Count == 1)
{
entry.Value = BitConverter.ToInt16(value, 0);
}
else if (entry.Count == 2)
{
entry.Value = new short[] { BitConverter.ToInt16(value, 0), BitConverter.ToInt16(value, 2) };
}
else
{
reader.Accessor.Position = entry.OffsetOrValue;
entry.Value = reader.ReadInt16Array((int)entry.Count);
}
break;
}
case TIFFDataType.Long:
{
if (entry.Count == 1)
{
entry.Value = BitConverter.ToUInt32(value, 0);
}
else
{
reader.Accessor.Position = entry.OffsetOrValue;
entry.Value = reader.ReadUInt32Array((int)entry.Count);
}
break;
}
case TIFFDataType.SignedLong:
{
if (entry.Count == 1)
{
entry.Value = BitConverter.ToInt32(value, 0);
}
else
{
reader.Accessor.Position = entry.OffsetOrValue;
entry.Value = reader.ReadInt32Array((int)entry.Count);
}
break;
}
}
reader.Accessor.Position = ofs;
return entry;
}
protected override void SaveInternal(ObjectModel objectModel)
{
TIFFObjectModelBase tiff = (objectModel as TIFFObjectModelBase);
if (tiff == null) throw new ObjectModelNotSupportedException();
Writer writer = Accessor.Writer;
writer.Endianness = Endianness;
switch (Endianness)
{
case Endianness.LittleEndian:
{
writer.WriteFixedLengthString("II");
break;
}
case Endianness.BigEndian:
{
writer.WriteFixedLengthString("MM");
break;
}
default:
{
throw new NotSupportedException();
}
}
writer.WriteUInt16(42); // signature2
uint IFDoffset = 8;
for (int i = 0; i < tiff.ImageFileDirectories.Count; i++)
{
writer.WriteUInt32(IFDoffset);
TIFFImageFileDirectory ifd = tiff.ImageFileDirectories[i];
WriteIFDEntries(writer, ifd);
IFDoffset = (uint)writer.Accessor.Position + 4;
}
}
private void WriteIFDEntries(Writer writer, TIFFImageFileDirectory ifd)
{
// There must be at least 1 IFD in a TIFF file and each IFD must have at least one entry.
writer.WriteUInt16((ushort)ifd.Entries.Count);
List<TIFFImageFileDirectoryEntry> ifdentries = new List<TIFFImageFileDirectoryEntry>(ifd.Entries);
ifdentries.Sort();
MemoryAccessor maOverflow = new MemoryAccessor();
Writer overflowWriter = maOverflow.Writer;
long overflowWriterOffset = Accessor.Position + ((ushort)ifdentries.Count * 12);
for (ushort i = 0; i < (ushort)ifdentries.Count; i++)
{
WriteIFDEntry(writer, ifdentries[i], overflowWriter, overflowWriterOffset);
}
writer.WriteBytes(maOverflow.ToArray());
}
private void WriteIFDEntry(Writer writer, TIFFImageFileDirectoryEntry entry, Writer overflowWriter, long overflowWriterOffset)
{
// An Image File Directory (IFD) consists of a 2-byte count of the number of directory
// entries(i.e., the number of fields), followed by a sequence of 12 - byte field
// entries, followed by a 4 - byte offset of the next IFD(or 0 if none). (Do not forget to
// write the 4 bytes of 0 after the last IFD.)
long overflowOffset = overflowWriter.Accessor.Position;
if (entry.Value is string)
{
entry.Type = TIFFDataType.Ascii;
string value = (string)entry.Value;
entry.Count = (uint)value.Length;
if (value.Length <= 4)
{
entry.OffsetOrValue = BitConverter.ToUInt32(System.Text.Encoding.Default.GetBytes(value), 0);
}
else
{
entry.OffsetOrValue = (uint)(overflowWriterOffset + overflowWriter.Accessor.Position);
overflowWriter.WriteFixedLengthString((string)entry.Value);
}
}
else if (entry.Value is byte[] && entry.Type == TIFFDataType.Undefined)
{
byte[] value = (byte[])entry.Value;
entry.Count = (uint)value.Length;
if (value.Length <= 4)
{
entry.OffsetOrValue = BitConverter.ToUInt32(value, 0);
}
else
{
entry.OffsetOrValue = (uint)(overflowWriterOffset + overflowWriter.Accessor.Position);
overflowWriter.WriteBytes(value);
}
}
else if ((entry.Value is byte || entry.Value is sbyte || entry.Value is byte[] || entry.Value is sbyte[]) && (entry.Type == TIFFDataType.Byte || entry.Type == TIFFDataType.SignedByte))
{
if (entry.Value is byte)
{
entry.Type = TIFFDataType.Byte;
entry.Count = 1;
entry.OffsetOrValue = (byte)entry.Value;
}
else if (entry.Value is byte[] && ((byte[])entry.Value).Length <= 4)
{
entry.Type = TIFFDataType.Byte;
byte[] value = (byte[])entry.Value;
entry.Count = (uint)value.Length;
entry.OffsetOrValue = BitConverter.ToUInt32(value, 0);
}
else if (entry.Value is byte[])
{
entry.Type = TIFFDataType.Byte;
entry.Count = (uint)((byte[])entry.Value).Length;
entry.OffsetOrValue = (uint)(overflowWriterOffset + overflowWriter.Accessor.Position);
overflowWriter.WriteBytes((byte[])entry.Value);
}
else if (entry.Value is sbyte)
{
entry.Type = TIFFDataType.SignedByte;
entry.Count = 1;
entry.OffsetOrValue = (uint)(sbyte)entry.Value;
}
else if (entry.Value is sbyte[] && ((sbyte[])entry.Value).Length <= 4)
{
entry.Type = TIFFDataType.SignedByte;
sbyte[] value = (sbyte[])entry.Value;
entry.Count = (uint)value.Length;
entry.OffsetOrValue = BitConverter.ToUInt32((byte[])(Array)value, 0);
}
else if (entry.Value is sbyte[])
{
entry.Type = TIFFDataType.SignedByte;
entry.Count = (uint)((sbyte[])entry.Value).Length;
entry.OffsetOrValue = (uint)(overflowWriterOffset + overflowWriter.Accessor.Position);
overflowWriter.WriteSBytes((sbyte[])entry.Value);
}
}
else if (entry.Value is ushort || entry.Value is ushort[])
{
entry.Type = TIFFDataType.Short;
if (entry.Value is ushort)
{
entry.Count = 1;
entry.OffsetOrValue = (ushort)entry.Value;
}
else if (entry.Value is ushort[] && ((ushort[])entry.Value).Length == 2)
{
entry.Count = 2;
byte[] data = new byte[4];
ushort[] items = (ushort[])entry.Value;
if (items.Length != 2)
throw new InvalidOperationException();
byte[] u1 = BitConverter.GetBytes(items[0]);
byte[] u2 = BitConverter.GetBytes(items[1]);
Array.Copy(u1, 0, data, 0, u1.Length);
Array.Copy(u2, 0, data, 2, u2.Length);
entry.OffsetOrValue = BitConverter.ToUInt32(data, 0);
}
else
{
entry.Count = (uint)((ushort[])entry.Value).Length;
entry.OffsetOrValue = (uint)(overflowWriterOffset + overflowWriter.Accessor.Position);
overflowWriter.WriteUInt16Array((ushort[])entry.Value);
}
}
else if (entry.Value is short || entry.Value is short[])
{
entry.Type = TIFFDataType.SignedShort;
if (entry.Value is short)
{
entry.Count = 1;
entry.OffsetOrValue = (uint)(short)entry.Value;
}
else if (entry.Value is short[] && ((short[])entry.Value).Length == 2)
{
entry.Count = 2;
byte[] data = new byte[4];
short[] items = (short[])entry.Value;
if (items.Length != 2)
throw new InvalidOperationException();
byte[] u1 = BitConverter.GetBytes(items[0]);
byte[] u2 = BitConverter.GetBytes(items[1]);
Array.Copy(u1, 0, data, 0, u1.Length);
Array.Copy(u2, 0, data, 2, u2.Length);
entry.OffsetOrValue = BitConverter.ToUInt32(data, 0);
}
else
{
entry.Count = (uint)((short[])entry.Value).Length;
entry.OffsetOrValue = (uint)(overflowWriterOffset + overflowWriter.Accessor.Position);
overflowWriter.WriteInt16Array((short[])entry.Value);
}
}
else if (entry.Value is uint || entry.Value is uint[])
{
entry.Type = TIFFDataType.Long;
if (entry.Value is uint)
{
entry.Count = 1;
entry.OffsetOrValue = (uint)entry.Value;
}
else if (entry.Value is uint[])
{
entry.Count = (uint)((uint[])entry.Value).Length;
entry.OffsetOrValue = (uint)(overflowWriterOffset + overflowWriter.Accessor.Position);
overflowWriter.WriteUInt32Array((uint[])entry.Value);
}
}
else if (entry.Value is int || entry.Value is int[])
{
entry.Type = TIFFDataType.SignedLong;
if (entry.Value is int)
{
entry.Count = 1;
entry.OffsetOrValue = (uint)((int)entry.Value);
}
else if (entry.Value is int[])
{
entry.Count = (uint)((int[])entry.Value).Length;
entry.OffsetOrValue = (uint)(overflowWriterOffset + overflowWriter.Accessor.Position);
overflowWriter.WriteInt32Array((int[])entry.Value);
}
}
writer.WriteUInt16((ushort)entry.Tag);
writer.WriteUInt16((ushort)entry.Type);
writer.WriteUInt32(entry.Count);
writer.WriteUInt32(entry.OffsetOrValue);
}
}
}

View File

@ -0,0 +1,76 @@
//
// TIFFDataType.cs
//
// Author:
// Michael Becker <alcexhim@gmail.com>
//
// Copyright (c) 2020 Mike Becker's Software
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
using System;
namespace UniversalEditor.DataFormats.Multimedia.Picture.TIFF
{
public enum TIFFDataType : ushort
{
/// <summary>
/// 8-bit unsigned integer.
/// </summary>
Byte = 0x0001,
/// <summary>
/// 8-bit byte that contains a 7-bit ASCII code; the last byte must be NUL (binary zero).
/// </summary>
Ascii = 0x0002,
/// <summary>
/// 16-bit (2-byte) unsigned integer.
/// </summary>
Short = 0x0003,
/// <summary>
/// 32-bit (4-byte) unsigned integer.
/// </summary>
Long = 0x0004,
/// <summary>
/// Two <see cref="Long" />s: the first represents the numerator of a fraction; the second, the denominator.
/// </summary>
Rational = 0x0005,
/// <summary>
/// An 8-bit signed (twos-complement) integer. Added in TIFF 6.0.
/// </summary>
SignedByte = 0x0006,
/// <summary>
/// An 8-bit byte that may contain anything, depending on the definition of the field. Added in TIFF 6.0.
/// </summary>
Undefined = 0x0007,
/// <summary>
/// A 16-bit (2-byte) signed (twos-complement) integer. Added in TIFF 6.0.
/// </summary>
SignedShort = 0x0008,
/// <summary>
/// A 32-bit (4-byte) signed (twos-complement) integer. Added in TIFF 6.0.
/// </summary>
SignedLong = 0x0009,
/// <summary>
/// Two SLONGs: the first represents the numerator of a fraction, the second the denominator. Added in TIFF 6.0.
/// </summary>
SignedRational = 0x000A,
/// <summary>
/// Single precision (4-byte) IEEE format. Added in TIFF 6.0.
/// </summary>
Float = 0x000B,
/// <summary>
/// Double precision (8-byte) IEEE format. Added in TIFF 6.0.
/// </summary>
Double = 0x000C
}
}

View File

@ -0,0 +1,41 @@
//
// TIFFExtraSamplesType.cs
//
// Author:
// Michael Becker <alcexhim@gmail.com>
//
// Copyright (c) 2020 Mike Becker's Software
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
using System;
namespace UniversalEditor.DataFormats.Multimedia.Picture.TIFF
{
public enum TIFFExtraSamplesType : ushort
{
/// <summary>
/// Unspecified data
/// </summary>
Unspecified = 0x00,
/// <summary>
/// Associated alpha data (with pre-multiplied color). Note that including both unassociated and associated alpha is undefined because associated alpha specifies that
/// color components are pre-multiplied by the alpha component, while unassociated alpha specifies the opposite.
/// </summary>
AssociatedAlpha = 0x01,
/// <summary>
/// Transparency information that logically exists independent of an image; it is commonly called a soft matte. Note that including both unassociated and associated alpha
/// is undefined because associated alpha specifies that color components are pre-multiplied by the alpha component, while unassociated alpha specifies the opposite.
/// </summary>
UnassociatedAlpha = 0x02,
}
}

View File

@ -0,0 +1,40 @@
//
// TIFFFillOrder.cs
//
// Author:
// Michael Becker <alcexhim@gmail.com>
//
// Copyright (c) 2020 Mike Becker's Software
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
using System;
namespace UniversalEditor.DataFormats.Multimedia.Picture.TIFF
{
public enum TIFFFillOrder : ushort
{
/// <summary>
/// Pixels are arranged within a byte such that pixels with lower column values are stored in the higher-order bits of the byte. 1-bit uncompressed data example: Pixel 0
/// of a row is stored in the high-order bit of byte 0, pixel 1 is stored in the next-highest bit, ..., pixel 7 is stored in the low-order bit of byte 0, pixel 8 is
/// stored in the high-order bit of byte 1, and so on. CCITT 1-bit compressed data example: The high-order bit of the first compression code is stored in the high-order
/// bit of byte 0, the next-highest bit of the first compression code is stored in the next-highest bit of byte 0, and so on.
/// </summary>
Normal = 1,
/// <summary>
/// Pixels are arranged within a byte such that pixels with lower column values are stored in the lower-order bits of the byte. We recommend that FillOrder = 2 be used
/// only in special-purpose applications. It is easy and inexpensive for writers to reverse bit order by using a 256-byte lookup table. FillOrder = 2 should be used only
/// when BitsPerSample = 1 and the data is either uncompressed or compressed using CCITT 1D or 2D compression, to avoid potentially ambiguous situations.
/// </summary>
Reverse = 2
}
}

View File

@ -0,0 +1,44 @@
//
// TIFFImageFile.cs
//
// Author:
// Michael Becker <alcexhim@gmail.com>
//
// Copyright (c) 2020 Mike Becker's Software
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
using System;
namespace UniversalEditor.DataFormats.Multimedia.Picture.TIFF
{
public class TIFFImageFileDirectory : ICloneable
{
public class TIFFImageFileDirectoryCollection
: System.Collections.ObjectModel.Collection<TIFFImageFileDirectory>
{
}
public TIFFImageFileDirectoryEntry.TIFFImageFileDirectoryEntryCollection Entries { get; } = new TIFFImageFileDirectoryEntry.TIFFImageFileDirectoryEntryCollection();
public object Clone()
{
TIFFImageFileDirectory clone = new TIFFImageFileDirectory();
for (int i = 0; i < Entries.Count; i++)
{
clone.Entries.Add(Entries[i].Clone() as TIFFImageFileDirectoryEntry);
}
return clone;
}
}
}

View File

@ -0,0 +1,190 @@
//
// TIFFImageFileDirectory.cs
//
// Author:
// Michael Becker <alcexhim@gmail.com>
//
// Copyright (c) 2020 Mike Becker's Software
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
using System;
namespace UniversalEditor.DataFormats.Multimedia.Picture.TIFF
{
public class TIFFImageFileDirectoryEntry : ICloneable, IComparable<TIFFImageFileDirectoryEntry>
{
public class TIFFImageFileDirectoryEntryCollection
: System.Collections.ObjectModel.Collection<TIFFImageFileDirectoryEntry>
{
public TIFFImageFileDirectoryEntry GetByTag(TIFFTag tag)
{
for (int i = 0; i < Count; i++)
{
if (this[i].Tag == tag)
return this[i];
}
return null;
}
public TIFFImageFileDirectoryEntry Add(TIFFTag tag, int value)
{
if (value <= short.MaxValue)
{
return Add(tag, (short)value);
}
TIFFImageFileDirectoryEntry item = new TIFFImageFileDirectoryEntry();
item.Tag = tag;
item.Type = TIFFDataType.SignedLong;
item.Value = value;
item.Count = 1;
Add(item);
return item;
}
public TIFFImageFileDirectoryEntry Add(TIFFTag tag, short value)
{
TIFFImageFileDirectoryEntry item = new TIFFImageFileDirectoryEntry();
item.Tag = tag;
item.Type = TIFFDataType.SignedShort;
item.Value = value;
item.Count = 1;
Add(item);
return item;
}
public TIFFImageFileDirectoryEntry Add(TIFFTag tag, uint value)
{
if (value <= ushort.MaxValue)
{
return Add(tag, (ushort)value);
}
TIFFImageFileDirectoryEntry item = new TIFFImageFileDirectoryEntry();
item.Tag = tag;
item.Type = TIFFDataType.Long;
item.Value = value;
item.Count = 1;
Add(item);
return item;
}
public TIFFImageFileDirectoryEntry Add(TIFFTag tag, ushort value)
{
TIFFImageFileDirectoryEntry item = new TIFFImageFileDirectoryEntry();
item.Tag = tag;
item.Type = TIFFDataType.Short;
item.Value = value;
item.Count = 1;
Add(item);
return item;
}
public TIFFImageFileDirectoryEntry Add(TIFFTag tag, int[] values)
{
TIFFImageFileDirectoryEntry item = new TIFFImageFileDirectoryEntry();
item.Tag = tag;
item.Type = TIFFDataType.SignedLong;
item.Value = values;
item.Count = (uint)values.Length;
Add(item);
return item;
}
public TIFFImageFileDirectoryEntry Add(TIFFTag tag, short[] values)
{
TIFFImageFileDirectoryEntry item = new TIFFImageFileDirectoryEntry();
item.Tag = tag;
item.Type = TIFFDataType.SignedShort;
item.Value = values;
item.Count = (uint)values.Length;
Add(item);
return item;
}
public TIFFImageFileDirectoryEntry Add(TIFFTag tag, uint[] values)
{
TIFFImageFileDirectoryEntry item = new TIFFImageFileDirectoryEntry();
item.Tag = tag;
item.Type = TIFFDataType.Long;
item.Value = values;
item.Count = (uint)values.Length;
Add(item);
return item;
}
public TIFFImageFileDirectoryEntry Add(TIFFTag tag, ushort[] values)
{
TIFFImageFileDirectoryEntry item = new TIFFImageFileDirectoryEntry();
item.Tag = tag;
item.Type = TIFFDataType.Short;
item.Value = values;
item.Count = (uint)values.Length;
Add(item);
return item;
}
}
public long GetNumericValue()
{
switch (Type)
{
case TIFFDataType.Byte: return (byte)Value;
case TIFFDataType.Short: return (ushort)Value;
case TIFFDataType.Long: return (uint)Value;
case TIFFDataType.SignedByte: return (sbyte)Value;
case TIFFDataType.SignedShort: return (short)Value;
case TIFFDataType.SignedLong: return (int)Value;
}
throw new NotSupportedException();
}
/// <summary>
/// The Tag that identifies the field.
/// </summary>
public TIFFTag Tag { get; set; }
/// <summary>
/// The field Type.
/// </summary>
public TIFFDataType Type { get; set; }
/// <summary>
/// The number of values, Count of the indicated Type.
/// </summary>
public uint Count { get; set; } = 1;
/// <summary>
/// The Value Offset, the file offset (in bytes) of the Value for the field. The Value is expected to begin on a word boundary; the corresponding
/// Value Offset will thus be an even number. This file offset may point anywhere in the file, even after the image data.
/// </summary>
/// <remarks>
/// To save time and space the Value Offset contains the Value instead of pointing to the Value IF AND ONLY IF the Value fits into 4 bytes. If the Value is shorter
/// than 4 bytes, it is left-justified within the 4-byte Value Offset, i.e., stored in the lower-numbered bytes. Whether the Value fits within 4 bytes is determined by
/// the Type and Count of the field.
/// </remarks>
public uint OffsetOrValue { get; set; }
public object Value { get; set; }
public override string ToString()
{
return String.Format("{0} ({1} x {2}) @ {3}", Tag, Type, Count, OffsetOrValue);
}
public object Clone()
{
TIFFImageFileDirectoryEntry clone = new TIFFImageFileDirectoryEntry();
clone.Tag = Tag;
clone.Type = Type;
clone.Count = Count;
clone.OffsetOrValue = OffsetOrValue;
return clone;
}
public int CompareTo(TIFFImageFileDirectoryEntry other)
{
return Tag.CompareTo(other.Tag);
}
}
}

View File

@ -0,0 +1,44 @@
//
// TIFFObjectModelBase.cs
//
// Author:
// Michael Becker <alcexhim@gmail.com>
//
// Copyright (c) 2020 Mike Becker's Software
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
using System;
namespace UniversalEditor.DataFormats.Multimedia.Picture.TIFF
{
public class TIFFObjectModelBase : ObjectModel
{
public TIFFImageFileDirectory.TIFFImageFileDirectoryCollection ImageFileDirectories { get; } = new TIFFImageFileDirectory.TIFFImageFileDirectoryCollection();
public override void Clear()
{
ImageFileDirectories.Clear();
}
public override void CopyTo(ObjectModel where)
{
TIFFObjectModelBase clone = (where as TIFFObjectModelBase);
if (clone == null) throw new ObjectModelNotSupportedException();
for (int i = 0; i < ImageFileDirectories.Count; i++)
{
clone.ImageFileDirectories.Add(ImageFileDirectories[i].Clone() as TIFFImageFileDirectory);
}
}
}
}

View File

@ -0,0 +1,48 @@
//
// TIFFPhotometricInterpretation.cs
//
// Author:
// Michael Becker <alcexhim@gmail.com>
//
// Copyright (c) 2020 Mike Becker's Software
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
namespace UniversalEditor.DataFormats.Multimedia.Picture.TIFF
{
public enum TIFFPhotometricInterpretation
{
/// <summary>
/// For bilevel and grayscale images: 0 is imaged as white. The maximum value is imaged as black. This is the normal value for Compression = 2.
/// </summary>
WhiteIsZero = 0x00,
/// <summary>
/// For bilevel and grayscale images: 0 is imaged as black. The maximum value is imaged as white. If this value is specified for Compression = 2, the
/// image should display and print reversed.
/// </summary>
BlackIsZero = 0x01,
/// <summary>
/// Indicates a full-color image. Each component is 8 bits deep in a Baseline TIFF RGB image.
/// </summary>
RGB = 0x02,
/// <summary>
/// Indicates a Palette-color image.
/// </summary>
PaletteColor = 0x03,
TransparencyMask = 0x04,
CMYK = 0x05,
YCbCr = 0x06,
CIELab = 0x08
}
}

View File

@ -0,0 +1,33 @@
//
// TIFFResolutionUnit.cs
//
// Author:
// Michael Becker <alcexhim@gmail.com>
//
// Copyright (c) 2020 Mike Becker's Software
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
using System;
namespace UniversalEditor.DataFormats.Multimedia.Picture.TIFF
{
public enum TIFFResolutionUnit : ushort
{
/// <summary>
/// No absolute unit of measurement. Used for images that may have a non-square aspect ratio but no meaningful absolute dimensions.
/// </summary>
None = 0x01,
Inch = 0x02,
Centimeter = 0x03
}
}

View File

@ -0,0 +1,186 @@
//
// TIFFTag.cs
//
// Author:
// Michael Becker <alcexhim@gmail.com>
//
// Copyright (c) 2020 Mike Becker's Software
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
using System;
namespace UniversalEditor.DataFormats.Multimedia.Picture.TIFF
{
public enum TIFFTag
{
/// <summary>
/// SHORT or LONG. The number of columns in the image, i.e., the number of pixels per scanline.
/// </summary>
ImageWidth = 256,
/// <summary>
/// SHORT or LONG. The number of rows (sometimes described as scanlines) in the image.
/// </summary>
ImageLength = 257,
/// <summary>
/// SHORT. The number of bits per component. Allowable values for Baseline TIFF grayscale images are 4 and 8, allowing either 16 or 256 distinct shades of gray.
/// </summary>
BitsPerSample = 258,
/// <summary>
/// SHORT. See <see cref="TIFFCompression" />.
/// </summary>
Compression = 259,
/// <summary>
/// SHORT. See <see cref="TIFFPhotometricInterpretation" />.
/// </summary>
PhotometricInterpretation = 262,
/// <summary>
/// SHORT. The width of the dithering or halftoning matrix used to create a dithered or halftoned bilevel file.
/// </summary>
CellWidth = 264,
/// <summary>
/// SHORT. The length of the dithering or halftoning matrix used to create a dithered or halftoned bilevel file. This field should only be present if
/// <see cref="Threshholding"/> = 2.
/// </summary>
CellLength = 265,
/// <summary>
/// SHORT. The logical order of bits within a byte. See <see cref="TIFFFillOrder" />. Default is <see cref="TIFFFillOrder.Normal" />.
/// </summary>
FillOrder = 266,
/// <summary>
/// ASCII. The name of the document from which this image was scanned.
/// </summary>
/// <seealso cref="PageName" />
DocumentName = 269,
/// <summary>
/// SHORT or LONG. For each strip, the byte offset of that strip.
/// </summary>
StripOffsets = 273,
/// <summary>
/// SHORT. The orientation of the image with respect to the rows and columns.
/// </summary>
Orientation = 274,
/// <summary>
/// SHORT. The number of components per pixel. This number is 3 for RGB images, unless extra samples are present. See the ExtraSamples field for further information.
/// </summary>
SamplesPerPixel = 277,
/// <summary>
/// SHORT or LONG. The number of rows in each strip (except possibly the last strip.) For example, if ImageLength is 24, and RowsPerStrip is 10, then there are 3
/// strips, with 10 rows in the first strip, 10 rows in the second strip, and 4 rows in the third strip. (The data in the last strip is not padded with 6 extra rows
/// of dummy data.)
/// </summary>
RowsPerStrip = 278,
/// <summary>
/// SHORT or LONG. For each strip, the number of bytes in that strip AFTER ANY COMPRESSION.
/// </summary>
StripByteCounts = 279,
/// <summary>
/// RATIONAL. The number of pixels per ResolutionUnit in the ImageWidth (typically, horizontal - see Orientation) direction.
/// </summary>
XResolution = 282,
/// <summary>
/// RATIONAL. The number of pixels per ResolutionUnit in the ImageLength (typically, vertical) direction.
/// </summary>
YResolution = 283,
/// <summary>
/// SHORT. How the components of each pixel are stored.
/// </summary>
PlanarConfiguration = 284,
/// <summary>
/// ASCII. The name of the page from which this image was scanned.
/// </summary>
/// <seealso cref="DocumentName" />
PageName = 285,
/// <summary>
/// RATIONAL. X position of the image, i.e. the X offset in ResolutionUnits of the left side of the image, with respect to the left side of the page.
/// </summary>
/// <seealso cref="YPosition" />
XPosition = 286,
/// <summary>
/// RATIONAL. Y position of the image, i.e. the Y offset in ResolutionUnits of the top of the image, with respect to the top of the page. In the TIFF coordinate scheme,
/// the positive Y direction is down, so that <see cref="YPosition" /> is always positive.
/// </summary>
/// <seealso cref="XPosition" />
YPosition = 287,
/// <summary>
/// SHORT. See <see cref="TIFFResolutionUnit" />. Default = 2 (<see cref="TIFFResolutionUnit.Inch" />).
/// </summary>
ResolutionUnit = 296,
/// <summary>
/// SHORT. The page number of the page from which this image was scanned. This field is used to specify page numbers of a multiple page (e.g. facsimile) document.
/// PageNumber[0] is the page number; PageNumber[1] is the total number of pages in the document. If PageNumber[1] is 0, the total number of pages in the document is
/// not available. Pages need not appear in numerical order. The first page is numbered 0 (zero).
/// </summary>
PageNumber = 297,
/// <summary>
/// ASCII. Name and version number of the software package(s) used to create the image.
/// </summary>
/// <seealso cref="Make" />
/// <seealso cref="Model" />
Software = 305,
/// <summary>
/// ASCII. Date and time of image creation. The format is: “YYYY:MM:DD HH:MM:SS”, with hours like those on a 24-hour clock, and one space character between the date and
/// the time. The length of the string, including the terminating NUL, is 20 bytes.
/// </summary>
DateTime = 306,
/// <summary>
/// SHORT. Description of extra components. Specifies that each pixel has m extra components whose interpretation is defined by one of the values listed below.
/// When this field is used, the SamplesPerPixel field has a value greater than the PhotometricInterpretation field suggests. For example, full-color RGB data normally
/// has SamplesPerPixel = 3. If SamplesPerPixel is greater than 3, then the ExtraSamples field describes the meaning of the extra samples. If SamplesPerPixel is, say, 5
/// then ExtraSamples will contain 2 values, one for each extra sample. ExtraSamples is typically used to include non-color information, such as opacity, in an image.
/// The possible values for each item in the field's value are defined by <see cref="TIFFExtraSamplesType" />. By convention, extra components that are present must be
/// stored as the "last components" in each pixel. For example, if SamplesPerPixel is 4 and there is 1 extra component, then it is located in the last component location
/// (SamplesPerPixel-1) in each pixel. Components designated as "extra" are just like other components in a pixel. In particular, the size of such components is defined
/// by the value of the <see cref="BitsPerSample" /> field. With the introduction of this field, TIFF readers must not assume a particular <see cref="SamplesPerPixel" />
/// value based on the value of the <see cref="PhotometricInterpretation" /> field. For example, if the file is an RGB file, <see cref="SamplesPerPixel" /> may be
/// greater than 3. The default is no extra samples. This field must be present if there are extra samples.
/// </summary>
/// <seealso cref="SamplesPerPixel" />
/// <seealso cref="AssociatedAlpha" />
ExtraSamples = 338,
/// <summary>
/// SHORT[SamplesPerPixel]. This field specifies how to interpret each data sample in a pixel. Possible values are defined in <see cref="TIFFSampleFormat" />.
/// </summary>
SampleFormat = 339,
/// <summary>
/// ASCII. Person who created the image.
/// </summary>
Artist = 315,
/// <summary>
/// SHORT. This field defines a Red-Green-Blue color map (often called a lookup table) for palette color images. In a palette-color image, a pixel value is used to index
/// into an RGB-lookup table. For example, a palette-color pixel having a value of 0 would be displayed according to the 0th Red, Green, Blue triplet. In a TIFF ColorMap,
/// all the Red values come first, followed by the Green values, then the Blue values. In the ColorMap, black is represented by 0,0,0 and white is represented by 65535,
/// 65535, 65535.
/// </summary>
ColorMap = 320,
XMPMetadata = 700,
/// <summary>
/// ASCII. Copyright notice of the person or organization that claims the copyright to the image. The complete copyright statement should be listed in this field
/// including any dates and statements of claims. For example, "Copyright, John Smith, 19xx. All rights reserved."
/// </summary>
Copyright = 33432,
ICCProfile = 34675
}
}

View File

@ -325,6 +325,18 @@
<Compile Include="DataFormats\Multimedia\Picture\XPM\XPMFormatVersion.cs" />
<Compile Include="ObjectModels\Multimedia\SpriteAnimationCollection\SpriteAnimationCollectionObjectModel.cs" />
<Compile Include="ObjectModels\Multimedia\SpriteAnimationCollection\SpriteAnimation.cs" />
<Compile Include="DataFormats\Multimedia\Picture\TIFF\TIFFDataFormatBase.cs" />
<Compile Include="DataFormats\Multimedia\Picture\TIFF\TIFFImageFileDirectoryEntry.cs" />
<Compile Include="DataFormats\Multimedia\Picture\TIFF\TIFFDataType.cs" />
<Compile Include="DataFormats\Multimedia\Picture\TIFF\TIFFTag.cs" />
<Compile Include="DataFormats\Multimedia\Picture\TIFF\TIFFCompression.cs" />
<Compile Include="DataFormats\Multimedia\Picture\TIFF\TIFFResolutionUnit.cs" />
<Compile Include="DataFormats\Multimedia\Picture\TIFF\TIFFPhotometricInterpretation.cs" />
<Compile Include="DataFormats\Multimedia\Picture\TIFF\TIFFObjectModelBase.cs" />
<Compile Include="DataFormats\Multimedia\Picture\TIFF\TIFFDataFormat.cs" />
<Compile Include="DataFormats\Multimedia\Picture\TIFF\TIFFExtraSamplesType.cs" />
<Compile Include="DataFormats\Multimedia\Picture\TIFF\TIFFFillOrder.cs" />
<Compile Include="DataFormats\Multimedia\Picture\TIFF\TIFFImageFileDirectory.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\Libraries\UniversalEditor.Compression\UniversalEditor.Compression.csproj">
@ -377,6 +389,7 @@
<Folder Include="DataFormats\Multimedia\Audio\Synthesized\EdLib\" />
<Folder Include="DataFormats\Multimedia\Picture\XPM\" />
<Folder Include="ObjectModels\Multimedia\SpriteAnimationCollection\" />
<Folder Include="DataFormats\Multimedia\Picture\TIFF\" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>