Skip to content

Support for palette access when reading indexed image formats #2404

Description

@Paul-JanPauptit

Prerequisites

  • I have written a descriptive issue title
  • I have verified that I am running the latest version of ImageSharp
  • I have verified if the problem exist in both DEBUG and RELEASE mode
  • I have searched open and closed issues to ensure it has not already been reported

ImageSharp version

3.0.0

Other ImageSharp packages and versions

Environment (Operating system, version and so on)

Windows, any

.NET Framework version

Description

I am processing 4-bpp indexed images (16 colors) for retro & fantasy platform development (TIC80 in particular). For that we often need access to the original palette of the image.

I understand this is not a primary use case for ImageSharp, but it would be great if ImageSharp offered just that... and like @JimBobSquarePants mentioned on twitter, "why not submit an issue". 😄

Steps to Reproduce

Load an indexed image. Try to access the palette.

Images

No response

Activity

  1. JimBobSquarePants commented on Nov 9, 2023

    @JimBobSquarePants
    Member

    @Paul-JanPauptit What format are your images in?

    Completed

    • gif
    • png

    For future

    • bmp
    • tiff
    • ico
    • cur
  2. Paul-JanPauptit commented on Nov 28, 2023

    @Paul-JanPauptit
    Author

    @JimBobSquarePants I am currently in a bit of crunch so my demoscene toolbuilding is on hold for a couple of weeks, but I wanted to say that I really appreciate that you have been adding this functionality. <3

    I don't have a set workflow yet, I think centering it around PNG should work perfectly. Basically being able to read out the palette and pixels should solve all my problems.

  3. JimBobSquarePants commented on Dec 1, 2023

    @JimBobSquarePants
    Member

    Happy to help!

    I'll eventually port bitmap and maybe tiff across to do it also but will leave that for future releases as it gets complicated.

  4. Beyley commented on Jan 3, 2024

    @Beyley

    Would this also extend to storing the palette used by a quantize operation on an Image for later access?

    Im trying to write a custom ImageSharp encoder for the LittleBigPlanet PSP custom texture format "MIP", which uses an 8bit indexed pixel format. currently to my knowledge, after i run a quantize with a "max colors" of 256, i need to loop over every pixel to fill out a palette myself, it would be nice if after doing this
    image
    i could somehow retrieve the palette used by the quantization, so that i can just directly write that to the file rather than needing to iterate over every pixel and fill out a palette myself (which is quite slow).

    heres how i currently get the palette after doing a quantize

    Dictionary<Rgba32, byte> outputPalette = new(256);
    {
        for (int x = 0; x < image.Width; x++)
        {
            for (int y = 0; y < image.Height; y++)
            {
                Rgba32 col = image[x, y];
                //If the color is not in the palette
                if (!outputPalette.TryGetValue(col, out _))
                {
                    //Add the color to the palette
                    outputPalette[col] = (byte)outputPalette.Count;
                }
            }
        }
    }
  5. benbaker76 commented on Mar 26, 2024

    @benbaker76

    Completed
    * [x] gif
    * [x] png

    @JimBobSquarePants Where can I find this branch?

  6. JimBobSquarePants commented on Mar 26, 2024

    @JimBobSquarePants
    Member

    Support for those types has already been released.

  7. benbaker76 commented on Mar 26, 2024

    @benbaker76

    Support for those types has already been released.

    Great! Is there an example on reading the raw palette and indices of a 4-bit / 8-bit indexed png?

  8. JimBobSquarePants commented on Mar 27, 2024

    @JimBobSquarePants
    Member

    Sure..

    You need to query the metata for each type.

    using Image<TPixel> image = ... ;
    PngMetadata metadata = image.Metadata.GetPngMetadata(); 
    
    // You want to check for null here. 
    ReadOnlySpan<Color> colorTable = metadata.ColorTable.Value.Span;
  9. benbaker76 commented on Mar 27, 2024

    @benbaker76

    Sure..

    You need to query the metata for each type.

    using Image<TPixel> image = ... ;
    PngMetadata metadata = image.Metadata.GetPngMetadata(); 
    
    // You want to check for null here. 
    ReadOnlySpan<Color> colorTable = metadata.ColorTable.Value.Span;

    That's great but how do I read the indices? What pixel format do I need to read it?

    Most of the image libraries I've looked at for .NET convert indexed pngs' to RGB. It would be fantastic if your library can read the raw indices.

    Also is it possible to write indexed pngs' in both 4-bit and 8-bit indexed formats with a custom palettes?

  10. JimBobSquarePants commented on Mar 28, 2024

    @JimBobSquarePants
    Member

    That's great but how do I read the indices? What pixel format do I need to read it?

    You don't read indices. An image buffer is a 2D representation of the decoded image pixels where the pixel format represents the requested layout in memory of each pixel. Indices are already read during decoding so there is none of that will-it-throw-an-exception nonsense you get in System.Drawing when trying to do graphics options that should be agnostic.

    ImageSharp will automatically decode the indexed image data into whatever pixel format you explicitly choose to use or the most memory efficient and appropriate pixel format.

    Also is it possible to write indexed pngs' in both 4-bit and 8-bit indexed formats with a custom palettes?

    Can you please keep questions focused and in the discussion channels. You should also read and understand the API docs before asking questions. (Also, yes you can)

  11. benbaker76 commented on Mar 28, 2024

    @benbaker76

    You don't read indices. An image buffer is a 2D representation of the decoded image pixels where the pixel format represents the requested layout in memory of each pixel. Indices are already read during decoding so there is none of that will-it-throw-an-exception nonsense you get in System.Drawing when trying to do graphics options that should be agnostic.

    Okay it looks like I need to make a feature request. Thanks for your time.

  12. benbaker76 commented on Apr 20, 2024

    @benbaker76

    I've moved to using the pngcs library.

  13. JimBobSquarePants commented on Jul 10, 2024

    @JimBobSquarePants
    Member

    Would this also extend to storing the palette used by a quantize operation on an Image for later access?

    Im trying to write a custom ImageSharp encoder for the LittleBigPlanet PSP custom texture format "MIP", which uses an 8bit indexed pixel format. currently to my knowledge, after i run a quantize with a "max colors" of 256, i need to loop over every pixel to fill out a palette myself, it would be nice if after doing this image i could somehow retrieve the palette used by the quantization, so that i can just directly write that to the file rather than needing to iterate over every pixel and fill out a palette myself (which is quite slow).

    heres how i currently get the palette after doing a quantize

    Dictionary<Rgba32, byte> outputPalette = new(256);
    {
        for (int x = 0; x < image.Width; x++)
        {
            for (int y = 0; y < image.Height; y++)
            {
                Rgba32 col = image[x, y];
                //If the color is not in the palette
                if (!outputPalette.TryGetValue(col, out _))
                {
                    //Add the color to the palette
                    outputPalette[col] = (byte)outputPalette.Count;
                }
            }
        }
    }

    Sorry, I missed this. I think you should have a look at how other quantizing image encoders do this (GifEncoderCore for example). Individual frames are quantized during encoding which yields an IndexedImageFrame contaiing the palette. This is then directly encoded.

  14. JimBobSquarePants commented on Feb 2, 2026

    @JimBobSquarePants
    Member

    All decoders now return a palette when available in the upcoming V4 release.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions