Frage

Ich versuche, auf die Rohdaten einer Bitmap im ARGB_8888-Format unter Android zuzugreifen, indem ich Folgendes verwende copyPixelsToBuffer und copyPixelsFromBuffer Methoden.Der Aufruf dieser Aufrufe scheint jedoch immer den Alphakanal auf die RGB-Kanäle anzuwenden.Ich brauche die Rohdaten in einem Byte [] oder ähnlichem (um JNI zu durchlaufen;ja, ich kenne Bitmap.h in Android 2.2, kann das nicht verwenden).

Hier ist ein Beispiel:

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

Das Protokoll zeigt dann

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

Ich verstehe, dass die Reihenfolge der Argb-Kanäle unterschiedlich ist;das ist in Ordnung.Aber ich nicht möchte, dass der Alphakanal auf jede Kopie angewendet wird (was anscheinend der Fall ist).

Ist das so copyPixelsToBuffer und copyPixelsFromBuffer sollen arbeiten?Gibt es jeder weg, um die Rohdaten in einem Byte zu bekommen []?

Als Antwort auf die Antwort unten hinzugefügt:

Einsetzen buffer.order(ByteOrder.nativeOrder()); vor dem copyPixelsToBuffer ändert das Ergebnis, aber immer noch nicht so, wie ich es möchte:

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

Scheint im Wesentlichen unter dem gleichen Problem zu leiden (Alpha wird auf jeden angewendet copyPixelsFrom/ToBuffer).

War es hilfreich?

Lösung

Mir ist klar, dass das sehr abgestanden ist und dir jetzt wahrscheinlich nicht helfen wird, aber ich bin kürzlich darauf gestoßen, als ich versucht habe, es zu bekommen copyPixelsFromBuffer in meiner App arbeiten.(Danke, dass Sie diese Frage gestellt haben, übrigens!Sie haben mir beim Debuggen jede Menge Zeit gespart.) Ich füge diese Antwort hinzu in der Hoffnung, dass sie anderen wie mir hilft, voranzukommen...

Obwohl ich dies noch nicht verwendet habe, um sicherzustellen, dass es funktioniert, sieht es so aus, dass wir ab API-Level 19 endlich eine Möglichkeit haben, anzugeben, dass das Alpha nicht "angewendet" werden soll (a.k.a.vormultiplizieren) innerhalb Bitmap.Sie fügen eine hinzu setPremultiplied(boolean) methode, die in solchen Situationen in Zukunft helfen soll, indem sie uns erlaubt, Folgendes anzugeben false.

Ich hoffe, das hilft!

Andere Tipps

Eine Möglichkeit, auf Daten in Bitmaps zuzugreifen, ist die Verwendung der Methode getPixels() .Unten finden Sie ein Beispiel, mit dem ich Graustufenbilder aus Argb-Daten und dann zurück vom Byte-Array zur Bitmap abgerufen habe (wenn Sie RGB benötigen, reservieren Sie natürlich 3x Bytes und speichern sie alle...):

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

}

Ich vermute, dass dies mit der Bytereihenfolge des von Ihnen verwendeten ByteBuffers zu tun haben könnte.ByteBuffer verwendet standardmäßig Big Endian.Setze Endianess auf den Puffer mit

buffer.order(ByteOrder.nativeOrder());

Sehen Sie, ob es hilft.

Darüber hinaus ändert copyPixelsFromBuffer / copyPixelsToBuffer die Pixeldaten in keiner Weise.Sie werden roh kopiert.

Dies ist eine alte Frage, aber ich bin auf das gleiche Problem gestoßen und habe gerade herausgefunden, dass das Bitmap-Byte vormultipliziert ist. Sie können die Bitmap (ab API 19) so einstellen, dass der Puffer nicht vormultipliziert wird, aber in der API sie machen keine Garantie.

Von Dok:

public final void setPremultiplied(boolean premultiplied)

Legt fest, ob die Bitmap ihre Daten als vormultipliziert behandeln soll.Bitmaps werden aus Leistungsgründen immer als vom Ansichtssystem und der Zeichenfläche vormultipliziert behandelt.Speichern von nicht vormultiplizierten Daten in einer Bitmap (durch setPixel, setPixels, oder BitmapFactory.Options.inPremultiplied) kann zu einer falschen Mischung führen, wenn sie vom Framework gezeichnet wird.

Diese Methode hat keinen Einfluss auf das Verhalten einer Bitmap ohne Alphakanal oder wenn hasAlpha() false.

Aufruf createBitmap oder createScaledBitmap bei einer Quellbitmap, deren Farben nicht vormultipliziert sind, kann dies zu einer RuntimeException, da diese Funktionen das Zeichnen der Quelle erfordern, was für nicht vormultiplizierte Bitmaps nicht unterstützt wird.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top