Pregunta

Estoy intentando acceder a los datos sin procesar de un mapa de bits en formato ARGB_8888 en Android, usando el copyPixelsToBuffer y copyPixelsFromBuffer métodos.Sin embargo, la invocación de esas llamadas parece aplicar siempre el canal alfa a los canales rgb.Necesito los datos sin procesar en un byte[] o similar (para pasar por JNI;sí, conozco bitmap.h en Android 2.2, no puedo usarlo).

Aquí hay una muestra:

    // Create 1x1 Bitmap with alpha channel, 8 bits per channel
    Bitmap one = Bitmap.createBitmap(1,1,Bitmap.Config.ARGB_8888);
    one.setPixel(0,0,0xef234567);
    Log.v("?","hasAlpha() = "+Boolean.toString(one.hasAlpha()));
    Log.v("?","pixel before = "+Integer.toHexString(one.getPixel(0,0)));

    // Copy Bitmap to buffer
    byte[] store = new byte[4];
    ByteBuffer buffer  = ByteBuffer.wrap(store);
    one.copyPixelsToBuffer(buffer);

    // Change value of the pixel
    int value=buffer.getInt(0);
    Log.v("?", "value before = "+Integer.toHexString(value));
    value = (value >> 8) | 0xffffff00;
    buffer.putInt(0, value);
    value=buffer.getInt(0);
    Log.v("?", "value after = "+Integer.toHexString(value));

    // Copy buffer back to Bitmap
    buffer.position(0);
    one.copyPixelsFromBuffer(buffer);
    Log.v("?","pixel after = "+Integer.toHexString(one.getPixel(0,0)));

El registro luego muestra

hasAlpha() = true
pixel before = ef234567
value before = 214161ef
value after = ffffff61
pixel after = 619e9e9e

Entiendo que el orden de los canales argb es diferente;está bien.Pero no quiero que el canal alfa se aplique en cada copia (que es lo que parece estar haciendo).

¿Es así como copyPixelsToBuffer y copyPixelsFromBuffer se supone que funcionan?Está ahí cualquier ¿Manera de obtener los datos sin procesar en un byte []?

Agregado en respuesta a la respuesta a continuación:

Poniéndolo dentro buffer.order(ByteOrder.nativeOrder()); antes de copyPixelsToBuffer cambia el resultado, pero aún no de la forma que quiero:

pixel before = ef234567
value before = ef614121
value after = ffffff41
pixel after = ff41ffff

Parece sufrir esencialmente el mismo problema (se aplica alfa en cada copyPixelsFrom/ToBuffer).

¿Fue útil?

Solución

Me doy cuenta de que esto está muy obsoleto y probablemente no te ayudará ahora, pero me encontré con esto recientemente al intentar obtener copyPixelsFromBuffer para trabajar en mi aplicación.(¡Gracias por hacer esta pregunta, por cierto!Me ahorraste toneladas de tiempo en la depuración). Estoy agregando esta respuesta con la esperanza de que ayude a otros como yo en el futuro...

Aunque todavía no he usado esto para asegurarme de que funcione, parece que, a partir del nivel API 19, finalmente tendremos una manera de especificar que no "aplicar el alfa" (también conocido comopremultiplicar) dentro Bitmap.Están agregando un setPremultiplied(boolean) método que debería ayudar en situaciones como esta en el futuro al permitirnos especificar false.

¡Espero que esto ayude!

Otros consejos

Una forma de acceder a los datos en Bitmap es utilizar el método getPixels().A continuación puede encontrar un ejemplo que utilicé para obtener una imagen en escala de grises a partir de datos argb y luego volver de la matriz de bytes al mapa de bits (por supuesto, si necesita rgb, reserve 3x bytes y guárdelos todos...):

/*Free to use licence by Sami Varjo (but nice if you retain this line)*/

public final class BitmapConverter {

    private BitmapConverter(){};

   /**
    * Get grayscale data from argb image to byte array
    */
   public static byte[] ARGB2Gray(Bitmap img)
   {

       int width = img.getWidth();
       int height = img.getHeight();

       int[] pixels = new int[height*width];
       byte grayIm[] = new byte[height*width];

       img.getPixels(pixels,0,width,0,0,width,height);

       int pixel=0;
       int count=width*height;

       while(count-->0){
           int inVal = pixels[pixel];

           //Get the pixel channel values from int 
           double r = (double)( (inVal & 0x00ff0000)>>16 );
           double g = (double)( (inVal & 0x0000ff00)>>8  );
           double b = (double)(  inVal & 0x000000ff)      ;

           grayIm[pixel++] = (byte)( 0.2989*r + 0.5870*g + 0.1140*b );
       }

       return grayIm;
   }

   /**
    * Create a gray scale bitmap from byte array
    */
   public static Bitmap gray2ARGB(byte[] data, int width, int height)
   {
       int count = height*width;
       int[] outPix = new int[count];
       int pixel=0;
       while(count-->0){
           int val = data[pixel] & 0xff; //convert byte to unsigned
           outPix[pixel++] = 0xff000000 | val << 16 | val << 8 | val ;
       }

       Bitmap out =  Bitmap.createBitmap(outPix,0,width,width, height, Bitmap.Config.ARGB_8888);
       return out;
   }

}

Supongo que esto podría tener que ver con el orden de bytes del ByteBuffer que estás utilizando.ByteBuffer usa big endian de forma predeterminada.Establezca la endianess en el búfer con

buffer.order(ByteOrder.nativeOrder());

Vea si ayuda.

Además, copyPixelsFromBuffer/copyPixelsToBuffer no cambia los datos de los píxeles de ninguna manera.Se copian en bruto.

Esta es una pregunta antigua, pero llegué al mismo problema y descubrí que los bytes del mapa de bits están premultiplicados, puede configurar el mapa de bits (a partir de API 19) para que no multiplique previamente el búfer, sino en la API. no dan ninguna garantía.

De los documentos:

public final void setPremultiplied(boolean premultiplied)

Establece si el mapa de bits debe tratar sus datos como premultiplicados.El sistema de visualización y Canvas siempre tratan los mapas de bits como premultiplicados por razones de rendimiento.Almacenamiento de datos no multiplicados previamente en un mapa de bits (a través de setPixel, setPixels, o BitmapFactory.Options.inPremultiplied) puede provocar una combinación incorrecta si se dibuja por el marco.

Este método no afectará el comportamiento de un mapa de bits sin un canal alfa, o si hasAlpha() devuelve falso.

Vocación createBitmap o createScaledBitmap con un mapa de bits de origen cuyos colores no estén premultiplicados puede resultar en una RuntimeException, ya que esas funciones requieren dibujar la fuente, lo cual no es compatible con mapas de bits no multiplicados previamente.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top