From 1c842411ff145f7a9c4ecb529c66909a68ea0199 Mon Sep 17 00:00:00 2001 From: Michael Becker Date: Wed, 17 Jun 2020 23:29:15 -0400 Subject: [PATCH] add support for reading first page of an uncompressed TIFF image (it's a start...) --- .../Associations/Picture/TIFF.uexml | 29 ++ ...lEditor.Content.PlatformIndependent.csproj | 1 + .../Picture/TIFF/TIFFCompression.cs | 45 ++ .../Multimedia/Picture/TIFF/TIFFDataFormat.cs | 177 +++++++ .../Picture/TIFF/TIFFDataFormatBase.cs | 482 ++++++++++++++++++ .../Multimedia/Picture/TIFF/TIFFDataType.cs | 76 +++ .../Picture/TIFF/TIFFExtraSamplesType.cs | 41 ++ .../Multimedia/Picture/TIFF/TIFFFillOrder.cs | 40 ++ .../Picture/TIFF/TIFFImageFileDirectory.cs | 44 ++ .../TIFF/TIFFImageFileDirectoryEntry.cs | 190 +++++++ .../Picture/TIFF/TIFFObjectModelBase.cs | 44 ++ .../TIFF/TIFFPhotometricInterpretation.cs | 48 ++ .../Picture/TIFF/TIFFResolutionUnit.cs | 33 ++ .../Multimedia/Picture/TIFF/TIFFTag.cs | 186 +++++++ .../UniversalEditor.Plugins.Multimedia.csproj | 13 + 15 files changed, 1449 insertions(+) create mode 100644 Content/UniversalEditor.Content.PlatformIndependent/Extensions/GraphicDesigner/Associations/Picture/TIFF.uexml create mode 100644 Plugins/UniversalEditor.Plugins.Multimedia/DataFormats/Multimedia/Picture/TIFF/TIFFCompression.cs create mode 100644 Plugins/UniversalEditor.Plugins.Multimedia/DataFormats/Multimedia/Picture/TIFF/TIFFDataFormat.cs create mode 100644 Plugins/UniversalEditor.Plugins.Multimedia/DataFormats/Multimedia/Picture/TIFF/TIFFDataFormatBase.cs create mode 100644 Plugins/UniversalEditor.Plugins.Multimedia/DataFormats/Multimedia/Picture/TIFF/TIFFDataType.cs create mode 100644 Plugins/UniversalEditor.Plugins.Multimedia/DataFormats/Multimedia/Picture/TIFF/TIFFExtraSamplesType.cs create mode 100644 Plugins/UniversalEditor.Plugins.Multimedia/DataFormats/Multimedia/Picture/TIFF/TIFFFillOrder.cs create mode 100644 Plugins/UniversalEditor.Plugins.Multimedia/DataFormats/Multimedia/Picture/TIFF/TIFFImageFileDirectory.cs create mode 100644 Plugins/UniversalEditor.Plugins.Multimedia/DataFormats/Multimedia/Picture/TIFF/TIFFImageFileDirectoryEntry.cs create mode 100644 Plugins/UniversalEditor.Plugins.Multimedia/DataFormats/Multimedia/Picture/TIFF/TIFFObjectModelBase.cs create mode 100644 Plugins/UniversalEditor.Plugins.Multimedia/DataFormats/Multimedia/Picture/TIFF/TIFFPhotometricInterpretation.cs create mode 100644 Plugins/UniversalEditor.Plugins.Multimedia/DataFormats/Multimedia/Picture/TIFF/TIFFResolutionUnit.cs create mode 100644 Plugins/UniversalEditor.Plugins.Multimedia/DataFormats/Multimedia/Picture/TIFF/TIFFTag.cs diff --git a/Content/UniversalEditor.Content.PlatformIndependent/Extensions/GraphicDesigner/Associations/Picture/TIFF.uexml b/Content/UniversalEditor.Content.PlatformIndependent/Extensions/GraphicDesigner/Associations/Picture/TIFF.uexml new file mode 100644 index 00000000..be44944c --- /dev/null +++ b/Content/UniversalEditor.Content.PlatformIndependent/Extensions/GraphicDesigner/Associations/Picture/TIFF.uexml @@ -0,0 +1,29 @@ + + + + + + + + *.tif + *.tiff + + + + II + + + MM + + + + + + + + + + + + + \ No newline at end of file diff --git a/Content/UniversalEditor.Content.PlatformIndependent/UniversalEditor.Content.PlatformIndependent.csproj b/Content/UniversalEditor.Content.PlatformIndependent/UniversalEditor.Content.PlatformIndependent.csproj index 1cdc560a..4bc2260c 100644 --- a/Content/UniversalEditor.Content.PlatformIndependent/UniversalEditor.Content.PlatformIndependent.csproj +++ b/Content/UniversalEditor.Content.PlatformIndependent/UniversalEditor.Content.PlatformIndependent.csproj @@ -743,6 +743,7 @@ + diff --git a/Plugins/UniversalEditor.Plugins.Multimedia/DataFormats/Multimedia/Picture/TIFF/TIFFCompression.cs b/Plugins/UniversalEditor.Plugins.Multimedia/DataFormats/Multimedia/Picture/TIFF/TIFFCompression.cs new file mode 100644 index 00000000..31273757 --- /dev/null +++ b/Plugins/UniversalEditor.Plugins.Multimedia/DataFormats/Multimedia/Picture/TIFF/TIFFCompression.cs @@ -0,0 +1,45 @@ +// +// TIFFCompression.cs +// +// Author: +// Michael Becker +// +// 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 . +using System; +namespace UniversalEditor.DataFormats.Multimedia.Picture.TIFF +{ + public enum TIFFCompression : ushort + { + /// + /// 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. + /// + None = 0x01, + /// + /// CCITT Group 3 1-Dimensional Modified Huffman run length encoding. + /// + RunLengthEncoding = 0x02, + Group3Fax = 0x03, + Group4Fax = 0x04, + LZW = 0x05, + JPEG = 0x06, + Deflate = 0x08, + /// + /// PackBits compression, a simple byte-oriented run length scheme. + /// + PackBits = 32773 + } +} diff --git a/Plugins/UniversalEditor.Plugins.Multimedia/DataFormats/Multimedia/Picture/TIFF/TIFFDataFormat.cs b/Plugins/UniversalEditor.Plugins.Multimedia/DataFormats/Multimedia/Picture/TIFF/TIFFDataFormat.cs new file mode 100644 index 00000000..0a640d07 --- /dev/null +++ b/Plugins/UniversalEditor.Plugins.Multimedia/DataFormats/Multimedia/Picture/TIFF/TIFFDataFormat.cs @@ -0,0 +1,177 @@ +// +// TIFFDataFormat.cs +// +// Author: +// Michael Becker +// +// 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 . + +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 objectModels) + { + base.BeforeLoadInternal(objectModels); + objectModels.Push(new TIFFObjectModelBase()); + } + protected override void AfterLoadInternal(Stack 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 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); + } + } +} diff --git a/Plugins/UniversalEditor.Plugins.Multimedia/DataFormats/Multimedia/Picture/TIFF/TIFFDataFormatBase.cs b/Plugins/UniversalEditor.Plugins.Multimedia/DataFormats/Multimedia/Picture/TIFF/TIFFDataFormatBase.cs new file mode 100644 index 00000000..0e160ee2 --- /dev/null +++ b/Plugins/UniversalEditor.Plugins.Multimedia/DataFormats/Multimedia/Picture/TIFF/TIFFDataFormatBase.cs @@ -0,0 +1,482 @@ +// +// TIFFDataFormatBase.cs +// +// Author: +// Michael Becker +// +// 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 . +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 ifdentries = new List(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); + } + } +} diff --git a/Plugins/UniversalEditor.Plugins.Multimedia/DataFormats/Multimedia/Picture/TIFF/TIFFDataType.cs b/Plugins/UniversalEditor.Plugins.Multimedia/DataFormats/Multimedia/Picture/TIFF/TIFFDataType.cs new file mode 100644 index 00000000..a095416a --- /dev/null +++ b/Plugins/UniversalEditor.Plugins.Multimedia/DataFormats/Multimedia/Picture/TIFF/TIFFDataType.cs @@ -0,0 +1,76 @@ +// +// TIFFDataType.cs +// +// Author: +// Michael Becker +// +// 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 . +using System; +namespace UniversalEditor.DataFormats.Multimedia.Picture.TIFF +{ + public enum TIFFDataType : ushort + { + /// + /// 8-bit unsigned integer. + /// + Byte = 0x0001, + /// + /// 8-bit byte that contains a 7-bit ASCII code; the last byte must be NUL (binary zero). + /// + Ascii = 0x0002, + /// + /// 16-bit (2-byte) unsigned integer. + /// + Short = 0x0003, + /// + /// 32-bit (4-byte) unsigned integer. + /// + Long = 0x0004, + /// + /// Two s: the first represents the numerator of a fraction; the second, the denominator. + /// + Rational = 0x0005, + + /// + /// An 8-bit signed (twos-complement) integer. Added in TIFF 6.0. + /// + SignedByte = 0x0006, + /// + /// An 8-bit byte that may contain anything, depending on the definition of the field. Added in TIFF 6.0. + /// + Undefined = 0x0007, + /// + /// A 16-bit (2-byte) signed (twos-complement) integer. Added in TIFF 6.0. + /// + SignedShort = 0x0008, + /// + /// A 32-bit (4-byte) signed (twos-complement) integer. Added in TIFF 6.0. + /// + SignedLong = 0x0009, + /// + /// Two SLONG’s: the first represents the numerator of a fraction, the second the denominator. Added in TIFF 6.0. + /// + SignedRational = 0x000A, + /// + /// Single precision (4-byte) IEEE format. Added in TIFF 6.0. + /// + Float = 0x000B, + /// + /// Double precision (8-byte) IEEE format. Added in TIFF 6.0. + /// + Double = 0x000C + } +} diff --git a/Plugins/UniversalEditor.Plugins.Multimedia/DataFormats/Multimedia/Picture/TIFF/TIFFExtraSamplesType.cs b/Plugins/UniversalEditor.Plugins.Multimedia/DataFormats/Multimedia/Picture/TIFF/TIFFExtraSamplesType.cs new file mode 100644 index 00000000..aee0f399 --- /dev/null +++ b/Plugins/UniversalEditor.Plugins.Multimedia/DataFormats/Multimedia/Picture/TIFF/TIFFExtraSamplesType.cs @@ -0,0 +1,41 @@ +// +// TIFFExtraSamplesType.cs +// +// Author: +// Michael Becker +// +// 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 . +using System; +namespace UniversalEditor.DataFormats.Multimedia.Picture.TIFF +{ + public enum TIFFExtraSamplesType : ushort + { + /// + /// Unspecified data + /// + Unspecified = 0x00, + /// + /// 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. + /// + AssociatedAlpha = 0x01, + /// + /// 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. + /// + UnassociatedAlpha = 0x02, + } +} diff --git a/Plugins/UniversalEditor.Plugins.Multimedia/DataFormats/Multimedia/Picture/TIFF/TIFFFillOrder.cs b/Plugins/UniversalEditor.Plugins.Multimedia/DataFormats/Multimedia/Picture/TIFF/TIFFFillOrder.cs new file mode 100644 index 00000000..de4d1227 --- /dev/null +++ b/Plugins/UniversalEditor.Plugins.Multimedia/DataFormats/Multimedia/Picture/TIFF/TIFFFillOrder.cs @@ -0,0 +1,40 @@ +// +// TIFFFillOrder.cs +// +// Author: +// Michael Becker +// +// 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 . +using System; +namespace UniversalEditor.DataFormats.Multimedia.Picture.TIFF +{ + public enum TIFFFillOrder : ushort + { + /// + /// 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. + /// + Normal = 1, + /// + /// 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. + /// + Reverse = 2 + } +} diff --git a/Plugins/UniversalEditor.Plugins.Multimedia/DataFormats/Multimedia/Picture/TIFF/TIFFImageFileDirectory.cs b/Plugins/UniversalEditor.Plugins.Multimedia/DataFormats/Multimedia/Picture/TIFF/TIFFImageFileDirectory.cs new file mode 100644 index 00000000..bc302cc2 --- /dev/null +++ b/Plugins/UniversalEditor.Plugins.Multimedia/DataFormats/Multimedia/Picture/TIFF/TIFFImageFileDirectory.cs @@ -0,0 +1,44 @@ +// +// TIFFImageFile.cs +// +// Author: +// Michael Becker +// +// 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 . +using System; +namespace UniversalEditor.DataFormats.Multimedia.Picture.TIFF +{ + public class TIFFImageFileDirectory : ICloneable + { + public class TIFFImageFileDirectoryCollection + : System.Collections.ObjectModel.Collection + { + + } + + 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; + } + } +} diff --git a/Plugins/UniversalEditor.Plugins.Multimedia/DataFormats/Multimedia/Picture/TIFF/TIFFImageFileDirectoryEntry.cs b/Plugins/UniversalEditor.Plugins.Multimedia/DataFormats/Multimedia/Picture/TIFF/TIFFImageFileDirectoryEntry.cs new file mode 100644 index 00000000..45a4b4a0 --- /dev/null +++ b/Plugins/UniversalEditor.Plugins.Multimedia/DataFormats/Multimedia/Picture/TIFF/TIFFImageFileDirectoryEntry.cs @@ -0,0 +1,190 @@ +// +// TIFFImageFileDirectory.cs +// +// Author: +// Michael Becker +// +// 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 . +using System; +namespace UniversalEditor.DataFormats.Multimedia.Picture.TIFF +{ + public class TIFFImageFileDirectoryEntry : ICloneable, IComparable + { + public class TIFFImageFileDirectoryEntryCollection + : System.Collections.ObjectModel.Collection + { + 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(); + } + + /// + /// The Tag that identifies the field. + /// + public TIFFTag Tag { get; set; } + /// + /// The field Type. + /// + public TIFFDataType Type { get; set; } + /// + /// The number of values, Count of the indicated Type. + /// + public uint Count { get; set; } = 1; + /// + /// 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. + /// + /// + /// 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. + /// + 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); + } + } +} diff --git a/Plugins/UniversalEditor.Plugins.Multimedia/DataFormats/Multimedia/Picture/TIFF/TIFFObjectModelBase.cs b/Plugins/UniversalEditor.Plugins.Multimedia/DataFormats/Multimedia/Picture/TIFF/TIFFObjectModelBase.cs new file mode 100644 index 00000000..22698d3c --- /dev/null +++ b/Plugins/UniversalEditor.Plugins.Multimedia/DataFormats/Multimedia/Picture/TIFF/TIFFObjectModelBase.cs @@ -0,0 +1,44 @@ +// +// TIFFObjectModelBase.cs +// +// Author: +// Michael Becker +// +// 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 . +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); + } + } + } +} diff --git a/Plugins/UniversalEditor.Plugins.Multimedia/DataFormats/Multimedia/Picture/TIFF/TIFFPhotometricInterpretation.cs b/Plugins/UniversalEditor.Plugins.Multimedia/DataFormats/Multimedia/Picture/TIFF/TIFFPhotometricInterpretation.cs new file mode 100644 index 00000000..24abf82b --- /dev/null +++ b/Plugins/UniversalEditor.Plugins.Multimedia/DataFormats/Multimedia/Picture/TIFF/TIFFPhotometricInterpretation.cs @@ -0,0 +1,48 @@ +// +// TIFFPhotometricInterpretation.cs +// +// Author: +// Michael Becker +// +// 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 . + +namespace UniversalEditor.DataFormats.Multimedia.Picture.TIFF +{ + public enum TIFFPhotometricInterpretation + { + /// + /// 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. + /// + WhiteIsZero = 0x00, + /// + /// 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. + /// + BlackIsZero = 0x01, + /// + /// Indicates a full-color image. Each component is 8 bits deep in a Baseline TIFF RGB image. + /// + RGB = 0x02, + /// + /// Indicates a Palette-color image. + /// + PaletteColor = 0x03, + TransparencyMask = 0x04, + CMYK = 0x05, + YCbCr = 0x06, + CIELab = 0x08 + } +} diff --git a/Plugins/UniversalEditor.Plugins.Multimedia/DataFormats/Multimedia/Picture/TIFF/TIFFResolutionUnit.cs b/Plugins/UniversalEditor.Plugins.Multimedia/DataFormats/Multimedia/Picture/TIFF/TIFFResolutionUnit.cs new file mode 100644 index 00000000..1e6030c6 --- /dev/null +++ b/Plugins/UniversalEditor.Plugins.Multimedia/DataFormats/Multimedia/Picture/TIFF/TIFFResolutionUnit.cs @@ -0,0 +1,33 @@ +// +// TIFFResolutionUnit.cs +// +// Author: +// Michael Becker +// +// 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 . +using System; +namespace UniversalEditor.DataFormats.Multimedia.Picture.TIFF +{ + public enum TIFFResolutionUnit : ushort + { + /// + /// No absolute unit of measurement. Used for images that may have a non-square aspect ratio but no meaningful absolute dimensions. + /// + None = 0x01, + Inch = 0x02, + Centimeter = 0x03 + } +} diff --git a/Plugins/UniversalEditor.Plugins.Multimedia/DataFormats/Multimedia/Picture/TIFF/TIFFTag.cs b/Plugins/UniversalEditor.Plugins.Multimedia/DataFormats/Multimedia/Picture/TIFF/TIFFTag.cs new file mode 100644 index 00000000..564b3e29 --- /dev/null +++ b/Plugins/UniversalEditor.Plugins.Multimedia/DataFormats/Multimedia/Picture/TIFF/TIFFTag.cs @@ -0,0 +1,186 @@ +// +// TIFFTag.cs +// +// Author: +// Michael Becker +// +// 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 . +using System; +namespace UniversalEditor.DataFormats.Multimedia.Picture.TIFF +{ + public enum TIFFTag + { + /// + /// SHORT or LONG. The number of columns in the image, i.e., the number of pixels per scanline. + /// + ImageWidth = 256, + /// + /// SHORT or LONG. The number of rows (sometimes described as scanlines) in the image. + /// + ImageLength = 257, + /// + /// 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. + /// + BitsPerSample = 258, + /// + /// SHORT. See . + /// + Compression = 259, + /// + /// SHORT. See . + /// + PhotometricInterpretation = 262, + + /// + /// SHORT. The width of the dithering or halftoning matrix used to create a dithered or halftoned bilevel file. + /// + CellWidth = 264, + /// + /// 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 + /// = 2. + /// + CellLength = 265, + + /// + /// SHORT. The logical order of bits within a byte. See . Default is . + /// + FillOrder = 266, + + /// + /// ASCII. The name of the document from which this image was scanned. + /// + /// + DocumentName = 269, + + /// + /// SHORT or LONG. For each strip, the byte offset of that strip. + /// + StripOffsets = 273, + /// + /// SHORT. The orientation of the image with respect to the rows and columns. + /// + Orientation = 274, + /// + /// 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. + /// + SamplesPerPixel = 277, + /// + /// 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.) + /// + RowsPerStrip = 278, + /// + /// SHORT or LONG. For each strip, the number of bytes in that strip AFTER ANY COMPRESSION. + /// + StripByteCounts = 279, + /// + /// RATIONAL. The number of pixels per ResolutionUnit in the ImageWidth (typically, horizontal - see Orientation) direction. + /// + XResolution = 282, + /// + /// RATIONAL. The number of pixels per ResolutionUnit in the ImageLength (typically, vertical) direction. + /// + YResolution = 283, + /// + /// SHORT. How the components of each pixel are stored. + /// + PlanarConfiguration = 284, + /// + /// ASCII. The name of the page from which this image was scanned. + /// + /// + PageName = 285, + + /// + /// 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. + /// + /// + XPosition = 286, + /// + /// 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 is always positive. + /// + /// + YPosition = 287, + + /// + /// SHORT. See . Default = 2 (). + /// + ResolutionUnit = 296, + /// + /// 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). + /// + PageNumber = 297, + + /// + /// ASCII. Name and version number of the software package(s) used to create the image. + /// + /// + /// + Software = 305, + /// + /// 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. + /// + DateTime = 306, + + /// + /// 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 . 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 field. With the introduction of this field, TIFF readers must not assume a particular + /// value based on the value of the field. For example, if the file is an RGB file, may be + /// greater than 3. The default is no extra samples. This field must be present if there are extra samples. + /// + /// + /// + ExtraSamples = 338, + /// + /// SHORT[SamplesPerPixel]. This field specifies how to interpret each data sample in a pixel. Possible values are defined in . + /// + SampleFormat = 339, + + /// + /// ASCII. Person who created the image. + /// + Artist = 315, + + /// + /// 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. + /// + ColorMap = 320, + + XMPMetadata = 700, + + /// + /// 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." + /// + Copyright = 33432, + + ICCProfile = 34675 + } +} diff --git a/Plugins/UniversalEditor.Plugins.Multimedia/UniversalEditor.Plugins.Multimedia.csproj b/Plugins/UniversalEditor.Plugins.Multimedia/UniversalEditor.Plugins.Multimedia.csproj index 86ddce75..ae27e3d3 100644 --- a/Plugins/UniversalEditor.Plugins.Multimedia/UniversalEditor.Plugins.Multimedia.csproj +++ b/Plugins/UniversalEditor.Plugins.Multimedia/UniversalEditor.Plugins.Multimedia.csproj @@ -325,6 +325,18 @@ + + + + + + + + + + + + @@ -377,6 +389,7 @@ + \ No newline at end of file