add support for reading first page of an uncompressed TIFF image (it's a start...)
This commit is contained in:
parent
0151b48216
commit
1c842411ff
@ -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>
|
||||
@ -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" />
|
||||
|
||||
@ -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
|
||||
}
|
||||
}
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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 SLONG’s: 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
|
||||
}
|
||||
}
|
||||
@ -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,
|
||||
}
|
||||
}
|
||||
@ -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
|
||||
}
|
||||
}
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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
|
||||
}
|
||||
}
|
||||
@ -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
|
||||
}
|
||||
}
|
||||
@ -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
|
||||
}
|
||||
}
|
||||
@ -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>
|
||||
Loading…
x
Reference in New Issue
Block a user