d2phap/ImageGlass · error · InvalidDataException
IGE: Native codec '{CodecId}' returned an unsupported pixel
Error message
IGE: Native codec '{CodecId}' returned an unsupported pixel buffer layout. What it means
Thrown by NativeCodecProxy.WrapPluginBufferAsImage when SKImage.FromPixels returns null even though the pixel buffer, format, and dimensions individually passed validation. Skia rejected the combined layout — usually because the stride is too small for the declared width/color type, or the total byte count (stride * height) does not match the SKData length passed to FromPixels.
Source
Thrown at source/ImageGlass.Lib/Plugins/NativeCodecProxy.cs:839
CodecApiPtr = (nint)_codecApi,
Buffer = buffer,
PluginId = _plugin.PluginId,
LiveToken = _plugin.LiveToken,
};
// Wrap the plugin pointer in SKData with a release callback, then build the SKImage.
var byteCount = checked(buffer.Stride * buffer.Height);
var data = SKData.Create((nint)buffer.Data, byteCount,
PluginPixelBufferRelease.ReleaseData, carrier);
var image = SKImage.FromPixels(info, data, buffer.Stride);
if (image is null)
{
// Skia rejected the layout; release the plugin buffer ourselves.
data?.Dispose();
carrier.ReleaseFromHost();
throw new InvalidDataException(
$"IGE: Native codec '{CodecId}' returned an unsupported pixel buffer layout.");
}
return image;
}
/// <summary>
/// Maps an <see cref="IGPixelFormat"/> to the corresponding Skia color/alpha types.
/// Returns (<see cref="SKColorType.Unknown"/>, <see cref="SKAlphaType.Unknown"/>) when the
/// host has no compatible Skia format for the buffer.
/// </summary>
internal static (SKColorType ColorType, SKAlphaType AlphaType) MapPixelFormat(IGPixelFormat format)
{
return format switch
{
IGPixelFormat.Bgra8Unorm => (SKColorType.Bgra8888, SKAlphaType.Unpremul),
IGPixelFormat.Rgba8Unorm => (SKColorType.Rgba8888, SKAlphaType.Unpremul),View on GitHub (pinned to 4a3c4fecef)
Solutions
- Have the plugin compute Stride as at least width * bytesPerPixel for the chosen IGPixelFormat, with any padding it actually writes.
- Verify the byte count the plugin allocated matches stride * height exactly (the host wraps stride*height in SKData at NativeCodecProxy.cs:837).
- Check the IGPixelBuffer struct field order in the plugin matches the SDK header exactly — a swapped Stride is the most subtle cause.
- Disable the plugin and decode with a built-in codec until the layout bug is fixed upstream.
Example fix
// before
var image = SKImage.FromPixels(info, data, buffer.Stride);
if (image is null) { data?.Dispose(); carrier.ReleaseFromHost(); throw new InvalidDataException(...); }
// after — validate stride before Skia sees it so the error names the real problem
var minStride = info.RowBytes;
if (buffer.Stride < minStride)
throw new InvalidDataException(
$"IGE: Native codec '{CodecId}' returned stride {buffer.Stride} < required {minStride} " +
$"for {buffer.Width}x{buffer.Height} {info.ColorType}.");
var image = SKImage.FromPixels(info, data, buffer.Stride);
if (image is null) { data?.Dispose(); carrier.ReleaseFromHost(); throw new InvalidDataException(...); } Defensive patterns
Strategy: validation
Validate before calling
// Validate stride vs width/bytesPerPixel before handing to Skia.
int bpp = info.BytesPerPixel;
if (buffer.Stride < info.RowBytes)
throw new InvalidDataException($"Plugin stride {buffer.Stride} < required {info.RowBytes}");
if ((long)buffer.Stride * buffer.Height > int.MaxValue)
throw new InvalidDataException("Plugin buffer byte count overflows Int32"); Type guard
static bool IsConsistentLayout(in IGPixelBuffer b, SKImageInfo info) =>
b.Stride >= info.RowBytes && (long)b.Stride * b.Height <= int.MaxValue; Try / catch
try { image = proxy.WrapPluginBufferAsImage(in buffer, colorSpace); }
catch (InvalidDataException ex) when (ex.Message.Contains("unsupported pixel buffer layout"))
{ _log.Warn($"Plugin {proxy.CodecId} stride/layout rejected by Skia (stride={buffer.Stride}, w={buffer.Width}, h={buffer.Height})"); return BuiltInFallback(metadata); } Prevention
- Compute Stride in the plugin as at least width * bytesPerPixel, including any padding actually written.
- Match the IGPixelBuffer field order between plugin and host SDK exactly.
- Check Stride >= info.RowBytes before calling SKImage.FromPixels so the error names the real problem.
- Verify the SKData byte count equals stride * height when wrapping the plugin pointer.
When it happens
Trigger: Produced at NativeCodecProxy.cs:839 when SKImage.FromPixels(info, data, buffer.Stride) returns null. The plugin's IGPixelBuffer passed field-level checks but the stride/width/height combination is inconsistent for Skia.
Common situations: Plugin sets Stride smaller than width*bytesPerPixel (Skia requires stride >= info.RowBytes); plugin computes Stride without alignment padding the plugin actually wrote; plugin declares a width in pixels but lays out bytes with a different bpp than MapPixelFormat assumed; ABI field-order mismatch swapping Stride with another field.
Related errors
- IGE: Native codec '{CodecId}' returned an invalid pixel buff
- IGE: Native codec '{CodecId}' returned an unsupported pixel
- Native codec '{CodecId}' does not support static-raster deco
- IGE: Native codec '{CodecId}' was unloaded.
- IGE: Native codec '{CodecId}' threw during decode of '{fileP
AI-assisted analysis of d2phap/ImageGlass@4a3c4fecef (2026-08-13).
Data as JSON: /api/errors/cc10e503adfe3f97.
Report an issue: GitHub.