SubtitleEdit/subtitleedit · error · InvalidOperationException

Failed to decode bitmap

Error message

Failed to decode bitmap

What it means

Thrown in CopyImageToClipboardWindows after re-encoding the bitmap to PNG and calling SKBitmap.Decode: SkiaSharp returned null, meaning the decoded image is null (the PNG bytes produced by bitmap.Save could not be decoded back). This is a Skia decode failure on the Windows clipboard path just before converting to a BGRA DIB.

Source

Thrown at src/ui/Logic/ClipboardHelper.cs:192

        await Task.Run(() =>
        {
            IntPtr hGlobal = IntPtr.Zero;

            try
            {
                var width = bitmap.PixelSize.Width;
                var height = bitmap.PixelSize.Height;

                // Save bitmap to memory stream and read pixel data
                using var memoryStream = new MemoryStream();
                bitmap.Save(memoryStream, PngBitmapEncoderOptions.Default);
                memoryStream.Position = 0;

                // Use SkiaSharp to decode the image and get pixel data
                using var skBitmap = SkiaSharp.SKBitmap.Decode(memoryStream);
                if (skBitmap == null)
                {
                    throw new InvalidOperationException("Failed to decode bitmap");
                }

                // Ensure we have BGRA format
                using var bgraBitmap = new SkiaSharp.SKBitmap(width, height, SkiaSharp.SKColorType.Bgra8888, SkiaSharp.SKAlphaType.Premul);
                using var canvas = new SkiaSharp.SKCanvas(bgraBitmap);
                canvas.DrawBitmap(skBitmap, 0, 0);
                canvas.Flush();

                var pixels = bgraBitmap.Bytes;

                // Calculate sizes
                var stride = width * 4; // 4 bytes per pixel (BGRA)
                var imageSize = stride * height;
                var headerSize = Marshal.SizeOf<BITMAPINFOHEADER>();
                var totalSize = headerSize + imageSize;

                // Allocate global memory
                hGlobal = GlobalAlloc(GMEM_MOVEABLE, new UIntPtr((uint)totalSize));

View on GitHub (pinned to 17a9f07487)

Solutions

  1. Check bitmap is non-null, has non-zero PixelSize, and is not disposed before copying.
  2. Verify the SkiaSharp version is intact/consistent (re-add the NuGet package).
  3. Log the PNG stream length to distinguish an empty stream from a decode failure.

Example fix

// before
using var skBitmap = SKBitmap.Decode(memoryStream);
if (skBitmap == null) throw new InvalidOperationException("Failed to decode bitmap");

// after - validate the source and the encoded stream
if (bitmap.PixelSize.Width <= 0 || bitmap.PixelSize.Height <= 0)
    throw new InvalidOperationException("Source bitmap has no pixels.");
if (memoryStream.Length == 0)
    throw new InvalidOperationException("PNG re-encode produced no bytes.");
using var skBitmap = SKBitmap.Decode(memoryStream) ?? throw new InvalidOperationException("Failed to decode bitmap");
Defensive patterns

Strategy: validation

Validate before calling

if (bitmap is null || bitmap.PixelSize.Width <= 0 || bitmap.PixelSize.Height <= 0)
    throw new InvalidOperationException("Source bitmap is empty or disposed.");

Try / catch

try { await CopyImageToClipboardWindows(bitmap); }
catch (InvalidOperationException ex) when (ex.Message == "Failed to decode bitmap")
{ SeLogger.Error(ex, "SkiaSharp failed to round-trip the PNG"); throw; }

Prevention

When it happens

Trigger: bitmap.Save produced an empty/corrupt PNG stream (disposed bitmap, zero-size bitmap, or encoder failure), or the SkiaSharp build cannot decode that PNG; SKBitmap.Decode returns null on malformed input.

Common situations: Source bitmap was already disposed or has zero pixel size; a corrupt/empty in-memory image; a SkiaSharp version mismatch failing to round-trip its own PNG output; out-of-memory during decode.

Understand the failure class

Related errors


AI-assisted analysis of SubtitleEdit/subtitleedit@17a9f07487 (2026-08-13). Data as JSON: /api/errors/4498c2559eafb11e. Report an issue: GitHub.