conversion de bitmap Java en tableau d'octets

292
  Bitmap bmp   = intent.getExtras().get("data");
  int size     = bmp.getRowBytes() * bmp.getHeight();
  ByteBuffer b = ByteBuffer.allocate(size);

  bmp.copyPixelsToBuffer(b);

  byte[] bytes = new byte[size];

  try {
     b.get(bytes, 0, bytes.length);
  } catch (BufferUnderflowException e) {
     // always happens
  }
  // do something with byte[]

Quand je regarde le tampon après que l'appel aux copyPixelsToBufferoctets soit tous à 0 ... Le bitmap renvoyé par la caméra est immuable ... mais cela n'a pas d'importance car il fait une copie.

Quel pourrait être le problème avec ce code?

Tom Fobear
la source

Réponses:

652

Essayez quelque chose comme ceci:

Bitmap bmp = intent.getExtras().get("data");
ByteArrayOutputStream stream = new ByteArrayOutputStream();
bmp.compress(Bitmap.CompressFormat.PNG, 100, stream);
byte[] byteArray = stream.toByteArray();
bmp.recycle();
Mezm
la source
9
Cela ne causera-t-il pas des problèmes si l'image n'est pas de type PNG?
pgsandstrom
7
pas parce que le Bitmap est une image décodée quelle qu'elle soit, comme un tableau de pixels. Il se compressera au format PNG, ce qui ne perdra pas en qualité lors de la compression
5
meilleure est l'option de rembobinage de @Ted Hopp - la compression est un gaspillage de CPU à moins que votre objectif ne soit une image encodée ....
Kaolin Fire
38
D'après mon expérience, sur un système à faible mémoire comme Android, il faut faire attention à ajouter bitmap.recycle (); juste après la compression et fermez le flux pour éviter l'exception de fuite de mémoire.
Son Huy TRAN
10
Cette approche est vraiment inutile d'allocations. Vous ByteArrayOutputStreamallouerez une byte[]taille égale à celle de byte[]votre support Bitmap, puis vous ByteArrayOutputStream.toByteArray()en allouerez encore une autre byte[]de la même taille.
zyamys
70

CompressFormat est trop lent ...

Essayez ByteBuffer.

※※※ Bitmap en octets ※※※

width = bitmap.getWidth();
height = bitmap.getHeight();

int size = bitmap.getRowBytes() * bitmap.getHeight();
ByteBuffer byteBuffer = ByteBuffer.allocate(size);
bitmap.copyPixelsToBuffer(byteBuffer);
byteArray = byteBuffer.array();

※※※ octet en bitmap ※※※

Bitmap.Config configBmp = Bitmap.Config.valueOf(bitmap.getConfig().name());
Bitmap bitmap_tmp = Bitmap.createBitmap(width, height, configBmp);
ByteBuffer buffer = ByteBuffer.wrap(byteArray);
bitmap_tmp.copyPixelsFromBuffer(buffer);
朱 西西
la source
5
Étant donné que cette question a la balise Android, la conversion d'octets en bitmap peut également être effectuée avec une ligne: Bitmap bmp = BitmapFactory.decodeByteArray(bytes, 0, bytes.length)bytesest votre tableau d'octets
automate
Peut-être que le grand / petit endian devrait être envisagé?
NeoWang
Si vous souhaitez enregistrer le tableau d'octets dans la base de données locale (Sqlite, Room), vous devez compresser comme réponse supérieure!
J.Dragon
Notez, cependant, que sans la compression, la différence de taille est dramatique. Pour la théorie, vous pouvez lire wikipedia, mais par exemple dans mon cas, le résultat compressé (selon la 1ère réponse) est de 20 Mo, l'autre (cette réponse) est de 48 Mo
Kirill Starostin
19

Voici l'extension bitmap .convertToByteArrayécrite dans Kotlin.

/**
 * Convert bitmap to byte array using ByteBuffer.
 */
fun Bitmap.convertToByteArray(): ByteArray {
    //minimum number of bytes that can be used to store this bitmap's pixels
    val size = this.byteCount

    //allocate new instances which will hold bitmap
    val buffer = ByteBuffer.allocate(size)
    val bytes = ByteArray(size)

    //copy the bitmap's pixels into the specified buffer
    this.copyPixelsToBuffer(buffer)

    //rewinds buffer (buffer position is set to zero and the mark is discarded)
    buffer.rewind()

    //transfer bytes from buffer into the given destination array
    buffer.get(bytes)

    //return bitmap's pixels
    return bytes
}
Tomas Ivan
la source
18

Avez-vous besoin de rembobiner le tampon, peut-être?

Cela peut également se produire si la foulée (en octets) du bitmap est supérieure à la longueur de ligne en pixels * octets / pixel. Faites la longueur des octets b.remaining () au lieu de la taille.

Ted Hopp
la source
6
rewind()C'est la clé. J'obtenais la même chose BufferUnderflowExceptionet rembobiner le tampon après l'avoir rempli a résolu ce problème.
tstuts
9

Utilisez les fonctions ci-dessous pour coder le bitmap en octet [] et vice versa

public static String encodeTobase64(Bitmap image) {
    Bitmap immagex = image;
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    immagex.compress(Bitmap.CompressFormat.PNG, 90, baos);
    byte[] b = baos.toByteArray();
    String imageEncoded = Base64.encodeToString(b, Base64.DEFAULT);
    return imageEncoded;
}

public static Bitmap decodeBase64(String input) {
    byte[] decodedByte = Base64.decode(input, 0);
    return BitmapFactory.decodeByteArray(decodedByte, 0, decodedByte.length);
}
Amol Suryawanshi
la source
6

Votre tableau d'octets est trop petit. Chaque pixel occupe 4 octets, pas seulement 1, donc multipliez votre taille * 4 pour que le tableau soit suffisamment grand.

MindJuice
la source
4
Son tableau d'octets est suffisamment grand. getRowBytes()prend en compte les 4 octets par pixel.
tstuts
3

Ted Hopp est correct, à partir de la documentation de l'API:

public void copyPixelsToBuffer (Buffer dst)

"... Après le retour de cette méthode, la position actuelle du tampon est mise à jour: la position est incrémentée du nombre d'éléments écrits dans le tampon."

et

public ByteBuffer get (byte[] dst, int dstOffset, int byteCount)

"Lit les octets de la position actuelle dans le tableau d'octets spécifié, en commençant à l'offset spécifié, et augmente la position du nombre d'octets lus."

CaptainCrunch
la source
2

Afin d'éviter les OutOfMemoryerreurs pour les fichiers plus gros, je résoudrais la tâche en divisant un bitmap en plusieurs parties et en fusionnant les octets de leurs parties.

private byte[] getBitmapBytes(Bitmap bitmap)
{
    int chunkNumbers = 10;
    int bitmapSize = bitmap.getRowBytes() * bitmap.getHeight();
    byte[] imageBytes = new byte[bitmapSize];
    int rows, cols;
    int chunkHeight, chunkWidth;
    rows = cols = (int) Math.sqrt(chunkNumbers);
    chunkHeight = bitmap.getHeight() / rows;
    chunkWidth = bitmap.getWidth() / cols;

    int yCoord = 0;
    int bitmapsSizes = 0;

    for (int x = 0; x < rows; x++)
    {
        int xCoord = 0;
        for (int y = 0; y < cols; y++)
        {
            Bitmap bitmapChunk = Bitmap.createBitmap(bitmap, xCoord, yCoord, chunkWidth, chunkHeight);
            byte[] bitmapArray = getBytesFromBitmapChunk(bitmapChunk);
            System.arraycopy(bitmapArray, 0, imageBytes, bitmapsSizes, bitmapArray.length);
            bitmapsSizes = bitmapsSizes + bitmapArray.length;
            xCoord += chunkWidth;

            bitmapChunk.recycle();
            bitmapChunk = null;
        }
        yCoord += chunkHeight;
    }

    return imageBytes;
}


private byte[] getBytesFromBitmapChunk(Bitmap bitmap)
{
    int bitmapSize = bitmap.getRowBytes() * bitmap.getHeight();
    ByteBuffer byteBuffer = ByteBuffer.allocate(bitmapSize);
    bitmap.copyPixelsToBuffer(byteBuffer);
    byteBuffer.rewind();
    return byteBuffer.array();
}
Ayaz Alifov
la source
0

Essayez ceci pour convertir String-Bitmap ou Bitmap-String

/**
 * @param bitmap
 * @return converting bitmap and return a string
 */
public static String BitMapToString(Bitmap bitmap){
    ByteArrayOutputStream baos=new ByteArrayOutputStream();
    bitmap.compress(Bitmap.CompressFormat.PNG,100, baos);
    byte [] b=baos.toByteArray();
    String temp=Base64.encodeToString(b, Base64.DEFAULT);
    return temp;
}

/**
 * @param encodedString
 * @return bitmap (from given string)
 */
public static Bitmap StringToBitMap(String encodedString){
    try{
        byte [] encodeByte=Base64.decode(encodedString,Base64.DEFAULT);
        Bitmap bitmap= BitmapFactory.decodeByteArray(encodeByte, 0, encodeByte.length);
        return bitmap;
    }catch(Exception e){
        e.getMessage();
        return null;
    }
}
Mohammad nabil
la source