Изменить массив размеров в ColorPalette.Entries

Я хочу изменить размер в 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' не может быть назначено -- оно доступно только для чтения


person Nejc Galof    schedule 04.01.2017    source источник
comment
You are not allowed to construct a ColorPalette object directly. If you created a ColorPalette object, you could then manipulate the palette size for a particular image, which is not allowed взято из msdn. microsoft.com/en-us/library/   -  person David Pilkington    schedule 04.01.2017
comment
@DavidPilkington И все же вы можете назначить другой объект Palette изображению, даже если оно было загружено из другого изображения и содержит меньший массив Entries. Отличная логика...   -  person Nyerguds    schedule 08.03.2018


Ответы (2)


Зачем вам менять размер 8bppIndex с 256 на 4? Индексы цвета в изображении зависят от 256 индексов. Вы не хотите, чтобы индекс выходил за пределы изображения. Что, если пиксель должен иметь индекс 5? Жаль, что нет формата Format2bppIndexed.

person Jeroen van Langen    schedule 04.01.2017
comment
Некоторые GIF с 4 цветами имеют только 4 размера, но они имеют Format8bppIndexed. Если я использую по умолчанию, я получаю другую палитру. - person Nejc Galof; 04.01.2017
comment
Итак, почему вы хотите уменьшить палитру?? - person TaW; 04.01.2017
comment
Вы могли бы создать новую палитру, а затем создать изображение с ней. Я не знаю - person Jeroen van Langen; 04.01.2017
comment
@TAW: png фактически поддерживает сохранение частичных палитр. Что касается причины, ну, это делает окончательный файл меньше. - person Nyerguds; 08.08.2018

Я действительно нашел способ сделать это; png могут иметь палитры переменного размера, и платформа .Net не дополняет их при загрузке файла.

И, ">создать файл png в массиве байтов с настроенными фрагментами довольно просто.

Со связанным там кодом (в основном 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, но если у вас нет очень серьезных проблем с пространством, размер палитры обычно не имеет значения.

И если вы на самом деле редактируете изображение (что возможно с помощью LockBits и Marshal.Copy для прямого управления резервным массивом), вам нужно быть очень осторожным, чтобы никогда не использовать значение индекса выше 3 для вашего изображения. , или все это, вероятно, рухнет и сгорит.

person Nyerguds    schedule 26.01.2018