-
-
Notifications
You must be signed in to change notification settings - Fork 851
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
Support frames metadata for Identify #2363
Merged
JimBobSquarePants
merged 20 commits into
SixLabors:main
from
IldarKhayrutdinov:tiff-frames-meta
Mar 1, 2023
Merged
Changes from 10 commits
Commits
Show all changes
20 commits
Select commit
Hold shift + click to select a range
1c23ccb
implement adding frames metadata to tiff image metadata
IldarKhayrutdinov 681c921
add TiffInkSet property
IldarKhayrutdinov 561c5d8
assert not supported ink names
IldarKhayrutdinov de71b0a
universal metadata parsing methods for loading and identify
IldarKhayrutdinov 308bfa4
deep cloning
IldarKhayrutdinov e1e5f25
Merge remote-tracking branch 'upstream/main' into tiff-frames-meta
IldarKhayrutdinov 220b8aa
add tests
IldarKhayrutdinov c21bbbd
Allow returning individual image frame metadata via Identify.
JimBobSquarePants 3fcacc6
Merge remote-tracking branch 'upstream/main' into tiff-frames-meta
JimBobSquarePants 468dbcb
Merge branch 'main' into tiff-frames-meta
JimBobSquarePants bb32439
Merge branch 'main' into tiff-frames-meta
JimBobSquarePants e9e0e64
update README.md
IldarKhayrutdinov 2ac7c4a
Merge branch 'tiff-frames-meta' of github.com:IldarKhayrutdinov/Image…
IldarKhayrutdinov d19b128
update README.md
IldarKhayrutdinov 07ca405
add Bit32 value for TiffBitsPerPixel
IldarKhayrutdinov cfaf555
add test for notSupported 64 bit cmyk, add more tests for Identify (i…
IldarKhayrutdinov 91c3d5e
cleanup
IldarKhayrutdinov 747923d
Add Bit64 and cleanup
JimBobSquarePants 99038f2
Merge remote-tracking branch 'upstream/main' into tiff-frames-meta
JimBobSquarePants 24a0a5f
Update build-and-test.yml
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
There are no files selected for viewing
This file contains 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 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 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 |
---|---|---|
|
@@ -61,7 +61,7 @@ public LzwDecoder(MemoryAllocator memoryAllocator, BufferedReadStream stream) | |
} | ||
|
||
/// <summary> | ||
/// Decodes and decompresses all pixel indices from the stream. | ||
/// Decodes and decompresses all pixel indices from the stream, assigning the pixel values to the buffer. | ||
/// </summary> | ||
/// <param name="minCodeSize">Minimum code size of the data.</param> | ||
/// <param name="pixels">The pixel array to decode to.</param> | ||
|
@@ -232,6 +232,159 @@ public void DecodePixels(int minCodeSize, Buffer2D<byte> pixels) | |
} | ||
} | ||
|
||
/// <summary> | ||
/// Decodes and decompresses all pixel indices from the stream allowing skipping of the data. | ||
/// </summary> | ||
/// <param name="minCodeSize">Minimum code size of the data.</param> | ||
/// <param name="length">The resulting index table length.</param> | ||
public void SkipIndices(int minCodeSize, int length) | ||
{ | ||
// Calculate the clear code. The value of the clear code is 2 ^ minCodeSize | ||
int clearCode = 1 << minCodeSize; | ||
|
||
// It is possible to specify a larger LZW minimum code size than the palette length in bits | ||
// which may leave a gap in the codes where no colors are assigned. | ||
// http://www.matthewflickinger.com/lab/whatsinagif/lzw_image_data.asp#lzw_compression | ||
if (minCodeSize < 2 || clearCode > MaxStackSize) | ||
{ | ||
// Don't attempt to decode the frame indices. | ||
// Theoretically we could determine a min code size from the length of the provided | ||
// color palette but we won't bother since the image is most likely corrupted. | ||
GifThrowHelper.ThrowInvalidImageContentException("Gif Image does not contain a valid LZW minimum code."); | ||
} | ||
|
||
int codeSize = minCodeSize + 1; | ||
|
||
// Calculate the end code | ||
int endCode = clearCode + 1; | ||
|
||
// Calculate the available code. | ||
int availableCode = clearCode + 2; | ||
|
||
// Jillzhangs Code see: http://giflib.codeplex.com/ | ||
// Adapted from John Cristy's ImageMagick. | ||
int code; | ||
int oldCode = NullCode; | ||
int codeMask = (1 << codeSize) - 1; | ||
int bits = 0; | ||
|
||
int top = 0; | ||
int count = 0; | ||
int bi = 0; | ||
int xyz = 0; | ||
|
||
int data = 0; | ||
int first = 0; | ||
|
||
ref int prefixRef = ref MemoryMarshal.GetReference(this.prefix.GetSpan()); | ||
ref int suffixRef = ref MemoryMarshal.GetReference(this.suffix.GetSpan()); | ||
ref int pixelStackRef = ref MemoryMarshal.GetReference(this.pixelStack.GetSpan()); | ||
|
||
for (code = 0; code < clearCode; code++) | ||
{ | ||
Unsafe.Add(ref suffixRef, code) = (byte)code; | ||
} | ||
|
||
Span<byte> buffer = stackalloc byte[byte.MaxValue]; | ||
while (xyz < length) | ||
{ | ||
if (top == 0) | ||
{ | ||
if (bits < codeSize) | ||
{ | ||
// Load bytes until there are enough bits for a code. | ||
if (count == 0) | ||
{ | ||
// Read a new data block. | ||
count = this.ReadBlock(buffer); | ||
if (count == 0) | ||
{ | ||
break; | ||
} | ||
|
||
bi = 0; | ||
} | ||
|
||
data += buffer[bi] << bits; | ||
|
||
bits += 8; | ||
bi++; | ||
count--; | ||
continue; | ||
} | ||
|
||
// Get the next code | ||
code = data & codeMask; | ||
data >>= codeSize; | ||
bits -= codeSize; | ||
|
||
// Interpret the code | ||
if (code > availableCode || code == endCode) | ||
{ | ||
break; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This break here is the killer. A lot of properties we require for each loop follow. |
||
} | ||
|
||
if (code == clearCode) | ||
{ | ||
// Reset the decoder | ||
codeSize = minCodeSize + 1; | ||
codeMask = (1 << codeSize) - 1; | ||
availableCode = clearCode + 2; | ||
oldCode = NullCode; | ||
continue; | ||
} | ||
|
||
if (oldCode == NullCode) | ||
{ | ||
Unsafe.Add(ref pixelStackRef, top++) = Unsafe.Add(ref suffixRef, code); | ||
oldCode = code; | ||
first = code; | ||
continue; | ||
} | ||
|
||
int inCode = code; | ||
if (code == availableCode) | ||
{ | ||
Unsafe.Add(ref pixelStackRef, top++) = (byte)first; | ||
|
||
code = oldCode; | ||
} | ||
|
||
while (code > clearCode) | ||
{ | ||
Unsafe.Add(ref pixelStackRef, top++) = Unsafe.Add(ref suffixRef, code); | ||
code = Unsafe.Add(ref prefixRef, code); | ||
} | ||
|
||
int suffixCode = Unsafe.Add(ref suffixRef, code); | ||
first = suffixCode; | ||
Unsafe.Add(ref pixelStackRef, top++) = suffixCode; | ||
|
||
// Fix for Gifs that have "deferred clear code" as per here : | ||
// https://bugzilla.mozilla.org/show_bug.cgi?id=55918 | ||
if (availableCode < MaxStackSize) | ||
{ | ||
Unsafe.Add(ref prefixRef, availableCode) = oldCode; | ||
Unsafe.Add(ref suffixRef, availableCode) = first; | ||
availableCode++; | ||
if (availableCode == codeMask + 1 && availableCode < MaxStackSize) | ||
{ | ||
codeSize++; | ||
codeMask = (1 << codeSize) - 1; | ||
} | ||
} | ||
|
||
oldCode = inCode; | ||
} | ||
|
||
// Pop a pixel off the pixel stack. | ||
top--; | ||
|
||
// Clear missing pixels | ||
xyz++; | ||
} | ||
} | ||
|
||
/// <summary> | ||
/// Reads the next data block from the stream. A data block begins with a byte, | ||
/// which defines the size of the block, followed by the block itself. | ||
|
This file contains 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 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 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 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 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 (c) Six Labors. | ||
// Licensed under the Six Labors Split License. | ||
|
||
using SixLabors.ImageSharp.Metadata.Profiles.Exif; | ||
|
||
namespace SixLabors.ImageSharp.Formats.Tiff.Constants; | ||
|
||
/// <summary> | ||
/// Enumeration representing the set of inks used in a separated (<see cref="TiffPhotometricInterpretation.Separated"/>) image. | ||
/// </summary> | ||
public enum TiffInkSet : ushort | ||
{ | ||
/// <summary> | ||
/// CMYK. | ||
/// The order of the components is cyan, magenta, yellow, black. | ||
/// Usually, a value of 0 represents 0% ink coverage and a value of 255 represents 100% ink coverage for that component, but see DotRange. | ||
/// The <see cref="ExifTagValue.InkNames"/> field should not exist when InkSet=1. | ||
/// </summary> | ||
Cmyk = 1, | ||
|
||
/// <summary> | ||
/// Not CMYK. | ||
/// See the <see cref="ExifTagValue.InkNames"/> field for a description of the inks to be used. | ||
/// </summary> | ||
NotCmyk = 2 | ||
} |
Oops, something went wrong.
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.
Gif doesn't tell you in advance the length of the combined LZW segment blocks. You have to read each one which must be decoded to read the next one.