SixLabors/ImageSharp · error · ImageFormatException

ANI bitmap resources require a supported bit depth.

Error message

ANI bitmap resources require a supported bit depth.

What it means

Thrown by AniEncoderCore.Encode when encoding with bitmapResources enabled and the ANI metadata's BitCount is not one of the ICO/BMP-supported depths (0 meaning unset/default, 1, 2, 4, 8, 16, 24, 32). Bitmap frame resources inside an ANI require a valid bit depth to be written into the icon directory entries.

Solutions

  1. Set the ANI metadata BitCount to 0 (default) or one of 1, 2, 4, 8, 16, 24, 32 before encoding.
  2. If the source depth is unsupported, encode frames as ICO/CUR resources instead of bitmapResources, or convert the images.
  3. Validate the BitCount value against the supported set before calling Save.

Example fix

// before
metadata.BitCount = 3;
await image.SaveAsAniAsync(stream, aniOptions);
// after
metadata.BitCount = 32; // supported: 0,1,2,4,8,16,24,32
await image.SaveAsAniAsync(stream, aniOptions);
Defensive patterns

Strategy: validation

Validate before calling

static readonly int[] SupportedBitDepths = { 0, 1, 2, 4, 8, 16, 24, 32 };
bool bitDepthOk = SupportedBitDepths.Contains(aniMetadata.BitCount);

Try / catch

try { await image.SaveAsAniAsync(stream, options); } catch (ImageFormatException ex) when (ex.Message.Contains("bit depth")) { /* fix metadata */ }

Prevention

When it happens

Trigger: Calling image.SaveAsAni (or Image.Save with AniEncoder) with bitmapResources configured while AniMetadata.BitCount holds an unsupported value such as 3, 5, or 64.

Common situations: Configuring ANI encoding options with a bit depth copied from a non-ICO source, typo'd metadata values, round-tripping metadata from exotic formats into ANI bitmap mode.

Understand the failure class

Background: "Invalid value" and "allowed values are" config errors: what your library rejected and how to fix it — this error's family across 41 libraries.

Related errors


AI-assisted analysis of SixLabors/ImageSharp@59ce6af6fc (2026-09-13). Data as JSON: /api/errors/c910c2e5edf16689. Report an issue: GitHub.

Appendix: source

Thrown at src/ImageSharp/Formats/Ani/AniEncoderCore.cs:65

    public void Encode<TPixel>(Image<TPixel> image, Stream stream, CancellationToken cancellationToken)
        where TPixel : unmanaged, IPixel<TPixel>
    {
        Guard.NotNull(image, nameof(image));
        Guard.NotNull(stream, nameof(stream));

        AniMetadata imageMetadata = image.Metadata.GetAniMetadata();
        AniFrameMetadata firstMetadata = image.Frames.RootFrame.Metadata.GetAniMetadata();
        AniFrameFormat firstFormat = firstMetadata.FrameFormat;
        bool bitmapResources = firstFormat is AniFrameFormat.Bmp;
        bool writeSequence = imageMetadata.Flags.HasFlag(AniHeaderFlags.ContainsSequence);
        uint displayRate = firstMetadata.FrameDelay is 0 ? imageMetadata.DisplayRate : firstMetadata.FrameDelay;
        bool hasVariableRates = false;
        int groupCount = 0;
        int maxGroupSize = 1;

        if (bitmapResources && imageMetadata.BitCount is not (0 or 1 or 2 or 4 or 8 or 16 or 24 or 32))
        {
            throw new ImageFormatException("ANI bitmap resources require a supported bit depth.");
        }

        if (bitmapResources && imageMetadata.Planes is not (0 or 1))
        {
            throw new ImageFormatException("ANI bitmap resources require exactly one color plane.");
        }

        // This validation pass derives the fixed ANI header and largest icon directory without allocating a grouping graph.
        // Encoding repeats the linear grouping scan below, trading a cheap pass for zero per-group collections.
        for (int frameIndex = 0; frameIndex < image.Frames.Count;)
        {
            AniFrameMetadata metadata = image.Frames[frameIndex].Metadata.GetAniMetadata();
            int groupSize = 1;

            if (metadata.FrameFormat is not (AniFrameFormat.Ico or AniFrameFormat.Cur or AniFrameFormat.Bmp))
            {
                // FrameFormat is public metadata and therefore must be validated before any container bytes are written.
                throw new ImageFormatException("ANI contains an unsupported embedded frame format.");

View on GitHub (pinned to 59ce6af6fc)