Skip to content

Commit 6da9bc3

Browse files
Fix transparency mode, update quantized refs
1 parent 5d77de9 commit 6da9bc3

File tree

122 files changed

+307
-259
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

122 files changed

+307
-259
lines changed

src/ImageSharp/Formats/Png/PngEncoderCore.cs

+36-21
Original file line numberDiff line numberDiff line change
@@ -182,7 +182,8 @@ public void Encode<TPixel>(Image<TPixel> image, Stream stream, CancellationToken
182182
if (clearTransparency)
183183
{
184184
currentFrame = clonedFrame = currentFrame.Clone();
185-
ClearTransparentPixels(currentFrame, this.backgroundColor.Value);
185+
currentFrameRegion = currentFrame.PixelBuffer.GetRegion();
186+
ClearTransparentPixels(in currentFrameRegion, this.backgroundColor.Value);
186187
}
187188

188189
// Do not move this. We require an accurate bit depth for the header chunk.
@@ -217,7 +218,7 @@ public void Encode<TPixel>(Image<TPixel> image, Stream stream, CancellationToken
217218
{
218219
cancellationToken.ThrowIfCancellationRequested();
219220
FrameControl frameControl = new((uint)this.width, (uint)this.height);
220-
this.WriteDataChunks(frameControl, currentFrame.PixelBuffer.GetRegion(), quantized, stream, false);
221+
this.WriteDataChunks(in frameControl, in currentFrameRegion, quantized, stream, false);
221222
currentFrameIndex++;
222223
}
223224

@@ -286,9 +287,10 @@ public void Encode<TPixel>(Image<TPixel> image, Stream stream, CancellationToken
286287
background,
287288
blend);
288289

290+
Buffer2DRegion<TPixel> encodingFrameRegion = encodingFrame.PixelBuffer.GetRegion(bounds);
289291
if (clearTransparency)
290292
{
291-
ClearTransparentPixels(encodingFrame, background);
293+
ClearTransparentPixels(in encodingFrameRegion, background);
292294
}
293295

294296
// Each frame control sequence number must be incremented by the number of frame data chunks that follow.
@@ -308,7 +310,6 @@ public void Encode<TPixel>(Image<TPixel> image, Stream stream, CancellationToken
308310
paletteQuantizer,
309311
default);
310312

311-
Buffer2DRegion<TPixel> encodingFrameRegion = encodingFrame.PixelBuffer.GetRegion(bounds);
312313
sequenceNumber += this.WriteDataChunks(frameControl, in encodingFrameRegion, quantized, stream, true) + 1;
313314

314315
previousFrame = currentFrame;
@@ -392,27 +393,26 @@ private static PngFrameMetadata GetPngFrameMetadata<TPixel>(ImageFrame<TPixel> f
392393
/// <typeparam name="TPixel">The type of the pixel.</typeparam>
393394
/// <param name="clone">The cloned image frame where the transparent pixels will be changed.</param>
394395
/// <param name="color">The color to change transparent pixels to.</param>
395-
private static void ClearTransparentPixels<TPixel>(ImageFrame<TPixel> clone, Color color)
396+
private static void ClearTransparentPixels<TPixel>(in Buffer2DRegion<TPixel> clone, Color color)
396397
where TPixel : unmanaged, IPixel<TPixel>
397-
=> clone.ProcessPixelRows(accessor =>
398+
{
399+
Rgba32 rgba32 = default;
400+
Rgba32 transparent = color;
401+
for (int y = 0; y < clone.Height; y++)
398402
{
399-
// TODO: We should be able to speed this up with SIMD and masking.
400-
Rgba32 rgba32 = default;
401-
Rgba32 transparent = color;
402-
for (int y = 0; y < accessor.Height; y++)
403+
Span<TPixel> row = clone.DangerousGetRowSpan(y);
404+
for (int x = 0; x < row.Length; x++)
403405
{
404-
Span<TPixel> span = accessor.GetRowSpan(y);
405-
for (int x = 0; x < accessor.Width; x++)
406-
{
407-
span[x].ToRgba32(ref rgba32);
406+
ref TPixel pixel = ref row[x];
407+
pixel.ToRgba32(ref rgba32);
408408

409-
if (rgba32.A is 0)
410-
{
411-
span[x].FromRgba32(transparent);
412-
}
409+
if (rgba32.A is 0)
410+
{
411+
pixel.FromRgba32(transparent);
413412
}
414413
}
415-
});
414+
}
415+
}
416416

417417
/// <summary>
418418
/// Creates the quantized image and calculates and sets the bit depth.
@@ -1595,7 +1595,7 @@ private void SanitizeAndSetEncoderOptions<TPixel>(
15951595
/// <param name="paletteQuantizer">The quantizer containing any previously derived palette.</param>
15961596
/// <param name="backgroundColor">The background color.</param>
15971597
private IndexedImageFrame<TPixel>? CreateQuantizedFrame<TPixel>(
1598-
QuantizingImageEncoder encoder,
1598+
PngEncoder encoder,
15991599
PngColorType colorType,
16001600
byte bitDepth,
16011601
PngMetadata metadata,
@@ -1667,7 +1667,22 @@ private void SanitizeAndSetEncoderOptions<TPixel>(
16671667
frameQuantizer.AddPaletteColors(px.GetRegion());
16681668
}
16691669

1670-
frameQuantizer.BuildPalette(encoder.PixelSamplingStrategy, image);
1670+
if (encoder.TransparentColorMode == PngTransparentColorMode.Clear)
1671+
{
1672+
foreach (Buffer2DRegion<TPixel> region in encoder.PixelSamplingStrategy.EnumeratePixelRegions(image))
1673+
{
1674+
using Buffer2D<TPixel> clone = region.Buffer.CloneRegion(this.configuration, region.Rectangle);
1675+
Buffer2DRegion<TPixel> clonedRegion = clone.GetRegion();
1676+
1677+
ClearTransparentPixels(in clonedRegion, backgroundColor);
1678+
frameQuantizer.AddPaletteColors(clonedRegion);
1679+
}
1680+
}
1681+
else
1682+
{
1683+
frameQuantizer.BuildPalette(encoder.PixelSamplingStrategy, image);
1684+
}
1685+
16711686
return frameQuantizer.QuantizeFrame(frame, bounds);
16721687
}
16731688

src/ImageSharp/Memory/Buffer2DExtensions.cs

+33
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,39 @@ public static IMemoryGroup<T> GetMemoryGroup<T>(this Buffer2D<T> buffer)
2525
return buffer.FastMemoryGroup.View;
2626
}
2727

28+
/// <summary>
29+
/// Performs a deep clone of the buffer covering the specified <paramref name="rectangle"/>.
30+
/// </summary>
31+
/// <typeparam name="T">The element type.</typeparam>
32+
/// <param name="source">The source buffer.</param>
33+
/// <param name="configuration">The configuration.</param>
34+
/// <param name="rectangle">The rectangle to clone.</param>
35+
/// <returns>The <see cref="Buffer2D{T}"/>.</returns>
36+
internal static Buffer2D<T> CloneRegion<T>(this Buffer2D<T> source, Configuration configuration, Rectangle rectangle)
37+
where T : unmanaged
38+
{
39+
Buffer2D<T> buffer = configuration.MemoryAllocator.Allocate2D<T>(
40+
rectangle.Width,
41+
rectangle.Height,
42+
configuration.PreferContiguousImageBuffers);
43+
44+
// Optimization for when the size of the area is the same as the buffer size.
45+
Buffer2DRegion<T> sourceRegion = source.GetRegion(rectangle);
46+
if (sourceRegion.IsFullBufferArea)
47+
{
48+
sourceRegion.Buffer.FastMemoryGroup.CopyTo(buffer.FastMemoryGroup);
49+
}
50+
else
51+
{
52+
for (int y = 0; y < rectangle.Height; y++)
53+
{
54+
sourceRegion.DangerousGetRowSpan(y).CopyTo(buffer.DangerousGetRowSpan(y));
55+
}
56+
}
57+
58+
return buffer;
59+
}
60+
2861
/// <summary>
2962
/// TODO: Does not work with multi-buffer groups, should be specific to Resize.
3063
/// Copy <paramref name="columnCount"/> columns of <paramref name="buffer"/> inplace,
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
version https://git-lfs.github.com/spec/v1
2-
oid sha256:11375b15df083d98335f4a4baf0717e7fdd6b21ab2132a6815cadc787ac17e7d
2+
oid sha256:6785d108cab9e3b508e98ce10cef383037471beb2a6d14a69df6069b5fbf5f3d
33
size 9270
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
version https://git-lfs.github.com/spec/v1
2-
oid sha256:e063e97cd8a000de6830adcc3961a7dc41785d40cd4d83af10ca38d96e071362
2+
oid sha256:5d9f2745de2b6e7fc3b1403fe651f3bbba835c67a6fb410fc8a9d91a15b44328
33
size 9270

0 commit comments

Comments
 (0)