Skip to content

Commit

Permalink
Merge pull request #2788 from SixLabors/js/multisize-tiff
Browse files Browse the repository at this point in the history
Allow decoding Tiff of different frame size.
  • Loading branch information
JimBobSquarePants committed Aug 18, 2024
2 parents 7f720db + 7d35113 commit 5c28129
Show file tree
Hide file tree
Showing 58 changed files with 699 additions and 447 deletions.
32 changes: 0 additions & 32 deletions src/ImageSharp/Formats/AnimatedImageFrameMetadata.cs

This file was deleted.

33 changes: 0 additions & 33 deletions src/ImageSharp/Formats/AnimatedImageMetadata.cs

This file was deleted.

6 changes: 6 additions & 0 deletions src/ImageSharp/Formats/Bmp/BmpMetadata.cs
Original file line number Diff line number Diff line change
Expand Up @@ -154,4 +154,10 @@ public FormatConnectingMetadata ToFormatConnectingMetadata()

/// <inheritdoc/>
public BmpMetadata DeepClone() => new(this);

/// <inheritdoc/>
public void AfterImageApply<TPixel>(Image<TPixel> destination)
where TPixel : unmanaged, IPixel<TPixel>
{
}
}
4 changes: 0 additions & 4 deletions src/ImageSharp/Formats/Cur/CurDecoderCore.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,6 @@ protected override void SetFrameMetadata(
curMetadata.Compression = compression;
curMetadata.BmpBitsPerPixel = bitsPerPixel;
curMetadata.ColorTable = colorTable;
curMetadata.EncodingWidth = curFrameMetadata.EncodingWidth;
curMetadata.EncodingHeight = curFrameMetadata.EncodingHeight;
curMetadata.HotspotX = curFrameMetadata.HotspotX;
curMetadata.HotspotY = curFrameMetadata.HotspotY;
}
}
}
20 changes: 20 additions & 0 deletions src/ImageSharp/Formats/Cur/CurFrameMetadata.cs
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,16 @@ public FormatConnectingFrameMetadata ToFormatConnectingFrameMetadata()
EncodingHeight = this.EncodingHeight
};

/// <inheritdoc/>
public void AfterFrameApply<TPixel>(ImageFrame<TPixel> source, ImageFrame<TPixel> destination)
where TPixel : unmanaged, IPixel<TPixel>
{
float ratioX = destination.Width / (float)source.Width;
float ratioY = destination.Height / (float)source.Height;
this.EncodingWidth = Scale(this.EncodingWidth, destination.Width, ratioX);
this.EncodingHeight = Scale(this.EncodingHeight, destination.Height, ratioY);
}

/// <inheritdoc/>
IDeepCloneable IDeepCloneable.DeepClone() => this.DeepClone();

Expand Down Expand Up @@ -222,4 +232,14 @@ private PixelTypeInfo GetPixelTypeInfo()
ColorType = color
};
}

private static byte Scale(byte? value, int destination, float ratio)
{
if (value is null)
{
return (byte)Math.Clamp(destination, 0, 255);
}

return Math.Min((byte)MathF.Ceiling(value.Value * ratio), (byte)Math.Clamp(destination, 0, 255));
}
}
32 changes: 6 additions & 26 deletions src/ImageSharp/Formats/Cur/CurMetadata.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,6 @@ public CurMetadata()
private CurMetadata(CurMetadata other)
{
this.Compression = other.Compression;
this.HotspotX = other.HotspotX;
this.HotspotY = other.HotspotY;
this.EncodingWidth = other.EncodingWidth;
this.EncodingHeight = other.EncodingHeight;
this.BmpBitsPerPixel = other.BmpBitsPerPixel;

if (other.ColorTable?.Length > 0)
Expand All @@ -39,28 +35,6 @@ private CurMetadata(CurMetadata other)
/// </summary>
public IconFrameCompression Compression { get; set; }

/// <summary>
/// Gets or sets the horizontal coordinates of the hotspot in number of pixels from the left. Derived from the root frame.
/// </summary>
public ushort HotspotX { get; set; }

/// <summary>
/// Gets or sets the vertical coordinates of the hotspot in number of pixels from the top. Derived from the root frame.
/// </summary>
public ushort HotspotY { get; set; }

/// <summary>
/// Gets or sets the encoding width. <br />
/// Can be any number between 0 and 255. Value 0 means a frame height of 256 pixels or greater. Derived from the root frame.
/// </summary>
public byte EncodingWidth { get; set; }

/// <summary>
/// Gets or sets the encoding height. <br />
/// Can be any number between 0 and 255. Value 0 means a frame height of 256 pixels or greater. Derived from the root frame.
/// </summary>
public byte EncodingHeight { get; set; }

/// <summary>
/// Gets or sets the number of bits per pixel.<br/>
/// Used when <see cref="Compression"/> is <see cref="IconFrameCompression.Bmp"/>
Expand Down Expand Up @@ -175,6 +149,12 @@ public FormatConnectingMetadata ToFormatConnectingMetadata()
ColorTable = this.ColorTable
};

/// <inheritdoc/>
public void AfterImageApply<TPixel>(Image<TPixel> destination)
where TPixel : unmanaged, IPixel<TPixel>
{
}

/// <inheritdoc/>
IDeepCloneable IDeepCloneable.DeepClone() => this.DeepClone();

Expand Down
2 changes: 1 addition & 1 deletion src/ImageSharp/Formats/Gif/GifEncoderCore.cs
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,7 @@ private void EncodeAdditionalFrames<TPixel>(
ImageFrame<TPixel> previousFrame = image.Frames.RootFrame;

// This frame is reused to store de-duplicated pixel buffers.
using ImageFrame<TPixel> encodingFrame = new(previousFrame.Configuration, previousFrame.Size());
using ImageFrame<TPixel> encodingFrame = new(previousFrame.Configuration, previousFrame.Size);

for (int i = 1; i < image.Frames.Count; i++)
{
Expand Down
37 changes: 6 additions & 31 deletions src/ImageSharp/Formats/Gif/GifFrameMetadata.cs
Original file line number Diff line number Diff line change
Expand Up @@ -126,40 +126,15 @@ public FormatConnectingFrameMetadata ToFormatConnectingFrameMetadata()
};
}

/// <inheritdoc/>
public void AfterFrameApply<TPixel>(ImageFrame<TPixel> source, ImageFrame<TPixel> destination)
where TPixel : unmanaged, IPixel<TPixel>
{
}

/// <inheritdoc/>
IDeepCloneable IDeepCloneable.DeepClone() => this.DeepClone();

/// <inheritdoc/>
public GifFrameMetadata DeepClone() => new(this);

internal static GifFrameMetadata FromAnimatedMetadata(AnimatedImageFrameMetadata metadata)
{
// TODO: v4 How do I link the parent metadata to the frame metadata to get the global color table?
int index = -1;
const float background = 1f;
if (metadata.ColorTable.HasValue)
{
ReadOnlySpan<Color> colorTable = metadata.ColorTable.Value.Span;
for (int i = 0; i < colorTable.Length; i++)
{
Vector4 vector = colorTable[i].ToScaledVector4();
if (vector.W < background)
{
index = i;
}
}
}

bool hasTransparency = index >= 0;

return new()
{
LocalColorTable = metadata.ColorTable,
ColorTableMode = metadata.ColorTableMode,
FrameDelay = (int)Math.Round(metadata.Duration.TotalMilliseconds / 10),
DisposalMode = metadata.DisposalMode,
HasTransparency = hasTransparency,
TransparencyIndex = hasTransparency ? unchecked((byte)index) : byte.MinValue,
};
}
}
6 changes: 6 additions & 0 deletions src/ImageSharp/Formats/Gif/GifMetadata.cs
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,12 @@ public FormatConnectingMetadata ToFormatConnectingMetadata()
};
}

/// <inheritdoc/>
public void AfterImageApply<TPixel>(Image<TPixel> destination)
where TPixel : unmanaged, IPixel<TPixel>
{
}

/// <inheritdoc/>
IDeepCloneable IDeepCloneable.DeepClone() => this.DeepClone();

Expand Down
11 changes: 11 additions & 0 deletions src/ImageSharp/Formats/IFormatFrameMetadata.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.

using SixLabors.ImageSharp.PixelFormats;

namespace SixLabors.ImageSharp.Formats;

/// <summary>
Expand All @@ -13,6 +15,15 @@ public interface IFormatFrameMetadata : IDeepCloneable
/// </summary>
/// <returns>The <see cref="FormatConnectingFrameMetadata"/>.</returns>
FormatConnectingFrameMetadata ToFormatConnectingFrameMetadata();

/// <summary>
/// This method is called after a process has been applied to the image frame.
/// </summary>
/// <typeparam name="TPixel">The type of pixel format.</typeparam>
/// <param name="source">The source image frame.</param>
/// <param name="destination">The destination image frame.</param>
void AfterFrameApply<TPixel>(ImageFrame<TPixel> source, ImageFrame<TPixel> destination)
where TPixel : unmanaged, IPixel<TPixel>;
}

/// <summary>
Expand Down
8 changes: 8 additions & 0 deletions src/ImageSharp/Formats/IFormatMetadata.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,14 @@ public interface IFormatMetadata : IDeepCloneable
/// </summary>
/// <returns>The <see cref="FormatConnectingMetadata"/>.</returns>
FormatConnectingMetadata ToFormatConnectingMetadata();

/// <summary>
/// This method is called after a process has been applied to the image.
/// </summary>
/// <typeparam name="TPixel">The type of pixel format.</typeparam>
/// <param name="destination">The destination image .</param>
void AfterImageApply<TPixel>(Image<TPixel> destination)
where TPixel : unmanaged, IPixel<TPixel>;
}

/// <summary>
Expand Down
2 changes: 0 additions & 2 deletions src/ImageSharp/Formats/Ico/IcoDecoderCore.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,6 @@ protected override void SetFrameMetadata(
curMetadata.Compression = compression;
curMetadata.BmpBitsPerPixel = bitsPerPixel;
curMetadata.ColorTable = colorTable;
curMetadata.EncodingWidth = icoFrameMetadata.EncodingWidth;
curMetadata.EncodingHeight = icoFrameMetadata.EncodingHeight;
}
}
}
20 changes: 20 additions & 0 deletions src/ImageSharp/Formats/Ico/IcoFrameMetadata.cs
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,16 @@ public FormatConnectingFrameMetadata ToFormatConnectingFrameMetadata()
EncodingHeight = this.EncodingHeight
};

/// <inheritdoc/>
public void AfterFrameApply<TPixel>(ImageFrame<TPixel> source, ImageFrame<TPixel> destination)
where TPixel : unmanaged, IPixel<TPixel>
{
float ratioX = destination.Width / (float)source.Width;
float ratioY = destination.Height / (float)source.Height;
this.EncodingWidth = Scale(this.EncodingWidth, destination.Width, ratioX);
this.EncodingHeight = Scale(this.EncodingHeight, destination.Height, ratioY);
}

/// <inheritdoc/>
IDeepCloneable IDeepCloneable.DeepClone() => this.DeepClone();

Expand Down Expand Up @@ -217,4 +227,14 @@ private PixelTypeInfo GetPixelTypeInfo()
ColorType = color
};
}

private static byte Scale(byte? value, int destination, float ratio)
{
if (value is null)
{
return (byte)Math.Clamp(destination, 0, 255);
}

return Math.Min((byte)MathF.Ceiling(value.Value * ratio), (byte)Math.Clamp(destination, 0, 255));
}
}
20 changes: 6 additions & 14 deletions src/ImageSharp/Formats/Ico/IcoMetadata.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,6 @@ public IcoMetadata()
private IcoMetadata(IcoMetadata other)
{
this.Compression = other.Compression;
this.EncodingWidth = other.EncodingWidth;
this.EncodingHeight = other.EncodingHeight;
this.BmpBitsPerPixel = other.BmpBitsPerPixel;

if (other.ColorTable?.Length > 0)
Expand All @@ -37,18 +35,6 @@ private IcoMetadata(IcoMetadata other)
/// </summary>
public IconFrameCompression Compression { get; set; }

/// <summary>
/// Gets or sets the encoding width. <br />
/// Can be any number between 0 and 255. Value 0 means a frame height of 256 pixels or greater. Derived from the root frame.
/// </summary>
public byte EncodingWidth { get; set; }

/// <summary>
/// Gets or sets the encoding height. <br />
/// Can be any number between 0 and 255. Value 0 means a frame height of 256 pixels or greater. Derived from the root frame.
/// </summary>
public byte EncodingHeight { get; set; }

/// <summary>
/// Gets or sets the number of bits per pixel.<br/>
/// Used when <see cref="Compression"/> is <see cref="IconFrameCompression.Bmp"/>
Expand Down Expand Up @@ -163,6 +149,12 @@ public FormatConnectingMetadata ToFormatConnectingMetadata()
ColorTable = this.ColorTable
};

/// <inheritdoc/>
public void AfterImageApply<TPixel>(Image<TPixel> destination)
where TPixel : unmanaged, IPixel<TPixel>
{
}

/// <inheritdoc/>
IDeepCloneable IDeepCloneable.DeepClone() => this.DeepClone();

Expand Down
6 changes: 6 additions & 0 deletions src/ImageSharp/Formats/Jpeg/JpegMetadata.cs
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,12 @@ public FormatConnectingMetadata ToFormatConnectingMetadata()
Quality = this.Quality,
};

/// <inheritdoc/>
public void AfterImageApply<TPixel>(Image<TPixel> destination)
where TPixel : unmanaged, IPixel<TPixel>
{
}

/// <inheritdoc/>
IDeepCloneable IDeepCloneable.DeepClone() => this.DeepClone();

Expand Down
6 changes: 6 additions & 0 deletions src/ImageSharp/Formats/Pbm/PbmMetadata.cs
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,12 @@ public FormatConnectingMetadata ToFormatConnectingMetadata()
PixelTypeInfo = this.GetPixelTypeInfo(),
};

/// <inheritdoc/>
public void AfterImageApply<TPixel>(Image<TPixel> destination)
where TPixel : unmanaged, IPixel<TPixel>
{
}

/// <inheritdoc/>
IDeepCloneable IDeepCloneable.DeepClone() => this.DeepClone();

Expand Down
2 changes: 1 addition & 1 deletion src/ImageSharp/Formats/Png/PngEncoderCore.cs
Original file line number Diff line number Diff line change
Expand Up @@ -231,7 +231,7 @@ public void Encode<TPixel>(Image<TPixel> image, Stream stream, CancellationToken
ImageFrame<TPixel> previousFrame = image.Frames.RootFrame;

// This frame is reused to store de-duplicated pixel buffers.
using ImageFrame<TPixel> encodingFrame = new(image.Configuration, previousFrame.Size());
using ImageFrame<TPixel> encodingFrame = new(image.Configuration, previousFrame.Size);

for (; currentFrameIndex < image.Frames.Count; currentFrameIndex++)
{
Expand Down
Loading

0 comments on commit 5c28129

Please sign in to comment.