将位图转换为文件

151
我理解使用BitmapFactory可以将文件转换为位图,但是否有办法将位图图像转换为文件呢?
6个回答

273

希望这可以帮到你:

//create a file to write bitmap data
File f = new File(context.getCacheDir(), filename);
f.createNewFile();

//Convert bitmap to byte array
Bitmap bitmap = your bitmap;
ByteArrayOutputStream bos = new ByteArrayOutputStream();
bitmap.compress(CompressFormat.PNG, 0 /*ignored for PNG*/, bos);
byte[] bitmapdata = bos.toByteArray();

//write the bytes in file
FileOutputStream fos = new FileOutputStream(f);
fos.write(bitmapdata);
fos.flush();
fos.close();

40
别忘了清除并关闭输出流 :) - Ben Holland
4
代码可以正常运行,但压缩方法需要很长时间。有什么解决办法吗? - Shail Adi
10
如果有人想知道Quality metric是什么,它是一个0到100的量表,类似于Photoshop导出等级。如前所述,对于PNG格式,这个量度会被忽略,但您可能希望使用“CompressFormat.JPEG”。根据Google文档:提示给压缩器,从0到100。0表示为小文件大小压缩,100表示为最高质量压缩。像PNG这样的一些格式将忽略质量设置 - wired00
3
缓存目录中的文件是否会自动删除? - Shajeel Afzal
1
为什么要使用 ByteArrayOutputStream,从中获取一个字节数组,然后将该数组写入到 FileOutputStream 中?为什么不直接在 Bitmap.compress 中使用 FileOutputStream 呢? - InsanityOnABun
显示剩余2条评论

94

试一下这个:

bitmap.compress(Bitmap.CompressFormat.PNG, quality, outStream);

点击这里


14
我不想要一个“FileOutputStream”,只想要一个文件。有什么办法可以绕过这个限制吗? - Mxyk
1
FileOutputStream 是用于向文件写入数据的类。请参阅 http://developer.android.com/reference/java/io/FileOutputStream.html。 - Torid
我其实不太明白你的意思...你可以使用 FileOutputStream 来创建一个文件。并且你可以使用文件实例(例如 amsiddh 的示例)来创建一个 FileOutputStream,以将位图导出到其中。有了这个(一个文件实例、一个实际的文件系统上的文件和 FileOutputStream),你应该拥有所需的一切,对吧? - P.Melch
质量是一个从0到100的整数,包括0和100,用于指定质量(提示压缩器,因此它不一定遵循规则)。https://developer.android.com/reference/android/graphics/Bitmap#compress(android.graphics.Bitmap.CompressFormat,%20int,%20java.io.OutputStream) - Ben Butterworth

49
File file = new File("path");
OutputStream os = new BufferedOutputStream(new FileOutputStream(file));
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, os);
os.close();

1
java.io.FileNotFoundException: /path: open failed: EROFS (Read-only file system) - Prasad
1
@Prasad 确保将正确的路径传递给您的 File() 构造函数。 - fraggjkee
它有默认路径吗? - Nathiel Barros
完美解决方案 - Alessandro Scarozza
什么是bitmap.compress?为什么这个函数会给出JPEG格式?100是什么意思? - roghayeh hosseini

14

Bitmap 转换为 File 需要在后台进行 (不要在主线程中进行),否则会导致界面卡顿,特别是当 bitmap 很大时。

File file;

public class fileFromBitmap extends AsyncTask<Void, Integer, String> {

    Context context;
    Bitmap bitmap;
    String path_external = Environment.getExternalStorageDirectory() + File.separator + "temporary_file.jpg";

    public fileFromBitmap(Bitmap bitmap, Context context) {
        this.bitmap = bitmap;
        this.context= context;
    }

    @Override
    protected void onPreExecute() {
        super.onPreExecute();
        // before executing doInBackground
        // update your UI
        // exp; make progressbar visible
    }

    @Override
    protected String doInBackground(Void... params) {

        ByteArrayOutputStream bytes = new ByteArrayOutputStream();
        bitmap.compress(Bitmap.CompressFormat.JPEG, 100, bytes);
        file = new File(Environment.getExternalStorageDirectory() + File.separator + "temporary_file.jpg");
        try {
            FileOutputStream fo = new FileOutputStream(file);
            fo.write(bytes.toByteArray());
            fo.flush();
            fo.close();
        } catch (IOException e) {
            e.printStackTrace();
        }

        return null;
    }


    @Override
    protected void onPostExecute(String s) {
        super.onPostExecute(s);
        // back to main thread after finishing doInBackground
        // update your UI or take action after
        // exp; make progressbar gone

         sendFile(file);

    }
}

称之为

new fileFromBitmap(my_bitmap, getApplicationContext()).execute();

你必须在onPostExecute中使用file

要更改存储在缓存中的file的目录,请替换以下行:

 file = new File(Environment.getExternalStorageDirectory() + File.separator + "temporary_file.jpg");

使用:

file  = new File(context.getCacheDir(), "temporary_file.jpg");

1
有时候会抛出“FileNotFound”异常,我仍在调查原因。另外,也许你应该考虑使用.webp扩展名保存文件,它的大小比JPG小大约40-50%。 - Pranaysharma
我猜“FileNotFound”异常发生在保存到缓存时,然后某种方式清除了缓存(有许多方法可以清除缓存,可能是由另一个应用程序)@Pranaysharma - Mohamed Embaby
构造函数后面不是缺少了 execute() 吗:new fileFromBitmap(my_bitmap, getApplicationContext());? - Andrea Leganza
1
@AndreaLeganza 是的,它确实缺失了,我已经编辑了我的答案,感谢你。 - Mohamed Embaby
在AsyncTask中保留上下文可能会导致内存泄漏!!!https://www.youtube.com/watch?v=bNM_3YkK2Ws - slaviboy

9

大多数答案过长或过短,无法实现目的。对于那些正在寻找将位图转换为文件对象的Java或Kotlin代码的人来说,这里有一篇我写的详细文章。在Android中将位图转换为文件

public static File bitmapToFile(Context context,Bitmap bitmap, String fileNameToSave) { // File name like "image.png"
        //create a file to write bitmap data
        File file = null;
        try {
            file = new File(Environment.getExternalStorageDirectory() + File.separator + fileNameToSave);
            file.createNewFile();

//Convert bitmap to byte array
            ByteArrayOutputStream bos = new ByteArrayOutputStream();
            bitmap.compress(Bitmap.CompressFormat.PNG, 0 , bos); // YOU can also save it in JPEG
            byte[] bitmapdata = bos.toByteArray();

//write the bytes in file
            FileOutputStream fos = new FileOutputStream(file);
            fos.write(bitmapdata);
            fos.flush();
            fos.close();
            return file;
        }catch (Exception e){
            e.printStackTrace();
            return file; // it will return null
        }
    }

3
希望这能帮到您。
主活动类:AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)

    // Get the bitmap from assets and display into image view
    val bitmap = assetsToBitmap("tulip.jpg")
    // If bitmap is not null
    bitmap?.let {
        image_view_bitmap.setImageBitmap(bitmap)
    }


    // Click listener for button widget
    button.setOnClickListener{
        if(bitmap!=null){
            // Save the bitmap to a file and display it into image view
            val uri = bitmapToFile(bitmap)
            image_view_file.setImageURI(uri)

            // Display the saved bitmap's uri in text view
            text_view.text = uri.toString()

            // Show a toast message
            toast("Bitmap saved in a file.")
        }else{
            toast("bitmap not found.")
        }
    }
}


// Method to get a bitmap from assets
private fun assetsToBitmap(fileName:String):Bitmap?{
    return try{
        val stream = assets.open(fileName)
        BitmapFactory.decodeStream(stream)
    }catch (e:IOException){
        e.printStackTrace()
        null
    }
}


// Method to save an bitmap to a file
private fun bitmapToFile(bitmap:Bitmap): Uri {
    // Get the context wrapper
    val wrapper = ContextWrapper(applicationContext)

    // Initialize a new file instance to save bitmap object
    var file = wrapper.getDir("Images",Context.MODE_PRIVATE)
    file = File(file,"${UUID.randomUUID()}.jpg")

    try{
        // Compress the bitmap and save in jpg format
        val stream:OutputStream = FileOutputStream(file)
        bitmap.compress(Bitmap.CompressFormat.JPEG,100,stream)
        stream.flush()
        stream.close()
    }catch (e:IOException){
        e.printStackTrace()
    }

    // Return the saved bitmap uri
    return Uri.parse(file.absolutePath)
}

}


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接