Android Bitmap to Base64 String
Asked Answered
C

7

168

How do I convert a large Bitmap (photo taken with the phone's camera) to a Base64 String?

Contemporize answered 10/2, 2012 at 7:8 Comment(2)
How do you want to encode the image?Derosa
You're asking the wrong question. Photos taken with the phone's camera are stored as jpeg, not bitmaps. You only need to decode the jpeg to a bitmap for the purpose of displaying it. You'll have less OutOfMemory errors and needless processing if you follow my answer below.Balkan
D
370

use following method to convert bitmap to byte array:

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

to encode base64 from byte array use following method

String encoded = Base64.encodeToString(byteArray, Base64.DEFAULT);
Deprave answered 10/2, 2012 at 7:20 Comment(11)
Thanks for solution, i have used same code but my encoded string has ... in end and i think it is not converted completely so please tell me why in end of Base 64 string are the dots(...)..Contemporize
@Pankaj Hi can u tell me how u solve that issue , im facing same problem in my encoded string has 3 dot(...) can u please help to solve thatShute
@SachinGurnani - it showes ... because the logcat showes limited String lenth and after that its truncated. thats why.Contemporize
Thanks for ur respons Pankaj . i had sove this issue on same day itselfShute
should this be done in asynctask? or is it fine to do this in the main thread?Triumphant
there is not any specific implementation for this code block, you can implement in async task or event thread as suitable to your requirements.Deprave
@SachinGurnani can u give me the exact code.? i am also getting the 3 dots(...)Zoilazoilla
Note that if you specify Bitmap.CompressFormat.PNG, the second parameter, "quality", will be ignored.Smew
This solution has 2 problems. You shouldn't be decoding the jpeg in the first place, and you shouldn't be storing the byteArray in memory. On large photos that's going to throw OOM errorsBalkan
You may wanna use Base64.NO_WRAP if you don't want \n in your Base64 string.Propensity
how do i know if base64 is correct in jpeg format like using it in <img> html tag in src?Eyeleteer
P
36

I have fast solution. Just create a file 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);
    }

}

Usage:

Bitmap bitmap = ImageUtil.convert(base64String);

or

String base64String = ImageUtil.convert(bitmap);
Powys answered 7/12, 2016 at 22:25 Comment(2)
what is this base64Str.substring(base64Str.indexOf(",") + 1) doing? I don't see my strings having a ",".Hickie
Hey, when i see the output in base64 string, this is rendering with break lines, how do i need to solve it? Because i need to get it on inline modeEyeleteer
C
14

The problem with jeet's answer is that you load all bytes of the image into a byte array, which will likely crash the app in low-end devices. Instead, I would first write the image to a file and read it using Apache's Base64InputStream class. Then you can create the Base64 string directly from the InputStream of that file. It will look like this:

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

As you can see, the above solution works directly with streams instead, avoiding the need to load all the bytes into a variable, therefore making the memory footprint much lower and less likely to crash in low-end devices. There is still the problem that putting the Base64 string itself into a String variable is not a good idea, because, again, it might cause OutOfMemory errors. But at least we have cut the memory consumption by half by eliminating the byte array.

If you want to skip the write-to-a-file step, you have to convert the OutputStream to an InputStream, which is not so straightforward to do (you must use PipedInputStream but that is a little more complex as the two streams must always be in different threads).

Cohby answered 22/7, 2014 at 1:57 Comment(1)
What is encoding here?Ardor
A
9

Try this, first scale your image to required width and height, just pass your original bitmap, required width and required height to the following method and get scaled bitmap in return:

For example: 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);
}

Now just pass your scaled bitmap to the following method and get base64 string in return:

For example: 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;
}

To decode the base64 string back to bitmap image:

byte[] decodedByteArray = Base64.decode(base64String, Base64.NO_WRAP);
Bitmap decodedBitmap = BitmapFactory.decodeByteArray(decodedByteArray, 0, decodedString.length);
Ambrosane answered 8/6, 2017 at 10:44 Comment(1)
I found answer for my problem: i got error "Illegal character a" at my base64 encoded bitmap, using Base64.NO_WRAP fixed this problemGeophilous
D
9

Now that most people use Kotlin instead of Java, here is the code in Kotlin for converting a bitmap into a base64 string.

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)
    }
Dipole answered 20/2, 2020 at 12:1 Comment(0)
B
5

All of these answers are inefficient as they needlessly decode to a bitmap and then recompress the bitmap. When you take a photo on Android, it is stored as a jpeg in the temp file you specify when you follow the android docs.

What you should do is directly convert that file to a Base64 string. Here is how to do that in easy copy-paste (in Kotlin). Note you must close the base64FilterStream to truly flush its internal buffer.

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()
            }
        }
    }
}

As a bonus, your image quality should be slightly improved, due to bypassing the re-compressing.

Balkan answered 5/2, 2019 at 12:7 Comment(0)
A
-3

Use this code..

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);
    }
}
Ardel answered 4/11, 2019 at 11:3 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.