-
-
Notifications
You must be signed in to change notification settings - Fork 890
[WIP] Implement Tiff codec #119
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
JimBobSquarePants
merged 77 commits into
SixLabors:tiff-codec
from
Andy-Wilkinson:tiff-codec
Dec 10, 2018
Merged
Changes from 1 commit
Commits
Show all changes
77 commits
Select commit
Hold shift + click to select a range
a74d143
Add initial Tiff codec projects, and TiffGen
Andy-Wilkinson 8cbfc8e
Add Tiff implementation of IImageFormat
Andy-Wilkinson 0196499
Reference ImageSharp (temporary code sharing)
Andy-Wilkinson 4f6c75a
Add stub Tiff encoders/decoders
Andy-Wilkinson 7e3d2c0
Read and validate the TIFF file header.
Andy-Wilkinson e976a2c
Make Tiff implementation details internal
Andy-Wilkinson be842dc
Make TiffDecoderCore more unit-testable
Andy-Wilkinson 5e0fc3b
Read raw data from TIFF IFDs
Andy-Wilkinson e4e2b4c
More comprehensive testing of header checks
Andy-Wilkinson 0534ce0
Read raw bytes for IFD entries
Andy-Wilkinson e3d7436
Read integer types from TIFF IFDs
Andy-Wilkinson a637ef4
Read strings from TIFF IFDs
Andy-Wilkinson fe6d5f6
Read rational numbers from TIFF IFDs
Andy-Wilkinson 6792d88
Use constants for data type sizes
Andy-Wilkinson 90a3dc9
Read floating-point numbers from TIFF IFDs
Andy-Wilkinson 8cec9d6
Add a number of TIFF specific constants/enums
Andy-Wilkinson 1cb02a4
Merge branch 'master' into tiff-codec
Andy-Wilkinson 736019e
Incorporate Tiff codec into new project structure
Andy-Wilkinson 94847e8
Remove unneeded using statements
Andy-Wilkinson 1646c67
Fix many StyleCop warnings!
Andy-Wilkinson 3b51c36
Add documentation to all elements.
Andy-Wilkinson aef9284
Run TIFF unit tests in CI
Andy-Wilkinson a874148
Fix project path for CI coverage script
Andy-Wilkinson c3a980c
Alternatively... Just merge in the TIFF tests
Andy-Wilkinson c582ecf
Decode TIFF image dimensions.
Andy-Wilkinson 143a73e
Decode TIFF image resolution
Andy-Wilkinson 959a560
Implement image decoding for the most basic TIFF image format.
Andy-Wilkinson b71a644
Add Image extensions to save TIFF format files
Andy-Wilkinson 2d6a661
Move TIFF internals into own namespace
Andy-Wilkinson 1322e07
Merge branch 'master' into tiff-codec
Andy-Wilkinson 6979a72
Update TIFF codec to new IImageDecoder signature
Andy-Wilkinson e00ce80
Add support for WhiteIsZero bilevel & 4-bit images
Andy-Wilkinson 2f1379a
Add support for PackBits compression
Andy-Wilkinson 756b8ab
Add support for multi-strip TIFF files
Andy-Wilkinson 2efc1f0
Merge branch 'master' into tiff-codec
Andy-Wilkinson b410526
Update namespaces and naming
Andy-Wilkinson da4b738
Add default WhiteIsZero implementation
Andy-Wilkinson a579df3
Add support for BlackIsZero
Andy-Wilkinson d241c19
Add support for pallete color images
Andy-Wilkinson 64e0e55
Add support for RGB full color images
Andy-Wilkinson 933f54b
Add optimised implementation for 8-bit RGB images
Andy-Wilkinson 2147169
Add support for Deflate (and OldDeflate) compression
Andy-Wilkinson d1e0cc6
Add support for RGB (planar) pixel formats
Andy-Wilkinson 40085b2
Add helper function when reading entries with defaults
Andy-Wilkinson ee295f2
Merge branch 'master' into tiff-codec
Andy-Wilkinson 024d268
PixelAccessor needs to be internal in unit tests
Andy-Wilkinson 96b3e06
Add support for LZW compression
Andy-Wilkinson 0ae6220
Add TIFF README.md file
Andy-Wilkinson 70b8207
Add more items to TIFF readme
Andy-Wilkinson 743801f
Fill TIFF Readme tables with current status.
Andy-Wilkinson faee97c
Refactor TIFF metadata reading into separate method
Andy-Wilkinson f986ac7
Read baseline TIFF metadata
Andy-Wilkinson 49867fb
Merge branch 'master' into tiff-codec
Andy-Wilkinson 38a89f1
Use new pixel packing methods
Andy-Wilkinson 0971b9d
Add some TIFF sample images (autogenerated)
Andy-Wilkinson 16319d0
Add TIFF as a default image format
Andy-Wilkinson cba51ed
Add 'DecodeTiff' benchmark
Andy-Wilkinson 719e6af
Add TiffEncoder and write TIFF header
Andy-Wilkinson dfaa4cf
Add TIFF IFD encoding
Andy-Wilkinson afbe283
Write metadata to a TIFF file
Andy-Wilkinson 8be5d3d
Update xUnit version (and fix test warnings)
Andy-Wilkinson 32ab03b
Merge from latest master
Andy-Wilkinson a3189de
Use new configuration API for TIFF codec
Andy-Wilkinson 5ca5f77
Merge branch 'master' into tiff-codec
JimBobSquarePants e4bb5e4
Merge branch 'master' into tiff-codec
JimBobSquarePants affd736
Merge branch 'master' of https://github.com/SixLabors/ImageSharp into…
JimBobSquarePants 64094c5
Update codebase to catch up with changes to main repo.
JimBobSquarePants 5fa27fb
Use environment specific newline in test
JimBobSquarePants 3bd7f72
Merge branch 'master' into tiff-codec
JimBobSquarePants 6b212c6
Merge branch 'master' of https://github.com/SixLabors/ImageSharp into…
JimBobSquarePants 554318b
Fix namespace reference in tests
JimBobSquarePants 8a513a5
Merge branch 'master' into tiff-codec
JimBobSquarePants bc7bafe
Merge remote-tracking branch 'upstream/master' into tiff-codec
JimBobSquarePants ca00f9b
Update tests/Images/External
JimBobSquarePants f0ead2d
Merge remote-tracking branch 'upstream/master' into tiff-codec
JimBobSquarePants baf6239
Update IPixel method calls to match new signatures
JimBobSquarePants a8d25ef
Update external references
JimBobSquarePants File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Read raw data from TIFF IFDs
- Loading branch information
commit 5e0fc3b9fa3a64b2488c03d7722a27a8c40ec6ed
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,22 @@ | ||
| // <copyright file="TiffIfd.cs" company="James Jackson-South"> | ||
| // Copyright (c) James Jackson-South and contributors. | ||
| // Licensed under the Apache License, Version 2.0. | ||
| // </copyright> | ||
|
|
||
| namespace ImageSharp.Formats | ||
| { | ||
| /// <summary> | ||
| /// Data structure for holding details of each TIFF IFD | ||
| /// </summary> | ||
| internal struct TiffIfd | ||
| { | ||
| public TiffIfdEntry[] Entries; | ||
| public uint NextIfdOffset; | ||
|
|
||
| public TiffIfd(TiffIfdEntry[] entries, uint nextIfdOffset) | ||
| { | ||
| this.Entries = entries; | ||
| this.NextIfdOffset = nextIfdOffset; | ||
| } | ||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,26 @@ | ||
| // <copyright file="TiffIfdEntry.cs" company="James Jackson-South"> | ||
| // Copyright (c) James Jackson-South and contributors. | ||
| // Licensed under the Apache License, Version 2.0. | ||
| // </copyright> | ||
|
|
||
| namespace ImageSharp.Formats | ||
| { | ||
| /// <summary> | ||
| /// Data structure for holding details of each TIFF IFD entry | ||
| /// </summary> | ||
| internal struct TiffIfdEntry | ||
| { | ||
| public ushort Tag; | ||
| public TiffType Type; | ||
| public uint Count; | ||
| public byte[] Value; | ||
|
|
||
| public TiffIfdEntry(ushort tag, TiffType type, uint count, byte[] value) | ||
| { | ||
| this.Tag = tag; | ||
| this.Type = type; | ||
| this.Count = count; | ||
| this.Value = value; | ||
| } | ||
| } | ||
| } |
111 changes: 111 additions & 0 deletions
111
tests/ImageSharp.Formats.Tiff.Tests/Formats/Tiff/TiffDecoderIfdTests.cs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,111 @@ | ||
| // <copyright file="TiffDecoderIfdTests.cs" company="James Jackson-South"> | ||
| // Copyright (c) James Jackson-South and contributors. | ||
| // Licensed under the Apache License, Version 2.0. | ||
| // </copyright> | ||
|
|
||
| namespace ImageSharp.Tests | ||
| { | ||
| using System.IO; | ||
| using System.Linq; | ||
| using Xunit; | ||
|
|
||
| using ImageSharp.Formats; | ||
|
|
||
| public class TiffDecoderIfdTests | ||
| { | ||
| public static object[][] IsLittleEndianValues = new[] { new object[] { false }, | ||
| new object[] { true } }; | ||
|
|
||
| [Theory] | ||
| [MemberData(nameof(IsLittleEndianValues))] | ||
| public void ReadIfd_ReadsNextIfdOffset_IfPresent(bool isLittleEndian) | ||
| { | ||
| Stream stream = new TiffGenIfd() | ||
| { | ||
| Entries = | ||
| { | ||
| TiffGenEntry.Integer(TiffTags.ImageWidth, TiffType.Long, 150) | ||
| }, | ||
| NextIfd = new TiffGenIfd() | ||
| } | ||
| .ToStream(isLittleEndian); | ||
|
|
||
| TiffDecoderCore decoder = new TiffDecoderCore(stream, isLittleEndian, null); | ||
| TiffIfd ifd = decoder.ReadIfd(0); | ||
|
|
||
| Assert.Equal(18u, ifd.NextIfdOffset); | ||
| } | ||
|
|
||
| [Theory] | ||
| [MemberData(nameof(IsLittleEndianValues))] | ||
| public void ReadIfd_ReadsNextIfdOffset_ZeroIfLastIfd(bool isLittleEndian) | ||
| { | ||
| Stream stream = new TiffGenIfd() | ||
| { | ||
| Entries = | ||
| { | ||
| TiffGenEntry.Integer(TiffTags.ImageWidth, TiffType.Long, 150) | ||
| } | ||
| } | ||
| .ToStream(isLittleEndian); | ||
|
|
||
| TiffDecoderCore decoder = new TiffDecoderCore(stream, isLittleEndian, null); | ||
| TiffIfd ifd = decoder.ReadIfd(0); | ||
|
|
||
| Assert.Equal(0u, ifd.NextIfdOffset); | ||
| } | ||
|
|
||
| [Theory] | ||
| [MemberData(nameof(IsLittleEndianValues))] | ||
| public void ReadIfd_ReturnsCorrectNumberOfEntries(bool isLittleEndian) | ||
| { | ||
| Stream stream = new TiffGenIfd() | ||
| { | ||
| Entries = | ||
| { | ||
| TiffGenEntry.Integer(TiffTags.ImageWidth, TiffType.Long, 150), | ||
| TiffGenEntry.Integer(TiffTags.ImageLength, TiffType.Long, 210), | ||
| TiffGenEntry.Integer(TiffTags.Orientation, TiffType.Short, 1), | ||
| TiffGenEntry.Ascii(TiffTags.Artist, "Image Artist Name"), | ||
| TiffGenEntry.Ascii(TiffTags.HostComputer, "Host Computer Name") | ||
| }, | ||
| NextIfd = new TiffGenIfd() | ||
| } | ||
| .ToStream(isLittleEndian); | ||
|
|
||
| TiffDecoderCore decoder = new TiffDecoderCore(stream, isLittleEndian, null); | ||
| TiffIfd ifd = decoder.ReadIfd(0); | ||
|
|
||
| Assert.NotNull(ifd.Entries); | ||
| Assert.Equal(5, ifd.Entries.Length); | ||
| } | ||
|
|
||
| [Theory] | ||
| [MemberData(nameof(IsLittleEndianValues))] | ||
| public void ReadIfd_ReadsRawTiffEntryData(bool isLittleEndian) | ||
| { | ||
| Stream stream = new TiffGenIfd() | ||
| { | ||
| Entries = | ||
| { | ||
| TiffGenEntry.Integer(TiffTags.ImageWidth, TiffType.Long, 150), | ||
| TiffGenEntry.Integer(TiffTags.ImageLength, TiffType.Long, 210), | ||
| TiffGenEntry.Integer(TiffTags.Orientation, TiffType.Short, 1) | ||
| }, | ||
| NextIfd = new TiffGenIfd() | ||
| } | ||
| .ToStream(isLittleEndian); | ||
|
|
||
| TiffDecoderCore decoder = new TiffDecoderCore(stream, isLittleEndian, null); | ||
| TiffIfd ifd = decoder.ReadIfd(0); | ||
| TiffIfdEntry entry = ifd.Entries[1]; | ||
|
|
||
| byte[] expectedData = isLittleEndian ? new byte[] {210,0,0,0} : new byte[] {0,0,0,210}; | ||
| Assert.NotNull(entry); | ||
| Assert.Equal(TiffTags.ImageLength, entry.Tag); | ||
| Assert.Equal(TiffType.Long, entry.Type); | ||
| Assert.Equal(4u, entry.Count); | ||
| Assert.Equal(expectedData, entry.Value); | ||
| } | ||
| } | ||
| } |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we can't assume that the TIFF image starts at the beginning of the stream. (Or at least we don't do this in other codecs.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No we can't assume that. Someone could have multiple images in a stream or other information. Best we can do is look for the identifier at the position we are currently at.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Okay... The easy fix is to store the offset that we start at, and do all Seeks relative to this, i.e.
InputStream.Seek(StartOffset + offset, SeekOrigin.Begin).I'd really love to get rid of the Seeks entirely, but unfortunately the TIFF file-format relies heavily on referencing offsets within the file. There is no way you can tell what the next bit of data is otherwise. As an example a file layout could be,
0-8 -> TIFF file header (8 bytes) - references first IFD at offset 30000
8-10000 -> Raw image data here
30000-... -> IFD (basically an image header) - references image data at offset 8
Until you read the IFD at offset 30000, you have no way of telling what data is at offset 8 - it could be image data in an unknown compression/format, another IFD, strings from the metadata. The format doesn't have any identifiers to let you know until you have read the IFD itself.
Any clever ideas to avoid Seeks would be great though! 😄