@@ -200,13 +200,10 @@ private uint ReadFrame<TPixel>(BufferedReadStream stream, ref Image<TPixel>? ima
200200 this . RestoreToBackground ( imageFrame , backgroundColor ) ;
201201 }
202202
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 ) ;
205204
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 ) ;
210207
211208 previousFrame = currentFrame ?? image . Frames . RootFrame ;
212209 this . restoreArea = regionRectangle ;
@@ -253,7 +250,7 @@ private byte ReadAlphaData(BufferedReadStream stream)
253250 /// <param name="frameData">The frame data.</param>
254251 /// <param name="webpInfo">The webp information.</param>
255252 /// <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 )
257254 where TPixel : unmanaged, IPixel < TPixel >
258255 {
259256 ImageFrame < TPixel > decodedFrame = new ( Configuration . Default , ( int ) frameData . Width , ( int ) frameData . Height ) ;
@@ -291,42 +288,43 @@ private Buffer2D<TPixel> DecodeImageData<TPixel>(WebpFrameData frameData, WebpIm
291288 /// Draws the decoded image on canvas. The decoded image can be smaller the canvas.
292289 /// </summary>
293290 /// <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>
295292 /// <param name="imageFrame">The image frame to draw into.</param>
296293 /// <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 )
298300 where TPixel : unmanaged, IPixel < TPixel >
299301 {
302+ // Trim the destination frame to match the restore area. The source frame is already trimmed.
300303 Buffer2DRegion < TPixel > imageFramePixels = imageFrame . PixelBuffer . GetRegion ( restoreArea ) ;
301- int decodedRowIdx = 0 ;
302- for ( int y = 0 ; y < restoreArea . Height ; y ++ )
304+ if ( blend )
303305 {
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 ;
307321 }
308- }
309322
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 ) ;
324323 for ( int y = 0 ; y < restoreArea . Height ; y ++ )
325324 {
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 ) ;
330328 }
331329 }
332330
0 commit comments