OpenRA/OpenRA · error · InvalidDataException

Unknown pixel format

Error message

Unknown pixel format

What it means

Thrown by the static IsPaletted() helper when the combination of bit depth and PNG color type does not match any of the three recognized patterns: (1) bitDepth <= 8 with colorType Indexed|Color (palette-based), (2) bitDepth == 8 with colorType Color|Alpha (RGBA), or (3) bitDepth == 8 with colorType Color (RGB). Any other combination is treated as an unknown pixel format.

Source

Thrown at OpenRA.Game/FileFormats/Png.cs:481

			return isPng;
		}

		[Flags]
		enum PngColorType : byte { Indexed = 1, Color = 2, Alpha = 4 }
		enum PngFilter : byte { None, Sub, Up, Average, Paeth }

		static bool IsPaletted(byte bitDepth, PngColorType colorType)
		{
			if (bitDepth <= 8 && colorType == (PngColorType.Indexed | PngColorType.Color))
				return true;

			if (bitDepth == 8 && colorType == (PngColorType.Color | PngColorType.Alpha))
				return false;

			if (bitDepth == 8 && colorType == PngColorType.Color)
				return false;

			throw new InvalidDataException("Unknown pixel format");
		}

		static void WritePngChunk(MemoryStream output, uint type, MemoryStream input)
		{
			Span<byte> header = stackalloc byte[8];
			BinaryPrimitives.WriteInt32BigEndian(header[..4], (int)input.Length);
			BinaryPrimitives.WriteUInt32BigEndian(header[4..], type);

			if (!input.TryGetBuffer(out var dataSegment))
				dataSegment = new ArraySegment<byte>(input.ToArray());

			ReadOnlySpan<byte> data = dataSegment.AsSpan(0, (int)input.Length);

			output.Write(header);
			output.Write(data);

			var crc = 0xFFFFFFFF;
			crc = CRC32.Update(crc, header[4..]);

View on GitHub (pinned to a520984d91)

Solutions

  1. Re-export the PNG as 8-bit RGB (color type 2) or 8-bit RGBA (color type 6).
  2. Convert to 8-bit: `convert input.png -depth 8 output.png`.
  3. Convert grayscale to RGB: `convert input.png -type TrueColor output.png`.
  4. For palette-based images, ensure bit depth is <= 8 with color type 3 (indexed).

Example fix

# convert 16-bit or grayscale PNG to 8-bit RGB
convert input.png -depth 8 -type TrueColor output.png

# or for RGBA
convert input.png -depth 8 -type TrueColorAlpha output.png
Defensive patterns

Strategy: validation

Validate before calling

// Check IHDR bit depth and color type before loading
if (!Png.Verify(stream)) return;
stream.Position = 8 + 4 + 4; // skip sig + length + type
var ihdr = new byte[13];
stream.Read(ihdr, 0, 13);
stream.Seek(0, SeekOrigin.Begin);
var bitDepth = ihdr[8];
var colorType = ihdr[9]; // 0=gray, 2=rgb, 3=indexed, 4=gray+alpha, 6=rgba

if (bitDepth != 8 && !(bitDepth <= 8 && colorType == 3))
    throw new InvalidDataException($"Unsupported bit depth {bitDepth}. Use 8-bit.");
if (colorType != 2 && colorType != 3 && colorType != 6)
    throw new InvalidDataException($"Unsupported color type {colorType}. Use RGB(2), RGBA(6), or Indexed(3).");

Try / catch

try
{
    var png = new Png(stream);
}
catch (InvalidDataException ex) when (ex.Message == "Unknown pixel format")
{
    logger.LogError($"Unsupported PNG pixel format — re-export as 8-bit RGB or RGBA: {ex.Message}");
}

Prevention

When it happens

Trigger: Constructing `new Png(stream)` where the IHDR chunk specifies a bit depth / color type combination not in the supported set. For example: 16-bit depth, grayscale (colorType=0), grayscale+alpha (colorType=4), or bitDepth < 8 with a non-indexed color type. IsPaletted() is called during IHDR parsing and throws for unsupported formats.

Common situations: A 16-bit-per-channel PNG was provided (OpenRA only supports 8-bit). A grayscale PNG (color type 0) was used instead of RGB/RGBA. A grayscale+alpha PNG (color type 4). An unusual bit depth like 2 or 4 with a non-indexed color type.

Related errors


AI-assisted analysis of OpenRA/OpenRA@a520984d91 (2026-08-13). Data as JSON: /api/errors/d175b10a5fc208b2. Report an issue: GitHub.