在ColorPalette.Entries中更改大小数组

时间:2017-01-04 12:25:09

标签: c# bitmap color-palette

我想在ColorPalette.Entries中更改大小。如果我喜欢下面,我得到错误。如何以正确的方式更改条目的大小?

Bitmap bm = new Bitmap(Width, Height,PixelFormat.Format8bppIndexed);
var palette = bm.Palette;
var colr = palette.Entries;
Array.Resize(ref colr, 4);

错误:

  

'ColorPalette.Entries'无法分配 - 它是只读的

2 个答案:

答案 0 :(得分:0)

为什么要将8bppIndex的大小从256更改为4?图像中的颜色指示取决于256个索引。你不希望图像中的索引超出范围。如果像素应该是索引5怎么办?太糟糕了,没有Format2bppIndexed格式。

答案 1 :(得分:0)

我实际上找到了一种方法来做到这一点; png可以有可变大小的调色板,.Net框架在加载文件时不会填充它们。

而且,constructing a png file in a byte array with customised chunks is fairly easy.

使用那里链接的代码(主要是WritePngChunk),这将构造一个包含所需颜色的png,加载它并提取其调色板对象:

private static Byte[] PNG_IDENTIFIER = {0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A};
private static Byte[] PNG_BLANK = { 0x08, 0xD7, 0x63, 0x60, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01};

/// <summary>
/// Creates a custom-sized color palette by creating an empty png with a limited palette and extracting its palette.
/// </summary>
/// <param name="colors">The colors to convert into a palette.</param>
/// <returns>A color palette containing the given colors.</returns>
public static ColorPalette GetPalette(Color[] colors)
{
    // Silliest idea ever, but it works.
    const Int32 chunkExtraLen = 0x0C;
    Int32 lenPng = PNG_IDENTIFIER.Length;
    const Int32 lenHdr = 0x0D;
    Int32 lenPal = Math.Min(colors.Length, 0x100) * 3;
    Int32 lenData = PNG_BLANK.Length;
    Int32 fullLen = lenPng + lenHdr + chunkExtraLen + lenPal + chunkExtraLen + lenData + chunkExtraLen + chunkExtraLen;
    Int32 offset = 0;
    Byte[] emptyPng = new Byte[fullLen];
    Array.Copy(PNG_IDENTIFIER, 0, emptyPng, 0, PNG_IDENTIFIER.Length);
    offset += lenPng;
    Byte[] header = new Byte[lenHdr];
    // Width: 1
    header[3] = 1;
    // Heigth: 1
    header[7] = 1;
    // Color depth: 8
    header[8] = 8;
    // Color type: paletted
    header[9] = 3;
    WritePngChunk(emptyPng, offset, "IHDR", header);
    offset += lenHdr + chunkExtraLen;
    // Don't even need to fill this in. We just need the size.
    Byte[] palette = new Byte[lenPal];
    WritePngChunk(emptyPng, offset, "PLTE", palette);
    offset += lenPal + chunkExtraLen;
    WritePngChunk(emptyPng, offset, "IDAT", PNG_BLANK);
    offset += lenData + chunkExtraLen;
    WritePngChunk(emptyPng, offset, "IEND", new Byte[0]);
    using (MemoryStream ms = new MemoryStream(emptyPng))
    // By doing this afterwards we can ensure the alpha is correct too; the PLTE chunk
    // is RGB without alpha, and if there's a tRNS chunk to add alpha, the framework will
    // convert the image to 32 bit for some bizarre reason.
    using (Bitmap loadedImage = new Bitmap(ms))
    {
        ColorPalette pal = loadedImage.Palette;
        for (Int32 i = 0; i < pal.Entries.Length; i++)
            pal.Entries[i] = colors[i];
        return pal;
    }
}

尽管如此,我不太确定您计划用这张图片实际。我在Nintendo 64 ROM图像格式上需要此功能以实现转换准确性,但除非您有太多可怕的空间问题,否则调色板大小通常无法发挥作用。

如果您实际编辑图像(可以使用LockBitsMarshal.Copy直接操作支持数组),您需要非常小心不要

一直使用图像上任何高于3的索引值,否则整个事情可能会崩溃并烧毁。