Question

J'essaie d'accéder aux données brutes d'un bitmap au format argb_8888 sur Android, en utilisant le copyPixelsToBuffer et copyPixelsFromBuffer Méthodes. Cependant, l'invocation de ces appels semble toujours appliquer le canal alpha aux canaux RVB. J'ai besoin des données brutes dans un octet [] ou similaire (pour passer par JNI; oui, je sais que Bitmap.h dans Android 2.2, ne peut pas l'utiliser).

Voici un échantillon:

    // 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)));

Le journal affiche alors

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

Je comprends que l'ordre des canaux Argb est différent; C'est très bien. Mais je ne veux pas que le canal Alpha soit appliqué à chaque copie (ce qu'il semble faire).

Est-ce comme ça copyPixelsToBuffer et copyPixelsFromBuffer sont censés fonctionner? Y a-t-il n'importe quel moyen d'obtenir les données brutes dans un octet []?

Ajouté en réponse à la réponse ci-dessous:

Mettre dans buffer.order(ByteOrder.nativeOrder()); avant le copyPixelsToBuffer Change le résultat, mais toujours pas dans la façon dont je le veux:

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

Semble souffrir essentiellement du même problème (Alpha est appliqué à chaque copyPixelsFrom/ToBuffer).

Était-ce utile?

La solution

Je me rends compte que c'est très vicié et ne vous aidera probablement pas maintenant, mais je l'ai rencontré récemment en essayant d'obtenir copyPixelsFromBuffer pour travailler dans mon application. (Merci d'avoir posé cette question, btw! Vous m'avez sauvé des tonnes de temps dans le débogage.) J'ajoute cette réponse dans l'espoir que cela aide d'autres comme moi à l'avenir ...

Bien que je n'ai pas encore utilisé cela pour m'assurer que cela fonctionne, il semble que, au niveau de l'API 19, nous aurons enfin un moyen de spécifier de ne pas "appliquer l'alpha" (aka prémultiply) Bitmap. Ils ajoutent un setPremultiplied(boolean) Méthode qui devrait aider dans des situations comme celle-ci à l'avenir en nous permettant de spécifier false.

J'espère que ça aide!

Autres conseils

Une façon d'accéder aux données dans Bitmap consiste à utiliser la méthode getPixels (). Ci-dessous, vous pouvez trouver un exemple que j'ai utilisé pour obtenir l'image en niveaux de gris à partir des données ArgB, puis de retour du tableau d'octets à Bitmap (bien sûr, si vous avez besoin de RGB, vous réservez 3x octets et les enregistrez tous ...):

/*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;
   }

}

Je suppose que cela pourrait avoir à voir avec l'ordre des octets du bytebuffer que vous utilisez. ByteBuffer utilise Big Endian par défaut. Réglez les endettes sur le tampon avec

buffer.order(ByteOrder.nativeOrder());

Voyez si cela aide.

De plus, CopyPixelsFrombUffer / CopyPixelStobuffer ne change en aucun cas les données de pixels. Ils sont copiés crus.

C'est une vieille question, mais je suis arrivé au même problème, et j'ai juste compris que l'octet bitmap est pré-multiplié, vous pouvez définir le bitmap (à partir de l'API 19) pour ne pas pré-multiplier le tampon, mais dans l'API Ils ne garantissent pas.

De les documents:

public final void setPremultiplied(boolean premultiplied)

Définit si le bitmap doit traiter ses données comme pré-multipliées. Les bitmaps sont toujours traités comme pré-multipliés par le système de vue et la toile pour des raisons de performance. Stockage des données non pré-reproduies dans un bitmap (à travers setPixel, setPixels, ou BitmapFactory.Options.inPremultiplied) peut entraîner un mélange incorrect s'il est dessiné par le cadre.

Cette méthode n'affectera pas le comportement d'un bitmap sans canal alpha, ou si hasAlpha() Renvoie false.

Appel createBitmap ou createScaledBitmap avec un bitmap source dont les couleurs ne sont pas pré-multipliées peuvent entraîner un RuntimeException, comme ces fonctions nécessitent de dessiner la source, qui n'est pas prise en charge pour les bitmaps non pré-multipliés.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top