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
- Check bitmap is non-null, has non-zero PixelSize, and is not disposed before copying.
- Verify the SkiaSharp version is intact/consistent (re-add the NuGet package).
- 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
- Validate the bitmap has non-zero size and is not disposed before copying.
- Keep SkiaSharp package versions consistent.
- Log the encoded stream length to distinguish empty vs corrupt.
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
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- Failed to allocate global memory
- Failed to set clipboard data
- Could not decode image
- Clipboard image copy not supported on this platform
- Failed to lock global memory
AI-assisted analysis of SubtitleEdit/subtitleedit@17a9f07487 (2026-08-13).
Data as JSON: /api/errors/4498c2559eafb11e.
Report an issue: GitHub.