Invertir colores de mapa de bits
Tengo el siguiente problema. Tengo un programa de gráficos, y su diseño es negro, pero los gráficos (que obtengo del servidor como imágenes) son ligeros (en realidad utiliza sólo 5 colores: rojo, verde, blanco, negro y gris).
Para adaptarse a la inversión de diseño hace un buen trabajo, el único problema es que el rojo y el verde también se invierten (verde -> rosa, rojo -> verde).
- Android: startActivityForResult () con funcionalidad de botón BACK
- ClassCastException durante el uso del servicio
- Unity3D y Android Studio Integration
- No se puede realizar el almacenamiento en caché HTTP en android
- Crear una nueva cadena de un Charset lanza NoSuchMethodError (Android)
¿Hay una manera de invertir todo menos esos 2 colores, o una manera de repetir esos colores después de la inversión? ¿Y cuan costosas son esas operaciones (ya que recibo las actualizaciones de la carta bastante a menudo)?
Gracias por adelantado 🙂
ACTUALIZAR
He intentado reemplazar los colores con el método setPixel en un bucle
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); } } }
Unfortunetely, el método tarda demasiado (~ 650ms), hay una manera más rápida de hacerlo, y setPixels () método de trabajo más rápido?
- Libstreaming: utilice VLC como cliente RTSP
- Verificar condiciones iguales y no iguales para valores dobles
- Enviar notificación push GCM por java
- Android: Umano AndroidSlidingUpPanel Deslizamiento de dos paneles?
- Solicitudes HTTP de Android que funcionan en el simulador, pero no en dispositivo de uso
- SetImageResource de una cadena
- ¿Cómo anotación @Inject sabría qué clase concreta instanciar en la misma interfaz?
- Cómo imprimir en la consola en Android Studio?
Manipular un mapa de bits es mucho más rápido si copia los datos de imagen en una matriz int llamando a getPixels sólo una vez y no llamar a ninguna función dentro del bucle. Simplemente manipule la matriz y, a continuación, llame a setPixels al final.
Algo como eso:
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());
Si lo tiene disponible como BufferedImage
, puede acceder a su raster y editarlo como desee.
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);
OK visto que realmente estás usando sólo 5 colores es bastante fácil.
En cuanto a las actuaciones, no sé acerca de Android, pero puedo decir que en Java utilizando setRGB es increíblemente más lento que volver a la memoria de datos y escribir directamente en el int [].
Cuando escribo "increíblemente más lento", para darle una idea, en OS X 10.4 el código siguiente:
for ( int x = 0; x < width; x++ ) { for ( int y = 0; y < height; y++ ) { img.setRGB(x,y,0xFFFFFFFF); } }
Puede ser 100 veces (!) Más lento que:
for ( int x = 0; x < width; x++ ) { for ( int y = 0; y < height; y++ ) { array[y*width+x] = 0xFFFFFFFF; } }
Usted leyó correctamente: cien veces. Medido en un Core 2 Duo / Mac Mini / OS X 10.4.
(Por supuesto, primero tienes que tener acceso a la matriz int [], pero espero que esto no debería ser difícil)
No puedo hacer suficiente hincapié en que el problema no son los dos para los bucles: en ambos casos es el mismo sin optimizar para los bucles. Así que es realmente setRGB que es el problema aquí.
No sé si funciona en Android, pero probablemente deberías deshacerte de setRGB si quieres algo que funcione bien.
Una manera rápida sería utilizar AvoidXfermode para repintar sólo los colores que desea cambiar – a continuación, puede cambiar entre los colores que desee. Sólo tienes que hacer algo como esto:
// 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
Es posible que tenga que jugar con la tolerancia para el AvoidXfermode
, pero que debe hacer lo que desea mucho más rápido que un cálculo por píxel. Además, asegúrese de que la imagen de gráfico esté en modo ARGB8888. De forma predeterminada, Android tiende a trabajar con imágenes en modo RGB565, lo que tiende a estropear los cálculos de color como desea utilizar. Para asegurarse, puede asegurarse de que su imagen esté en modo ARGB8888 y mutable llamando a Bitmap chart = chartFromServer.copy(Config.ARGB_8888, true);
Antes de configurar el Xfermode.
Aclaración : para cambiar otros colores, no tendrías que volver a cargar las imágenes de nuevo, solo tendrías que crear otras Pinturas con los colores adecuados que quieras cambiar así:
// 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);