Android Bitmap เป็นสตริง Base64


128

ฉันจะแปลง Bitmap ขนาดใหญ่ (ภาพที่ถ่ายด้วยกล้องของโทรศัพท์) เป็นสตริง Base64 ได้อย่างไร


คุณต้องการเข้ารหัสภาพอย่างไร?
Ted Hopp

คุณกำลังถามคำถามผิด รูปภาพที่ถ่ายด้วยกล้องโทรศัพท์จะจัดเก็บเป็น jpeg ไม่ใช่บิตแมป คุณจะต้องถอดรหัส jpeg เป็นบิตแมปเพื่อแสดงเท่านั้น คุณจะมีข้อผิดพลาด OutOfMemory น้อยลงและการประมวลผลที่ไม่จำเป็นหากคุณทำตามคำตอบของฉันด้านล่าง
Carson Holzheimer

คำตอบ:


302

ใช้วิธีการต่อไปนี้เพื่อแปลงบิตแมปเป็นไบต์อาร์เรย์:

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

ในการเข้ารหัส base64 จากไบต์อาร์เรย์ใช้วิธีการต่อไปนี้

String encoded = Base64.encodeToString(byteArray, Base64.DEFAULT);

ขอบคุณสำหรับวิธีแก้ปัญหาฉันใช้รหัสเดียวกัน แต่สตริงที่เข้ารหัสของฉันมี ... ในที่สุดและฉันคิดว่ามันไม่ได้ถูกแปลงอย่างสมบูรณ์ดังนั้นโปรดบอกฉันว่าทำไมในตอนท้ายของสตริงฐาน 64 จึงเป็นจุด (... ) ..
Pankaj Singh

@Pankaj สวัสดีคุณช่วยบอกฉันได้ไหมว่าคุณแก้ปัญหานั้นได้อย่างไรฉันประสบปัญหาเดียวกันในสตริงที่เข้ารหัสของฉันมี 3 จุด (... ) โปรดช่วยแก้ปัญหานั้นได้
ไหม

5
@SachinGurnani - มันแสดง ... เพราะ logcat แสดงความยาวของสตริงที่ จำกัด และหลังจากนั้นมันก็ถูกตัดทอน นั่นคือเหตุผล
Pankaj Singh

ขอบคุณสำหรับการตอบสนองของคุณ Pankaj ฉันได้แก้ปัญหานี้ในวันเดียวกัน
Sachin Gurnani

1
ควรทำใน asynctask หรือไม่ หรือทำในเธรดหลักได้ดี?
n3wb

28

ฉันมีวิธีแก้ปัญหาอย่างรวดเร็ว เพียงแค่สร้างไฟล์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);

หรือ

String base64String = ImageUtil.convert(bitmap);

13

ปัญหาเกี่ยวกับคำตอบของ jeet คือคุณโหลดไบต์ทั้งหมดของรูปภาพลงในอาร์เรย์ไบต์ซึ่งอาจทำให้แอปในอุปกรณ์ระดับล่างพังได้ ก่อนอื่นฉันจะเขียนภาพลงในไฟล์และอ่านโดยใช้คลาสBase64InputStreamของ Apache จากนั้นคุณสามารถสร้างสตริง 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แต่จะซับซ้อนกว่าเล็กน้อยเนื่องจากสตรีมทั้งสองต้องเสมอกัน อยู่คนละเธรด)


2
การเข้ารหัสที่นี่คืออะไร?
Animesh Mangla

5

ลองทำสิ่งนี้ก่อนปรับขนาดภาพของคุณให้มีความกว้างและความสูงที่ต้องการเพียงแค่ส่งบิตแมปเดิมของคุณความกว้างที่ต้องการและความสูงที่ต้องการไปยังวิธีการต่อไปนี้และรับบิตแมปที่ปรับขนาดในทางกลับกัน:

ตัวอย่างเช่น: 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);

3

คำตอบทั้งหมดนี้ไม่มีประสิทธิภาพเนื่องจากถอดรหัสเป็นบิตแมปโดยไม่จำเป็นจากนั้นจึงบีบอัดบิตแมปใหม่ เมื่อคุณถ่ายภาพบน Android ก็จะถูกเก็บไว้เป็น JPEG ในไฟล์ temp ที่คุณระบุเมื่อคุณทำตามเอกสารหุ่นยนต์

สิ่งที่คุณควรทำคือแปลงไฟล์นั้นเป็นสตริง Base64 โดยตรง นี่คือวิธีการทำในการคัดลอกวางอย่างง่าย (ใน Kotlin) โปรดทราบว่าคุณต้องปิด 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()
            }
        }
    }
}

เป็นโบนัสคุณภาพของภาพควรได้รับการปรับปรุงเล็กน้อยเนื่องจากการข้ามการบีบอัดซ้ำ


1

ตอนนี้คนส่วนใหญ่ใช้ 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)
    }

-2

ใช้รหัสนี้ ..

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);
    }
}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.