Инвертировать растровые цвета - PullRequest
6 голосов
/ 07 января 2011

У меня следующая проблема. У меня есть программа для построения графиков, и ее дизайн черный, но диаграммы (которые я получаю с сервера в виде изображений) светлые (на самом деле используются только 5 цветов: красный, зеленый, белый, черный и серый).

Чтобы соответствовать дизайну, инверсия хорошо работает, единственная проблема в том, что красный и зеленый также инвертированы (зеленый -> розовый, красный -> зеленый).

Есть ли способ инвертировать все, кроме этих двух цветов, или способ перекрасить эти цвета после инверсии? И насколько дороги эти операции (так как я получаю обновления диаграммы довольно часто)?

Заранее спасибо:)

UPDATE

Я попытался заменить цвета с помощью метода setPixel в цикле

for(int x = 0 ;x < chart.getWidth();x++) {
        for(int y = 0;y < chart.getHeight();y++) {
            final int replacement = getColorReplacement(chart.getPixel(x, y));
            if(replacement != 0) {
                chart.setPixel(x, y, replacement);
            }
        }
    }

К сожалению, метод занимает слишком много времени (~ 650 мс), есть ли более быстрый способ сделать это, и будет ли метод setPixels () работать быстрее?

Ответы [ 4 ]

7 голосов
/ 07 января 2011

Управление растровым изображением происходит намного быстрее, если вы копируете данные изображения в массив int, вызывая getPixels только один раз, и не вызываете никаких функций внутри цикла.Просто манипулируйте массивом, затем в конце вызовите setPixels.

Что-то в этом роде:

int length = bitmap.getWidth()*bitmap.getHeight();
int[] array = new int[length];
bitmap.getPixels(array,0,bitmap.getWidth(),0,0,bitmap.getWidth(),bitmap.getHeight());
for (int i=0;i<length;i++){
// If the bitmap is in ARGB_8888 format
  if (array[i] == 0xff000000){
    array[i] = 0xffffffff;
  } else if ...
  }
}
bitmap.setPixels(array,0,bitmap.getWidth(),0,0,bitmap.getWidth(),bitmap.getHeight());
2 голосов
/ 07 января 2011

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

// will change red to green
Paint change1 = new Paint();
change1.setColor(Color.GREEN);
change1.setXfermode(new AvoidXfermode(Color.RED, 245, AvoidXfermode.Mode.TARGET));

Canvas c = new Canvas();
c.setBitmap(chart);
c.drawRect(0, 0, width, height, change1);

// rinse, repeat for other colors

Возможно, вам придется поиграть с допуском для AvoidXfermode, но это должно сделать то, что вы хотите, намного быстрее, чем расчёт на пиксель. Кроме того, убедитесь, что изображение диаграммы находится в режиме ARGB8888. По умолчанию Android имеет тенденцию работать с изображениями в режиме RGB565, что приводит к путанице в вычислениях цветов, которые вы хотите использовать - чтобы быть уверенным, вы можете убедиться, что ваше изображение находится в режимах ARGB8888 и , изменяемых с помощью вызов Bitmap chart = chartFromServer.copy(Config.ARGB_8888, true); перед настройкой Xfermode.

Уточнение : чтобы изменить другие цвета, вам не нужно будет заново загружать изображения заново, вам просто нужно создать другие краски с соответствующими цветами, которые вы хотите изменить, например так:

// changes green to red
Paint change1 = new Paint();
change1.setColor(Color.GREEN);
change1.setXfermode(new AvoidXfermode(Color.RED, 245, AvoidXfermode.Mode.TARGET));

// changes white to blue
Paint change2 = new Paint();
change2.setColor(Color.BLUE);
change2.setXfermode(new AvoidXfermode(Color.WHITE, 245, AvoidXfermode.Mode.TARGET));

// ... other Paints with other changes you want to apply to this image

Canvas c = new Canvas();
c.setBitmap(chart);
c.drawRect(0, 0, width, height, change1);
c.drawRect(0, 0, width, height, change2);
//...
c.drawRect(0, 0, width, height, changeN);
2 голосов
/ 07 января 2011

Хорошо, видно, что вы действительно используете только 5 цветов, это довольно просто.

Что касается производительности, я не знаю об Android, но могу вам сказать, что в Java используется setRGB Это на удивление медленнее, чем возвращение буфера данных и запись непосредственно в int [].

Когда я пишу «на удивление медленнее», чтобы дать вам представление, в OS X 10.4 следующий код:

for ( int x = 0; x < width; x++ ) {
    for ( int y = 0; y < height; y++ ) {
        img.setRGB(x,y,0xFFFFFFFF);
    }
}

может быть в 100 раз (!) Медленнее, чем:

for ( int x = 0; x < width; x++ ) {
    for ( int y = 0; y < height; y++ ) {
        array[y*width+x] = 0xFFFFFFFF;
    }
}

Вы правильно прочитали: сто раз.Измерено на Core 2 Duo / Mac Mini / OS X 10.4.

(конечно, сначала необходимо получить доступ к базовому массиву int [], но, надеюсь, это не должно быть сложным)

Не могу не подчеркнуть, что проблема заключается не в двух циклах: в обоих случаях это одна и та же неоптимизированная для циклов.Таким образом, проблема заключается именно в setRGB.

Я не знаю, работает ли он на Android, но вам, вероятно, следует избавиться от setRGB, если вы хотите что-то, что работает хорошо.

2 голосов
/ 07 января 2011

Если он доступен как BufferedImage, вы можете получить доступ к его растру и редактировать его, как вам угодно.

WritableRaster raster = my_image.getRaster();

// Edit all the pixels you wanna change in the raster (green -> red, pink -> green)
// for (x,y) in ...
// raster.setPixel(x, y, ...) 

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