d2phap/ImageGlass · error · InvalidDataException
IGE: Native codec '{CodecId}' returned an unsupported pixel
Error message
IGE: Native codec '{CodecId}' returned an unsupported pixel format ({buffer.PixelFormat}). What it means
Thrown by NativeCodecProxy.WrapPluginBufferAsImage when MapPixelFormat returns SKColorType.Unknown for the buffer's declared IGPixelFormat. The host supports a fixed set of pixel formats (Bgra8Unorm and a few others); the plugin picked a format outside that set, so Skia cannot interpret the bytes.
Source
Thrown at source/ImageGlass.Lib/Plugins/NativeCodecProxy.cs:807
/// <summary>
/// Wraps a plugin-owned <see cref="IGPixelBuffer"/> in an <see cref="SKImage"/>
/// without copying the pixels. The returned image owns the plugin buffer:
/// disposing the image calls back into the plugin's <c>FreePixelBuffer</c>
/// via the release delegate (which the SDK contract requires to be thread-safe).
/// </summary>
internal SKImage WrapPluginBufferAsImage(in IGPixelBuffer buffer, SKColorSpace? srcColorSpace)
{
// Validate the buffer before we hand it to Skia.
if (buffer.Data == null || buffer.Width <= 0 || buffer.Height <= 0)
{
throw new InvalidDataException(
$"IGE: Native codec '{CodecId}' returned an invalid pixel buffer.");
}
var (colorType, alphaType) = MapPixelFormat((IGPixelFormat)buffer.PixelFormat);
if (colorType == SKColorType.Unknown)
{
throw new InvalidDataException(
$"IGE: Native codec '{CodecId}' returned an unsupported pixel format ({buffer.PixelFormat}).");
}
var info = new SKImageInfo(buffer.Width, buffer.Height, colorType, alphaType);
if (srcColorSpace is not null)
{
info = info.WithColorSpace(srcColorSpace);
}
// Carrier holds the plugin codec API + a copy of the buffer descriptor so
// SkiaSharp can hand the pointer back to the plugin on dispose.
var carrier = new PluginPixelBufferRelease
{
CodecApiPtr = (nint)_codecApi,
Buffer = buffer,
PluginId = _plugin.PluginId,
LiveToken = _plugin.LiveToken,
};View on GitHub (pinned to 4a3c4fecef)
Solutions
- Have the plugin output one of the host-supported formats — Bgra8Unorm is the canonical one (see ReadPixelsInto comment about why BGRA Unpremul is mandatory).
- Update MapPixelFormat in NativeCodecProxy if a new legitimate format was added to the SDK and the host should accept it.
- Verify the plugin is built against the same IGPixelFormat enum values as the host (no enum drift).
- Disable the plugin and let a built-in codec decode the file in a host-native format.
Example fix
// before
var (colorType, alphaType) = MapPixelFormat((IGPixelFormat)buffer.PixelFormat);
if (colorType == SKColorType.Unknown)
throw new InvalidDataException($"IGE: Native codec '{CodecId}' returned an unsupported pixel format ({buffer.PixelFormat}).");
// after — name the enum value so the plugin author knows which format was rejected
var (colorType, alphaType) = MapPixelFormat((IGPixelFormat)buffer.PixelFormat);
if (colorType == SKColorType.Unknown)
throw new InvalidDataException(
$"IGE: Native codec '{CodecId}' returned an unsupported pixel format " +
$"({(IGPixelFormat)buffer.PixelFormat} = {buffer.PixelFormat}). Supported: Bgra8Unorm."); Defensive patterns
Strategy: validation
Validate before calling
// Before WrapPluginBufferAsImage, check the format maps to a known Skia color type.
var (ct, _) = MapPixelFormat((IGPixelFormat)buffer.PixelFormat);
if (ct == SKColorType.Unknown)
throw new InvalidDataException($"Plugin returned unsupported format {(IGPixelFormat)buffer.PixelFormat}"); Type guard
static bool IsSupportedFormat(IGPixelFormat f) =>
MapPixelFormat(f).colorType != SKColorType.Unknown; Try / catch
try { image = proxy.WrapPluginBufferAsImage(in buffer, colorSpace); }
catch (InvalidDataException ex) when (ex.Message.Contains("unsupported pixel format"))
{ _log.Warn($"Plugin {proxy.CodecId} emitted {buffer.PixelFormat}; requesting Bgra8Unorm."); return BuiltInFallback(metadata); } Prevention
- Have plugins output Bgra8Unorm (the canonical host format) unless they have a specific reason not to.
- Extend MapPixelFormat if a new legitimate format was added to the SDK.
- Ensure plugin and host share the same IGPixelFormat enum values (no enum drift).
- Document the supported format list in the plugin SDK so authors do not pick unsupported ones.
When it happens
Trigger: Produced at NativeCodecProxy.cs:807 when the IGPixelFormat in IGPixelBuffer.PixelFormat does not map to any known SKColorType. The plugin successfully produced pixels but in a layout the host cannot consume.
Common situations: Plugin author chose a format not in the host's MapPixelFormat table (e.g. a Planar YUV, a 16-bit planar HDR, or a vendor-specific format); ABI drift where PixelFormat lands at the wrong offset and reads as a garbage int; plugin built against an older SDK that used different IGPixelFormat enum values.
Related errors
- 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
- IGE: Native codec '{CodecId}' returned status {status} for '
AI-assisted analysis of d2phap/ImageGlass@4a3c4fecef (2026-08-13).
Data as JSON: /api/errors/af1059c9e16ff786.
Report an issue: GitHub.