преобразование растрового изображения Java в массив байтов
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[]
когда я смотрю на буфер после вызова copyPixelsToBuffer
все байты равны 0... Растровое изображение, возвращенное с камеры, является неизменным... но это не должно иметь значения, так как он делает копию.
что может быть не так с этим кодом?
9 ответов:
попробуйте что-то вроде этого:
Bitmap bmp = intent.getExtras().get("data"); ByteArrayOutputStream stream = new ByteArrayOutputStream(); bmp.compress(Bitmap.CompressFormat.PNG, 100, stream); byte[] byteArray = stream.toByteArray(); bmp.recycle();
использовать CompressFormat слишком медленно...
попробуйте использовать ByteBuffer.
※※※растровое изображение в Byte※※※
width = bitmap.getWidth(); height = bitmap.getHeight(); int size = bitmap.getRowBytes() * bitmap.getHeight(); ByteBuffer byteBuffer = ByteBuffer.allocate(size); bitmap.copyPixelsToBuffer(byteBuffer); byteArray = byteBuffer.array();
※※※байт в растровое изображение※※※
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);
вам нужно перемотать буфер, возможно?
кроме того, это может произойти, если шаг (в байтах) растрового изображения больше, чем длина строки в пикселях * байт/пиксель. Сделайте длину байтов b. remaining () вместо размера.
Ваш массив байтов слишком мал. Каждый пиксель занимает 4 байта, а не только 1, поэтому умножьте свой размер * 4, чтобы массив был достаточно большим.
используйте следующие функции для кодирования растрового изображения в байт[] и наоборот
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); }
вот растровое расширение
.convertToByteArray
написал в Котлине./** * 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 }
для того, чтобы избежать
OutOfMemory
ошибка для больших файлов я бы решил задачу, разделив растровое изображение на несколько частей и объединив байты их частей.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(); }
Тед Хопп прав, из документации API:
public void copyPixelsToBuffer (Buffer dst)
"... После того, как этот метод возвращает,текущая позиция буфера обновляется: позиция увеличивается на количество элементов, записанных в буфер. "
и
public ByteBuffer get (byte[] dst, int dstOffset, int byteCount)
" считывает байты из текущая позиция в указанный байтовый массив, начиная с указанного смещения и увеличивает позицию на количество прочитанных байт."
попробуйте это, чтобы преобразовать String-Bitmap или 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; } }