Skip to content

Commit 729d64e

Browse files
committed
Refactor SetFrameMetadata
Signed-off-by: 舰队的偶像-岛风酱! <frg2089@outlook.com>
1 parent 05d33f2 commit 729d64e

3 files changed

Lines changed: 60 additions & 21 deletions

File tree

src/ImageSharp/Formats/Icon/Cur/CurDecoderCore.cs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,5 +14,11 @@ public CurDecoderCore(DecoderOptions options)
1414
{
1515
}
1616

17-
protected override void SetFrameMetadata(ImageFrameMetadata metadata, in IconDirEntry entry) => metadata.GetCurMetadata().FromIconDirEntry(entry);
17+
protected override void SetFrameMetadata(ImageFrameMetadata metadata, in IconDirEntry entry, IconFrameCompression compression, Bmp.BmpBitsPerPixel bitsPerPixel)
18+
{
19+
CurFrameMetadata curFrameMetadata = metadata.GetCurMetadata();
20+
curFrameMetadata.FromIconDirEntry(entry);
21+
curFrameMetadata.Compression = compression;
22+
curFrameMetadata.BitsPerPixel = bitsPerPixel;
23+
}
1824
}

src/ImageSharp/Formats/Icon/Ico/IcoDecoderCore.cs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,11 @@ public IcoDecoderCore(DecoderOptions options)
1414
{
1515
}
1616

17-
protected override void SetFrameMetadata(ImageFrameMetadata metadata, in IconDirEntry entry)
18-
=> metadata.GetIcoMetadata().FromIconDirEntry(entry);
17+
protected override void SetFrameMetadata(ImageFrameMetadata metadata, in IconDirEntry entry, IconFrameCompression compression, Bmp.BmpBitsPerPixel bitsPerPixel)
18+
{
19+
IcoFrameMetadata icoFrameMetadata = metadata.GetIcoMetadata();
20+
icoFrameMetadata.FromIconDirEntry(entry);
21+
icoFrameMetadata.Compression = compression;
22+
icoFrameMetadata.BitsPerPixel = bitsPerPixel;
23+
}
1924
}

src/ImageSharp/Formats/Icon/IconDecoderCore.cs

Lines changed: 46 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ public Image<TPixel> Decode<TPixel>(BufferedReadStream stream, CancellationToken
3333

3434
Span<byte> flag = stackalloc byte[PngConstants.HeaderBytes.Length];
3535

36-
List<(Image<TPixel> Image, bool IsPng, int Index)> decodedEntries = new(this.Entries.Length);
36+
List<(Image<TPixel> Image, IconFrameCompression Compression, int Index)> decodedEntries = new(this.Entries.Length);
3737

3838
for (int i = 0; i < this.Entries.Length; i++)
3939
{
@@ -58,18 +58,18 @@ public Image<TPixel> Decode<TPixel>(BufferedReadStream stream, CancellationToken
5858

5959
// Decode the frame into a temp image buffer. This is disposed after the frame is copied to the result.
6060
Image<TPixel> temp = this.GetDecoder(isPng).Decode<TPixel>(stream, cancellationToken);
61-
decodedEntries.Add((temp, isPng, i));
61+
decodedEntries.Add((temp, isPng ? IconFrameCompression.Png : IconFrameCompression.Bmp, i));
6262

6363
// Since Windows Vista, the size of an image is determined from the BITMAPINFOHEADER structure or PNG image data
6464
// which technically allows storing icons with larger than 256 pixels, but such larger sizes are not recommended by Microsoft.
6565
this.Dimensions = new(Math.Max(this.Dimensions.Width, temp.Size.Width), Math.Max(this.Dimensions.Height, temp.Size.Height));
6666
}
6767

6868
ImageMetadata metadata = new();
69-
BmpMetadata? bmpMetadata = null;
7069
PngMetadata? pngMetadata = null;
7170
Image<TPixel> result = new(this.Options.Configuration, metadata, decodedEntries.Select(x =>
7271
{
72+
BmpBitsPerPixel bitsPerPixel = default;
7373
ImageFrame<TPixel> target = new(this.Options.Configuration, this.Dimensions);
7474
ImageFrame<TPixel> source = x.Image.Frames.RootFrameUnsafe;
7575
for (int y = 0; y < source.Height; y++)
@@ -78,7 +78,7 @@ public Image<TPixel> Decode<TPixel>(BufferedReadStream stream, CancellationToken
7878
}
7979

8080
// Copy the format specific frame metadata to the image.
81-
if (x.IsPng)
81+
if (x.Compression is IconFrameCompression.Png)
8282
{
8383
if (x.Index == 0)
8484
{
@@ -88,24 +88,19 @@ public Image<TPixel> Decode<TPixel>(BufferedReadStream stream, CancellationToken
8888
// Bmp does not contain frame specific metadata.
8989
target.Metadata.SetFormatMetadata(PngFormat.Instance, target.Metadata.GetPngFrameMetadata());
9090
}
91-
else if (x.Index == 0)
91+
else
9292
{
93-
bmpMetadata = x.Image.Metadata.GetBmpMetadata();
93+
bitsPerPixel = x.Image.Metadata.GetBmpMetadata().BitsPerPixel;
9494
}
9595

96-
this.SetFrameMetadata(target.Metadata, this.Entries[x.Index]);
96+
this.SetFrameMetadata(target.Metadata, this.Entries[x.Index], x.Compression, bitsPerPixel);
9797

9898
x.Image.Dispose();
9999

100100
return target;
101101
}).ToArray());
102102

103103
// Copy the format specific metadata to the image.
104-
if (bmpMetadata != null)
105-
{
106-
result.Metadata.SetFormatMetadata(BmpFormat.Instance, bmpMetadata);
107-
}
108-
109104
if (pngMetadata != null)
110105
{
111106
result.Metadata.SetFormatMetadata(PngFormat.Instance, pngMetadata);
@@ -116,23 +111,56 @@ public Image<TPixel> Decode<TPixel>(BufferedReadStream stream, CancellationToken
116111

117112
public ImageInfo Identify(BufferedReadStream stream, CancellationToken cancellationToken)
118113
{
114+
// Stream may not at 0.
115+
long basePosition = stream.Position;
119116
this.ReadHeader(stream);
120117

118+
Span<byte> flag = stackalloc byte[PngConstants.HeaderBytes.Length];
119+
121120
ImageMetadata metadata = new();
122121
ImageFrameMetadata[] frames = new ImageFrameMetadata[this.FileHeader.Count];
123122
for (int i = 0; i < frames.Length; i++)
124123
{
125-
// TODO: Use the Identify methods in each decoder to return the
126-
// format specific metadata for the image and frame.
124+
BmpBitsPerPixel bitsPerPixel = default;
125+
ref IconDirEntry entry = ref this.Entries[i];
126+
127+
// If we hit the end of the stream we should break.
128+
if (stream.Seek(basePosition + entry.ImageOffset, SeekOrigin.Begin) >= stream.Length)
129+
{
130+
break;
131+
}
132+
133+
// There should always be enough bytes for this regardless of the entry type.
134+
if (stream.Read(flag) != PngConstants.HeaderBytes.Length)
135+
{
136+
break;
137+
}
138+
139+
// Reset the stream position.
140+
stream.Seek(-PngConstants.HeaderBytes.Length, SeekOrigin.Current);
141+
142+
bool isPng = flag.SequenceEqual(PngConstants.HeaderBytes);
143+
144+
// Decode the frame into a temp image buffer. This is disposed after the frame is copied to the result.
145+
ImageInfo temp = this.GetDecoder(isPng).Identify(stream, cancellationToken);
146+
127147
frames[i] = new();
128-
this.SetFrameMetadata(frames[i], this.Entries[i]);
148+
if (isPng)
149+
{
150+
bitsPerPixel = temp.Metadata.GetBmpMetadata().BitsPerPixel;
151+
}
152+
153+
this.SetFrameMetadata(frames[i], this.Entries[i], isPng ? IconFrameCompression.Png : IconFrameCompression.Bmp, bitsPerPixel);
154+
155+
// Since Windows Vista, the size of an image is determined from the BITMAPINFOHEADER structure or PNG image data
156+
// which technically allows storing icons with larger than 256 pixels, but such larger sizes are not recommended by Microsoft.
157+
this.Dimensions = new(Math.Max(this.Dimensions.Width, temp.Size.Width), Math.Max(this.Dimensions.Height, temp.Size.Height));
129158
}
130159

131-
// TODO: Use real values from the metadata.
132-
return new(new(32), new(0), metadata, frames);
160+
return new(new(32), this.Dimensions, metadata, frames);
133161
}
134162

135-
protected abstract void SetFrameMetadata(ImageFrameMetadata metadata, in IconDirEntry entry);
163+
protected abstract void SetFrameMetadata(ImageFrameMetadata metadata, in IconDirEntry entry, IconFrameCompression compression, BmpBitsPerPixel bitsPerPixel);
136164

137165
protected void ReadHeader(Stream stream)
138166
{

0 commit comments

Comments
 (0)