Android Bitmap в строку Base64

Как преобразовать большое растровое изображение (фотография, сделанная камерой телефона) в строку Base64?


person Pankaj Singh    schedule 10.02.2012    source источник
comment
Как вы хотите закодировать изображение?   -  person Ted Hopp    schedule 10.02.2012
comment
Вы задаете неправильный вопрос. Фотографии, сделанные камерой телефона, сохраняются в формате JPEG, а не растровых изображений. Вам нужно только декодировать jpeg в растровое изображение для его отображения. У вас будет меньше ошибок OutOfMemory и ненужной обработки, если вы последуете моему ответу ниже.   -  person Carson Holzheimer    schedule 05.02.2019


Ответы (7)


используйте следующий метод для преобразования растрового изображения в массив байтов:

ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();  
bitmap.compress(Bitmap.CompressFormat.PNG, 100, byteArrayOutputStream);
byte[] byteArray = byteArrayOutputStream .toByteArray();

для кодирования base64 из массива байтов используйте следующий метод

String encoded = Base64.encodeToString(byteArray, Base64.DEFAULT);
person jeet    schedule 10.02.2012
comment
Спасибо за решение, я использовал тот же код, но моя закодированная строка имеет... в конце, и я думаю, что она не преобразована полностью, поэтому, пожалуйста, скажите мне, почему в конце строки Base 64 есть точки (...).. - person Pankaj Singh; 10.02.2012
comment
@Pankaj Привет, не могли бы вы рассказать мне, как решить эту проблему, я столкнулся с той же проблемой в моей закодированной строке с 3 точками (...), не могли бы вы помочь решить эту проблему? - person Sachin Gurnani; 12.10.2012
comment
@SachinGurnani - это показывает ... потому что логарифм показывает ограниченную длину строки, а после этого она усекается. вот почему. - person Pankaj Singh; 30.10.2012
comment
Спасибо за ваши ответы Панкадж. я решил эту проблему в тот же день - person Sachin Gurnani; 30.10.2012
comment
это должно быть сделано в asynctask? или это нормально делать в основном потоке? - person n3wb; 12.03.2014
comment
для этого блока кода нет какой-либо конкретной реализации, вы можете реализовать асинхронную задачу или поток событий в соответствии с вашими требованиями. - person jeet; 13.03.2014
comment
@SachinGurnani, можешь дать мне точный код? я также получаю 3 точки (...) - person Deepu T; 06.08.2014
comment
Большое спасибо. - person Riyaz Parasara; 10.09.2016
comment
Обратите внимание, что если вы укажете Bitmap.CompressFormat.PNG, второй параметр, качество, будет проигнорирован. - person RominaV; 08.12.2016
comment
Это решение имеет 2 проблемы. Вы не должны декодировать jpeg в первую очередь, и вы не должны хранить byteArray в памяти. На больших фотографиях будут выдаваться ошибки OOM - person Carson Holzheimer; 05.02.2019
comment
Вы можете использовать Base64.NO_WRAP, если не хотите \n в строке Base64. - person NecipAllef; 05.05.2019
comment
как узнать, правильно ли base64 в формате jpeg, например, используя его в html-теге ‹img› в src? - person Fernando Torres; 06.10.2019

У меня есть быстрое решение. Просто создайте файл ImageUtil.java

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.util.Base64;
import java.io.ByteArrayOutputStream;

public class ImageUtil
{
    public static Bitmap convert(String base64Str) throws IllegalArgumentException
    {
        byte[] decodedBytes = Base64.decode(
            base64Str.substring(base64Str.indexOf(",")  + 1),
            Base64.DEFAULT
        );

        return BitmapFactory.decodeByteArray(decodedBytes, 0, decodedBytes.length);
    }

    public static String convert(Bitmap bitmap)
    {
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        bitmap.compress(Bitmap.CompressFormat.PNG, 100, outputStream);

        return Base64.encodeToString(outputStream.toByteArray(), Base64.DEFAULT);
    }

}

Использование:

Bitmap bitmap = ImageUtil.convert(base64String);

or

String base64String = ImageUtil.convert(bitmap);
person Vasilii Suricov    schedule 07.12.2016
comment
что делает этот base64Str.substring(base64Str.indexOf(",") + 1)? Я не вижу, чтобы мои строки имели ,. - person A1m; 24.02.2021
comment
Эй, когда я вижу вывод в строке base64, это рендеринг с разрывными линиями, как мне это решить? Потому что мне нужно получить его в встроенном режиме - person Fernando Torres; 25.02.2021

Проблема с ответом jeet заключается в том, что вы загружаете все байты изображения в массив байтов, что, вероятно, приведет к сбою приложения на недорогих устройствах. Вместо этого я сначала запишу изображение в файл и прочитаю его, используя Apache Base64InputStream. Затем вы можете создать строку Base64 непосредственно из InputStream этого файла. Это будет выглядеть так:

//Don't forget the manifest permission to write files
final FileOutputStream fos = new FileOutputStream(yourFileHere); 
bitmap.compress(Bitmap.CompressFormat.PNG, 100, fos);

fos.close();

final InputStream is = new Base64InputStream( new FileInputStream(yourFileHere) );

//Now that we have the InputStream, we can read it and put it into the String
final StringWriter writer = new StringWriter();
IOUtils.copy(is , writer, encoding);
final String yourBase64String = writer.toString();

Как видите, приведенное выше решение вместо этого работает напрямую с потоками, избегая необходимости загружать все байты в переменную, что значительно снижает объем памяти и снижает вероятность сбоев на младших устройствах. По-прежнему существует проблема, заключающаяся в том, что помещение самой строки Base64 в переменную String — не очень хорошая идея, потому что, опять же, это может вызвать ошибки OutOfMemory. Но, по крайней мере, мы сократили потребление памяти вдвое, убрав массив байтов.

Если вы хотите пропустить шаг записи в файл, вам нужно преобразовать OutputStream в InputStream, что не так просто сделать (вы должны использовать PipedInputStream, но это немного сложнее, так как два потока всегда должны быть в разных потоках).

person Bitcoin Cash - ADA enthusiast    schedule 22.07.2014
comment
При чем здесь кодировка? - person Animesh Mangla; 18.12.2015

Попробуйте это, сначала масштабируйте изображение до необходимой ширины и высоты, просто передайте исходное растровое изображение, требуемую ширину и требуемую высоту следующему методу и получите взамен масштабированное растровое изображение:

Например: Bitmap scaledBitmap = getScaledBitmap(originalBitmap, 250, 350);

private Bitmap getScaledBitmap(Bitmap b, int reqWidth, int reqHeight)
{
    int bWidth = b.getWidth();
    int bHeight = b.getHeight();

    int nWidth = bWidth;
    int nHeight = bHeight;

    if(nWidth > reqWidth)
    {
        int ratio = bWidth / reqWidth;
        if(ratio > 0)
        {
            nWidth = reqWidth;
            nHeight = bHeight / ratio;
        }
    }

    if(nHeight > reqHeight)
    {
        int ratio = bHeight / reqHeight;
        if(ratio > 0)
        {
            nHeight = reqHeight;
            nWidth = bWidth / ratio;
        }
    }

    return Bitmap.createScaledBitmap(b, nWidth, nHeight, true);
}

Теперь просто передайте масштабированное растровое изображение следующему методу и получите взамен строку base64:

Например: String base64String = getBase64String(scaledBitmap);

private String getBase64String(Bitmap bitmap)
{
    ByteArrayOutputStream baos = new ByteArrayOutputStream();

    bitmap.compress(Bitmap.CompressFormat.JPEG, 100, baos);

    byte[] imageBytes = baos.toByteArray();

    String base64String = Base64.encodeToString(imageBytes, Base64.NO_WRAP);

    return base64String;
}

Чтобы декодировать строку base64 обратно в растровое изображение:

byte[] decodedByteArray = Base64.decode(base64String, Base64.NO_WRAP);
Bitmap decodedBitmap = BitmapFactory.decodeByteArray(decodedByteArray, 0, decodedString.length);
person Ashwin    schedule 08.06.2017

Все эти ответы неэффективны, поскольку они без необходимости декодируют растровое изображение, а затем повторно сжимают растровое изображение. Когда вы делаете фотографию на Android, она сохраняется в формате jpeg во временном файле, который вы указываете при подписке на документы для Android.

Что вам нужно сделать, так это напрямую преобразовать этот файл в строку Base64. Вот как это сделать простым копированием и вставкой (в Котлине). Обратите внимание, что вы должны закрыть base64FilterStream, чтобы действительно очистить его внутренний буфер.

fun convertImageFileToBase64(imageFile: File): String {

    return FileInputStream(imageFile).use { inputStream ->
        ByteArrayOutputStream().use { outputStream ->
            Base64OutputStream(outputStream, Base64.DEFAULT).use { base64FilterStream ->
                inputStream.copyTo(base64FilterStream)
                base64FilterStream.close()
                outputStream.toString()
            }
        }
    }
}

В качестве бонуса качество вашего изображения должно немного улучшиться за счет обхода повторного сжатия.

person Carson Holzheimer    schedule 05.02.2019

Теперь, когда большинство людей используют Kotlin вместо Java, вот код на Kotlin для преобразования растрового изображения в строку base64.

import java.io.ByteArrayOutputStream

private fun encodeImage(bm: Bitmap): String? {
        val baos = ByteArrayOutputStream()
        bm.compress(Bitmap.CompressFormat.JPEG, 100, baos)
        val b = baos.toByteArray()
        return Base64.encodeToString(b, Base64.DEFAULT)
    }
person Reddy Tintaya    schedule 20.02.2020

Используйте этот код..

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.util.Base64;
import java.io.ByteArrayOutputStream;

public class ImageUtil 
{ 
    public static Bitmap convert(String base64Str) throws IllegalArgumentException 
    { 
        byte[] decodedBytes = Base64.decode( base64Str.substring(base64Str.indexOf(",") + 1), Base64.DEFAULT );
        return BitmapFactory.decodeByteArray(decodedBytes, 0, decodedBytes.length);
    } 

    public static String convert(Bitmap bitmap) 
    { 
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        bitmap.compress(Bitmap.CompressFormat.PNG, 100, outputStream);
        return Base64.encodeToString(outputStream.toByteArray(), Base64.DEFAULT);
    }
}
person Acme Developers    schedule 04.11.2019