Skip to content

Commit 2127b46

Browse files
Implement PngFrameMetadata
1 parent 5b47e79 commit 2127b46

26 files changed

Lines changed: 475 additions & 184 deletions

src/ImageSharp/Formats/Gif/GifDecoderCore.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -719,7 +719,7 @@ private void SetFrameMetadata(ImageFrameMetadata metadata)
719719
gifMeta.HasTransparency = this.graphicsControlExtension.TransparencyFlag;
720720
gifMeta.TransparencyIndex = this.graphicsControlExtension.TransparencyIndex;
721721
gifMeta.FrameDelay = this.graphicsControlExtension.DelayTime;
722-
gifMeta.DisposalMethod = this.graphicsControlExtension.DisposalMethod;
722+
gifMeta.DisposalMode = this.graphicsControlExtension.DisposalMethod;
723723
}
724724
}
725725

src/ImageSharp/Formats/Gif/GifEncoderCore.cs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -171,7 +171,7 @@ public void Encode<TPixel>(Image<TPixel> image, Stream stream, CancellationToken
171171
// Capture the global palette for reuse on subsequent frames and cleanup the quantized frame.
172172
TPixel[] globalPalette = image.Frames.Count == 1 ? [] : quantized.Palette.ToArray();
173173

174-
this.EncodeAdditionalFrames(stream, image, globalPalette, derivedTransparencyIndex, frameMetadata.DisposalMethod);
174+
this.EncodeAdditionalFrames(stream, image, globalPalette, derivedTransparencyIndex, frameMetadata.DisposalMode);
175175

176176
stream.WriteByte(GifConstants.EndIntroducer);
177177

@@ -183,7 +183,7 @@ private static GifMetadata GetGifMetadata<TPixel>(Image<TPixel> image)
183183
{
184184
if (image.Metadata.TryGetGifMetadata(out GifMetadata? gif))
185185
{
186-
return (GifMetadata)gif.DeepClone();
186+
return gif.DeepClone();
187187
}
188188

189189
if (image.Metadata.TryGetPngMetadata(out PngMetadata? png))
@@ -208,7 +208,7 @@ private static GifFrameMetadata GetGifFrameMetadata<TPixel>(ImageFrame<TPixel> f
208208
GifFrameMetadata? metadata = null;
209209
if (frame.Metadata.TryGetGifMetadata(out GifFrameMetadata? gif))
210210
{
211-
metadata = (GifFrameMetadata)gif.DeepClone();
211+
metadata = gif.DeepClone();
212212
}
213213
else if (frame.Metadata.TryGetPngMetadata(out PngFrameMetadata? png))
214214
{
@@ -282,7 +282,7 @@ private void EncodeAdditionalFrames<TPixel>(
282282
previousDisposalMode);
283283

284284
previousFrame = currentFrame;
285-
previousDisposalMode = gifMetadata.DisposalMethod;
285+
previousDisposalMode = gifMetadata.DisposalMode;
286286
}
287287

288288
if (hasPaletteQuantizer)
@@ -664,7 +664,7 @@ private void WriteGraphicalControlExtension(GifFrameMetadata metadata, Stream st
664664
bool hasTransparency = metadata.HasTransparency;
665665

666666
byte packedValue = GifGraphicControlExtension.GetPackedValue(
667-
disposalMode: metadata.DisposalMethod,
667+
disposalMode: metadata.DisposalMode,
668668
transparencyFlag: hasTransparency);
669669

670670
GifGraphicControlExtension extension = new(

src/ImageSharp/Formats/Gif/GifFrameMetadata.cs

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ private GifFrameMetadata(GifFrameMetadata other)
2626
{
2727
this.ColorTableMode = other.ColorTableMode;
2828
this.FrameDelay = other.FrameDelay;
29-
this.DisposalMethod = other.DisposalMethod;
29+
this.DisposalMode = other.DisposalMode;
3030

3131
if (other.LocalColorTable?.Length > 0)
3232
{
@@ -73,7 +73,7 @@ private GifFrameMetadata(GifFrameMetadata other)
7373
/// Primarily used in Gif animation, this field indicates the way in which the graphic is to
7474
/// be treated after being displayed.
7575
/// </summary>
76-
public FrameDisposalMode DisposalMethod { get; set; }
76+
public FrameDisposalMode DisposalMode { get; set; }
7777

7878
/// <inheritdoc />
7979
public static GifFrameMetadata FromFormatConnectingFrameMetadata(FormatConnectingFrameMetadata metadata)
@@ -100,7 +100,7 @@ public static GifFrameMetadata FromFormatConnectingFrameMetadata(FormatConnectin
100100
LocalColorTable = metadata.ColorTable,
101101
ColorTableMode = metadata.ColorTableMode,
102102
FrameDelay = (int)Math.Round(metadata.Duration.TotalMilliseconds / 10),
103-
DisposalMethod = metadata.DisposalMode,
103+
DisposalMode = metadata.DisposalMode,
104104
HasTransparency = hasTransparency,
105105
TransparencyIndex = hasTransparency ? unchecked((byte)index) : byte.MinValue,
106106
};
@@ -109,10 +109,9 @@ public static GifFrameMetadata FromFormatConnectingFrameMetadata(FormatConnectin
109109
/// <inheritdoc />
110110
public FormatConnectingFrameMetadata ToFormatConnectingFrameMetadata()
111111
{
112-
// throw new NotImplementedException();
113112
// For most scenarios we would consider the blend method to be 'Over' however if a frame has a disposal method of 'RestoreToBackground' or
114113
// has a local palette with 256 colors and is not transparent we should use 'Source'.
115-
bool blendSource = this.DisposalMethod == FrameDisposalMode.RestoreToBackground || (this.LocalColorTable?.Length == 256 && !this.HasTransparency);
114+
bool blendSource = this.DisposalMode == FrameDisposalMode.RestoreToBackground || (this.LocalColorTable?.Length == 256 && !this.HasTransparency);
116115

117116
// If the color table is global and frame has no transparency. Consider it 'Source' also.
118117
blendSource |= this.ColorTableMode == FrameColorTableMode.Global && !this.HasTransparency;
@@ -122,7 +121,7 @@ public FormatConnectingFrameMetadata ToFormatConnectingFrameMetadata()
122121
ColorTable = this.LocalColorTable,
123122
ColorTableMode = this.ColorTableMode,
124123
Duration = TimeSpan.FromMilliseconds(this.FrameDelay * 10),
125-
DisposalMode = this.DisposalMethod,
124+
DisposalMode = this.DisposalMode,
126125
BlendMode = blendSource ? FrameBlendMode.Source : FrameBlendMode.Over,
127126
};
128127
}
@@ -158,7 +157,7 @@ internal static GifFrameMetadata FromAnimatedMetadata(AnimatedImageFrameMetadata
158157
LocalColorTable = metadata.ColorTable,
159158
ColorTableMode = metadata.ColorTableMode,
160159
FrameDelay = (int)Math.Round(metadata.Duration.TotalMilliseconds / 10),
161-
DisposalMethod = metadata.DisposalMode,
160+
DisposalMode = metadata.DisposalMode,
162161
HasTransparency = hasTransparency,
163162
TransparencyIndex = hasTransparency ? unchecked((byte)index) : byte.MinValue,
164163
};

src/ImageSharp/Formats/Gif/GifMetadata.cs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -129,16 +129,20 @@ public FormatConnectingMetadata ToFormatConnectingMetadata()
129129
? this.GlobalColorTable.Value.Span[this.BackgroundColorIndex]
130130
: Color.Transparent;
131131

132+
int bpp = this.GlobalColorTable.HasValue
133+
? Numerics.Clamp(ColorNumerics.GetBitsNeededForColorDepth(this.GlobalColorTable.Value.Length), 1, 8)
134+
: 8;
135+
132136
return new()
133137
{
134138
AnimateRootFrame = true,
135139
BackgroundColor = color,
136140
ColorTable = this.GlobalColorTable,
137141
ColorTableMode = this.ColorTableMode,
138-
PixelTypeInfo = new PixelTypeInfo(24)
142+
PixelTypeInfo = new PixelTypeInfo(bpp)
139143
{
140144
ColorType = PixelColorType.Indexed,
141-
ComponentInfo = PixelComponentInfo.Create(3, 24, 8, 8, 8),
145+
ComponentInfo = PixelComponentInfo.Create(1, bpp, bpp),
142146
},
143147
RepeatCount = this.RepeatCount,
144148
};

src/ImageSharp/Formats/Gif/MetadataExtensions.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ internal static AnimatedImageFrameMetadata ToAnimatedImageFrameMetadata(this Gif
8080
{
8181
// For most scenarios we would consider the blend method to be 'Over' however if a frame has a disposal method of 'RestoreToBackground' or
8282
// has a local palette with 256 colors and is not transparent we should use 'Source'.
83-
bool blendSource = source.DisposalMethod == FrameDisposalMode.RestoreToBackground || (source.LocalColorTable?.Length == 256 && !source.HasTransparency);
83+
bool blendSource = source.DisposalMode == FrameDisposalMode.RestoreToBackground || (source.LocalColorTable?.Length == 256 && !source.HasTransparency);
8484

8585
// If the color table is global and frame has no transparency. Consider it 'Source' also.
8686
blendSource |= source.ColorTableMode == FrameColorTableMode.Global && !source.HasTransparency;
@@ -90,7 +90,7 @@ internal static AnimatedImageFrameMetadata ToAnimatedImageFrameMetadata(this Gif
9090
ColorTable = source.LocalColorTable,
9191
ColorTableMode = source.ColorTableMode,
9292
Duration = TimeSpan.FromMilliseconds(source.FrameDelay * 10),
93-
DisposalMode = source.DisposalMethod,
93+
DisposalMode = source.DisposalMode,
9494
BlendMode = blendSource ? FrameBlendMode.Source : FrameBlendMode.Over,
9595
};
9696
}

src/ImageSharp/Formats/IImageFormat.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright (c) Six Labors.
1+
// Copyright (c) Six Labors.
22
// Licensed under the Six Labors Split License.
33

44
namespace SixLabors.ImageSharp.Formats;
@@ -14,12 +14,12 @@ public interface IImageFormat
1414
string Name { get; }
1515

1616
/// <summary>
17-
/// Gets the default mimetype that the image format uses
17+
/// Gets the default mime type that the image format uses
1818
/// </summary>
1919
string DefaultMimeType { get; }
2020

2121
/// <summary>
22-
/// Gets all the mimetypes that have been used by this image format.
22+
/// Gets all the mime types that have been used by this image format.
2323
/// </summary>
2424
IEnumerable<string> MimeTypes { get; }
2525

src/ImageSharp/Formats/Pbm/PbmMetadata.cs

Lines changed: 94 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
11
// Copyright (c) Six Labors.
22
// Licensed under the Six Labors Split License.
33

4+
using SixLabors.ImageSharp.PixelFormats;
5+
46
namespace SixLabors.ImageSharp.Formats.Pbm;
57

68
/// <summary>
79
/// Provides PBM specific metadata information for the image.
810
/// </summary>
9-
public class PbmMetadata : IDeepCloneable
11+
public class PbmMetadata : IFormatMetadata<PbmMetadata>
1012
{
1113
/// <summary>
1214
/// Initializes a new instance of the <see cref="PbmMetadata"/> class.
@@ -38,8 +40,97 @@ private PbmMetadata(PbmMetadata other)
3840
/// <summary>
3941
/// Gets or sets the data type of the pixel components.
4042
/// </summary>
41-
public PbmComponentType ComponentType { get; set; }
43+
public PbmComponentType ComponentType { get; set; } = PbmComponentType.Byte;
44+
45+
/// <inheritdoc/>
46+
public static PbmMetadata FromFormatConnectingMetadata(FormatConnectingMetadata metadata)
47+
{
48+
PbmColorType color;
49+
PixelColorType colorType = metadata.PixelTypeInfo.ColorType ?? PixelColorType.Luminance;
50+
51+
switch (colorType)
52+
{
53+
case PixelColorType.Binary:
54+
color = PbmColorType.BlackAndWhite;
55+
break;
56+
case PixelColorType.Luminance:
57+
color = PbmColorType.Grayscale;
58+
break;
59+
default:
60+
if (colorType.HasFlag(PixelColorType.RGB) || colorType.HasFlag(PixelColorType.BGR))
61+
{
62+
color = PbmColorType.Rgb;
63+
}
64+
else
65+
{
66+
color = PbmColorType.Grayscale;
67+
}
68+
69+
break;
70+
}
71+
72+
PbmComponentType componentType = PbmComponentType.Short;
73+
int bpp = metadata.PixelTypeInfo.BitsPerPixel;
74+
if (bpp == 1)
75+
{
76+
componentType = PbmComponentType.Bit;
77+
}
78+
else if (bpp <= 8)
79+
{
80+
componentType = PbmComponentType.Byte;
81+
}
82+
83+
return new PbmMetadata
84+
{
85+
ColorType = color,
86+
ComponentType = componentType
87+
};
88+
}
89+
90+
/// <inheritdoc/>
91+
public FormatConnectingMetadata ToFormatConnectingMetadata()
92+
{
93+
int bpp;
94+
PixelColorType colorType;
95+
PixelComponentInfo info;
96+
switch (this.ColorType)
97+
{
98+
case PbmColorType.BlackAndWhite:
99+
bpp = 1;
100+
colorType = PixelColorType.Binary;
101+
info = PixelComponentInfo.Create(1, bpp, 1);
102+
break;
103+
case PbmColorType.Grayscale:
104+
bpp = 8;
105+
colorType = PixelColorType.Luminance;
106+
info = PixelComponentInfo.Create(1, bpp, 8);
107+
break;
108+
case PbmColorType.Rgb:
109+
bpp = 24;
110+
colorType = PixelColorType.RGB;
111+
info = PixelComponentInfo.Create(3, bpp, 8, 8, 8);
112+
break;
113+
default:
114+
bpp = 8;
115+
colorType = PixelColorType.Luminance;
116+
info = PixelComponentInfo.Create(1, bpp, 8);
117+
break;
118+
}
119+
120+
return new FormatConnectingMetadata
121+
{
122+
PixelTypeInfo = new PixelTypeInfo(bpp)
123+
{
124+
AlphaRepresentation = PixelAlphaRepresentation.None,
125+
ColorType = colorType,
126+
ComponentInfo = info,
127+
},
128+
};
129+
}
130+
131+
/// <inheritdoc/>
132+
IDeepCloneable IDeepCloneable.DeepClone() => this.DeepClone();
42133

43134
/// <inheritdoc/>
44-
public IDeepCloneable DeepClone() => new PbmMetadata(this);
135+
public PbmMetadata DeepClone() => new(this);
45136
}

src/ImageSharp/Formats/Png/Chunks/FrameControl.cs

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,8 @@ public FrameControl(
2222
uint yOffset,
2323
ushort delayNumerator,
2424
ushort delayDenominator,
25-
PngDisposalMethod disposeOperation,
26-
PngBlendMethod blendOperation)
25+
FrameDisposalMode disposalMode,
26+
FrameBlendMode blendMode)
2727
{
2828
this.SequenceNumber = sequenceNumber;
2929
this.Width = width;
@@ -32,8 +32,8 @@ public FrameControl(
3232
this.YOffset = yOffset;
3333
this.DelayNumerator = delayNumerator;
3434
this.DelayDenominator = delayDenominator;
35-
this.DisposeOperation = disposeOperation;
36-
this.BlendOperation = blendOperation;
35+
this.DisposalMode = disposalMode;
36+
this.BlendMode = blendMode;
3737
}
3838

3939
/// <summary>
@@ -84,12 +84,12 @@ public FrameControl(
8484
/// <summary>
8585
/// Gets the type of frame area disposal to be done after rendering this frame
8686
/// </summary>
87-
public PngDisposalMethod DisposeOperation { get; }
87+
public FrameDisposalMode DisposalMode { get; }
8888

8989
/// <summary>
9090
/// Gets the type of frame area rendering for this frame
9191
/// </summary>
92-
public PngBlendMethod BlendOperation { get; }
92+
public FrameBlendMode BlendMode { get; }
9393

9494
public Rectangle Bounds => new((int)this.XOffset, (int)this.YOffset, (int)this.Width, (int)this.Height);
9595

@@ -137,8 +137,8 @@ public void WriteTo(Span<byte> buffer)
137137
BinaryPrimitives.WriteUInt16BigEndian(buffer[20..22], this.DelayNumerator);
138138
BinaryPrimitives.WriteUInt16BigEndian(buffer[22..24], this.DelayDenominator);
139139

140-
buffer[24] = (byte)this.DisposeOperation;
141-
buffer[25] = (byte)this.BlendOperation;
140+
buffer[24] = (byte)(this.DisposalMode - 1);
141+
buffer[25] = (byte)this.BlendMode;
142142
}
143143

144144
/// <summary>
@@ -155,6 +155,6 @@ public static FrameControl Parse(ReadOnlySpan<byte> data)
155155
yOffset: BinaryPrimitives.ReadUInt32BigEndian(data[16..20]),
156156
delayNumerator: BinaryPrimitives.ReadUInt16BigEndian(data[20..22]),
157157
delayDenominator: BinaryPrimitives.ReadUInt16BigEndian(data[22..24]),
158-
disposeOperation: (PngDisposalMethod)data[24],
159-
blendOperation: (PngBlendMethod)data[25]);
158+
disposalMode: (FrameDisposalMode)(data[24] + 1),
159+
blendMode: (FrameBlendMode)data[25]);
160160
}

src/ImageSharp/Formats/Png/MetadataExtensions.cs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -69,16 +69,16 @@ internal static AnimatedImageFrameMetadata ToAnimatedImageFrameMetadata(this Png
6969
{
7070
ColorTableMode = FrameColorTableMode.Global,
7171
Duration = TimeSpan.FromMilliseconds(delay * 1000),
72-
DisposalMode = GetMode(source.DisposalMethod),
73-
BlendMode = source.BlendMethod == PngBlendMethod.Source ? FrameBlendMode.Source : FrameBlendMode.Over,
72+
DisposalMode = GetMode(source.DisposalMode),
73+
BlendMode = source.BlendMode,
7474
};
7575
}
7676

77-
private static FrameDisposalMode GetMode(PngDisposalMethod method) => method switch
77+
private static FrameDisposalMode GetMode(FrameDisposalMode method) => method switch
7878
{
79-
PngDisposalMethod.DoNotDispose => FrameDisposalMode.DoNotDispose,
80-
PngDisposalMethod.RestoreToBackground => FrameDisposalMode.RestoreToBackground,
81-
PngDisposalMethod.RestoreToPrevious => FrameDisposalMode.RestoreToPrevious,
82-
_ => FrameDisposalMode.Unspecified,
79+
FrameDisposalMode.DoNotDispose => FrameDisposalMode.DoNotDispose,
80+
FrameDisposalMode.RestoreToBackground => FrameDisposalMode.RestoreToBackground,
81+
FrameDisposalMode.RestoreToPrevious => FrameDisposalMode.RestoreToPrevious,
82+
_ => FrameDisposalMode.DoNotDispose,
8383
};
8484
}

src/ImageSharp/Formats/Png/PngBlendMethod.cs

Lines changed: 0 additions & 22 deletions
This file was deleted.

0 commit comments

Comments
 (0)