Установка значений RGB для уменьшения палитры в изображении PNG - PullRequest
2 голосов
/ 30 июля 2011

У меня есть следующий метод , который уменьшает размер палитры в изображении PNG.

private BufferedImage setColour(BufferedImage image) {
    IndexColorModel cm = new IndexColorModel(
            3, 
            6,       
            new byte[]{-100, 0, 0, 0, -1, 0},  // r 
            new byte[]{0, -100, 60, 0, -1, 0}, // g
            new byte[]{0, 0, 0, -100, -1, 0}); // b
    BufferedImage img = new BufferedImage(
            image.getWidth(), image.getHeight(),
            BufferedImage.TYPE_BYTE_INDEXED,
            cm);
    Graphics2D g2 = img.createGraphics();
    g2.drawImage(image, 0, 0, null);
    g2.dispose();       
    return img;
}

Я понимаю, что каждый байтовый массив используется для индексации палитры, связанной с пикселем PNG. Что я не понимаю, так это как установить значения в байтовых массивах так, чтобы я мог только немного уменьшить число цветов в изображении PNG.

1 Ответ

3 голосов
/ 31 июля 2011

Индексированная цветовая модель по существу перечисляет все цвета, которые могут использоваться в BufferedImage, с их значениями RGB.

Каждый столбец в

//          red, light green, dark green, blue, white, black
new byte[]{-100,       0,         0,        0,    -1,    0},  // red part
new byte[]{   0,    -100,        60,        0,    -1,    0},  // green part
new byte[]{   0,       0,         0,     -100,    -1,    0}   // blue part

соответствует одному цвету - я добавил их в строку комментария.

В конечном итоге в конечном изображении будут использоваться только эти цвета, все остальное будет приближено к ближайшему цвету или шаблону из двух ближайших цветов:

(in - out)
(Изображение похищено из Ответ Рекина .)

Если вы хотите уменьшить не только 6 цветов, но и большее количество, вам просто нужно перечислить больше из них. Вы можете использовать здесь предварительно определенный список или адаптировать их по статистике исходного изображения (например, если изображение состоит в основном из голубого неба, включите здесь несколько синих оттенков, но не так много других цветов). Или выберите одну из нескольких предопределенных палитр, вид которой дает наименьшее отличие от исходного изображения.

Вместо использования IndexedColorModel вы также можете использовать одну из других реализаций ColorModel. Например, это будет 64-цветное пространство с 4 уровнями прозрачности, равномерно распределенными (я думаю), использующими один байт на пиксель (два бита на цвет):

new DirectColorModel(8, 0xC0, 0x30, 0x0C, 0x03);

В этом случае для прозрачности будет использоваться только один бит, вместо зеленого - три бита (которые человеческие глаза видят более четко):

new DirectColorModel(8, 0xC0, 0x38, 0x06, 0x01);

Я не тестировал их вместе с кодировщиком PNG, пожалуйста, сделайте это.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...