@@ -200,13 +200,10 @@ private uint ReadFrame<TPixel>(BufferedReadStream stream, ref Image<TPixel>? ima
200
200
this . RestoreToBackground ( imageFrame , backgroundColor ) ;
201
201
}
202
202
203
- using Buffer2D < TPixel > decodedImage = this . DecodeImageData < TPixel > ( frameData , webpInfo ) ;
204
- DrawDecodedImageOnCanvas ( decodedImage , imageFrame , regionRectangle ) ;
203
+ using Buffer2D < TPixel > decodedImageFrame = this . DecodeImageFrameData < TPixel > ( frameData , webpInfo ) ;
205
204
206
- if ( previousFrame != null && frameData . BlendingMethod is WebpBlendingMethod . AlphaBlending )
207
- {
208
- this . AlphaBlend ( previousFrame , imageFrame , regionRectangle ) ;
209
- }
205
+ bool blend = previousFrame != null && frameData . BlendingMethod == WebpBlendingMethod . AlphaBlending ;
206
+ DrawDecodedImageFrameOnCanvas ( decodedImageFrame , imageFrame , regionRectangle , blend ) ;
210
207
211
208
previousFrame = currentFrame ?? image . Frames . RootFrame ;
212
209
this . restoreArea = regionRectangle ;
@@ -253,7 +250,7 @@ private byte ReadAlphaData(BufferedReadStream stream)
253
250
/// <param name="frameData">The frame data.</param>
254
251
/// <param name="webpInfo">The webp information.</param>
255
252
/// <returns>A decoded image.</returns>
256
- private Buffer2D < TPixel > DecodeImageData < TPixel > ( WebpFrameData frameData , WebpImageInfo webpInfo )
253
+ private Buffer2D < TPixel > DecodeImageFrameData < TPixel > ( WebpFrameData frameData , WebpImageInfo webpInfo )
257
254
where TPixel : unmanaged, IPixel < TPixel >
258
255
{
259
256
ImageFrame < TPixel > decodedFrame = new ( Configuration . Default , ( int ) frameData . Width , ( int ) frameData . Height ) ;
@@ -291,42 +288,43 @@ private Buffer2D<TPixel> DecodeImageData<TPixel>(WebpFrameData frameData, WebpIm
291
288
/// Draws the decoded image on canvas. The decoded image can be smaller the canvas.
292
289
/// </summary>
293
290
/// <typeparam name="TPixel">The type of the pixel.</typeparam>
294
- /// <param name="decodedImage ">The decoded image.</param>
291
+ /// <param name="decodedImageFrame ">The decoded image.</param>
295
292
/// <param name="imageFrame">The image frame to draw into.</param>
296
293
/// <param name="restoreArea">The area of the frame.</param>
297
- private static void DrawDecodedImageOnCanvas < TPixel > ( Buffer2D < TPixel > decodedImage , ImageFrame < TPixel > imageFrame , Rectangle restoreArea )
294
+ /// <param name="blend">Whether to blend the decoded frame data onto the target frame.</param>
295
+ private static void DrawDecodedImageFrameOnCanvas < TPixel > (
296
+ Buffer2D < TPixel > decodedImageFrame ,
297
+ ImageFrame < TPixel > imageFrame ,
298
+ Rectangle restoreArea ,
299
+ bool blend )
298
300
where TPixel : unmanaged, IPixel < TPixel >
299
301
{
302
+ // Trim the destination frame to match the restore area. The source frame is already trimmed.
300
303
Buffer2DRegion < TPixel > imageFramePixels = imageFrame . PixelBuffer . GetRegion ( restoreArea ) ;
301
- int decodedRowIdx = 0 ;
302
- for ( int y = 0 ; y < restoreArea . Height ; y ++ )
304
+ if ( blend )
303
305
{
304
- Span < TPixel > framePixelRow = imageFramePixels . DangerousGetRowSpan ( y ) ;
305
- Span < TPixel > decodedPixelRow = decodedImage . DangerousGetRowSpan ( decodedRowIdx ++ ) [ ..restoreArea . Width ] ;
306
- decodedPixelRow . TryCopyTo ( framePixelRow ) ;
306
+ // The destination frame has already been prepopulated with the pixel data from the previous frame
307
+ // so blending will leave the desired result which takes into consideration restoration to the
308
+ // background color within the restore area.
309
+ PixelBlender < TPixel > blender =
310
+ PixelOperations < TPixel > . Instance . GetPixelBlender ( PixelColorBlendingMode . Normal , PixelAlphaCompositionMode . SrcOver ) ;
311
+
312
+ for ( int y = 0 ; y < restoreArea . Height ; y ++ )
313
+ {
314
+ Span < TPixel > framePixelRow = imageFramePixels . DangerousGetRowSpan ( y ) ;
315
+ Span < TPixel > decodedPixelRow = decodedImageFrame . DangerousGetRowSpan ( y ) [ ..restoreArea . Width ] ;
316
+
317
+ blender . Blend < TPixel > ( imageFrame . Configuration , framePixelRow , framePixelRow , decodedPixelRow , 1f ) ;
318
+ }
319
+
320
+ return ;
307
321
}
308
- }
309
322
310
- /// <summary>
311
- /// After disposing of the previous frame, render the current frame on the canvas using alpha-blending.
312
- /// If the current frame does not have an alpha channel, assume alpha value of 255, effectively replacing the rectangle.
313
- /// </summary>
314
- /// <typeparam name="TPixel">The pixel format.</typeparam>
315
- /// <param name="src">The source image.</param>
316
- /// <param name="dst">The destination image.</param>
317
- /// <param name="restoreArea">The area of the frame.</param>
318
- private void AlphaBlend < TPixel > ( ImageFrame < TPixel > src , ImageFrame < TPixel > dst , Rectangle restoreArea )
319
- where TPixel : unmanaged, IPixel < TPixel >
320
- {
321
- Buffer2DRegion < TPixel > srcPixels = src . PixelBuffer . GetRegion ( restoreArea ) ;
322
- Buffer2DRegion < TPixel > dstPixels = dst . PixelBuffer . GetRegion ( restoreArea ) ;
323
- PixelBlender < TPixel > blender = PixelOperations < TPixel > . Instance . GetPixelBlender ( PixelColorBlendingMode . Normal , PixelAlphaCompositionMode . SrcOver ) ;
324
323
for ( int y = 0 ; y < restoreArea . Height ; y ++ )
325
324
{
326
- Span < TPixel > srcPixelRow = srcPixels . DangerousGetRowSpan ( y ) ;
327
- Span < TPixel > dstPixelRow = dstPixels . DangerousGetRowSpan ( y ) ;
328
-
329
- blender . Blend < TPixel > ( this . configuration , dstPixelRow , srcPixelRow , dstPixelRow , 1f ) ;
325
+ Span < TPixel > framePixelRow = imageFramePixels . DangerousGetRowSpan ( y ) ;
326
+ Span < TPixel > decodedPixelRow = decodedImageFrame . DangerousGetRowSpan ( y ) [ ..restoreArea . Width ] ;
327
+ decodedPixelRow . CopyTo ( framePixelRow ) ;
330
328
}
331
329
}
332
330
0 commit comments