首页 文章

将位图保存到位置

提问于
浏览
415

我正在开发一个功能,从Web服务器下载图像,将其显示在屏幕上,如果用户希望保留图像,请将其保存在某个文件夹中的SD卡上 . 是否有一种简单的方法来获取位图并将其保存到我选择的文件夹中的SD卡?

我的问题是我可以下载图像,将其作为位图显示在屏幕上 . 我能够找到将图像保存到特定文件夹的唯一方法是使用FileOutputStream,但这需要一个字节数组 . 我不确定如何转换(如果这是正确的方法)从Bitmap到字节数组,所以我可以使用FileOutputStream来写入数据 .

我的另一个选择是使用MediaStore:

MediaStore.Images.Media.insertImage(getContentResolver(), bm,
    barcodeNumber + ".jpg Card Image", barcodeNumber + ".jpg Card Image");

哪个可以保存到SD卡,但不允许您自定义文件夹 .

17 回答

  • 0

    在调用 bitmap.compress 之前,请确保已创建目录:

    new File(FileName.substring(0,FileName.lastIndexOf("/"))).mkdirs();
    
  • 1
    try (FileOutputStream out = new FileOutputStream(filename)) {
        bmp.compress(Bitmap.CompressFormat.PNG, 100, out); // bmp is your Bitmap instance
        // PNG is a lossless format, the compression factor (100) is ignored
    } catch (IOException e) {
        e.printStackTrace();
    }
    
  • 34

    在Android 4.4 Kitkat之后,截至2017年Android 4.4及更低的份额约为20%并且正在减少,因此无法使用 File class和 getExternalStorageDirectory() 方法保存到SD卡 . 此方法返回您的设备内部存储器和图像,保存每个应用程序可见 . 您还可以仅保存应用程序专用的图像,并在用户使用 openFileOutput() 方法删除应用程序时将其删除 .

    从Android 6.0开始,您可以将SD卡格式化为内部存储器,但只能将其格式化为您的设备 . (如果将SD car格式化为内部存储器,只有您的设备可以访问或查看其内容)您可以使用SD卡保存到该SD卡其他答案,但如果你想使用可移动的SD卡,你应该阅读下面的答案 .

    您应该使用 Storage Access Framework 获取uri到文件夹 onActivityResult 活动方法以获取用户选择的文件夹,并添加可翻译的持久权限以便在用户重新启动设备后能够访问文件夹 .

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
    
        if (resultCode == RESULT_OK) {
    
            // selectDirectory() invoked
            if (requestCode == REQUEST_FOLDER_ACCESS) {
    
                if (data.getData() != null) {
                    Uri treeUri = data.getData();
                    tvSAF.setText("Dir: " + data.getData().toString());
                    currentFolder = treeUri.toString();
                    saveCurrentFolderToPrefs();
    
                    // grantUriPermission(getPackageName(), treeUri,
                    // Intent.FLAG_GRANT_READ_URI_PERMISSION |
                    // Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
    
                    final int takeFlags = data.getFlags()
                            & (Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
                    // Check for the freshest data.
                    getContentResolver().takePersistableUriPermission(treeUri, takeFlags);
    
                }
            }
        }
    }
    

    现在,将保存文件夹保存到共享首选项,而不是每次要保存图像时都要求用户选择文件夹 .

    您应该使用 DocumentFile class来保存图像,而不是 FileParcelFileDescriptor ,有关详细信息,您可以使用 compress(CompressFormat.JPEG, 100, out); 方法和 DocumentFile 类检查this thread以将图像保存到SD卡 .

  • 0

    为视频创建视频缩略图 . 如果视频损坏或不支持格式,它可能返回null .

    private void makeVideoPreview() {
        Bitmap thumbnail = ThumbnailUtils.createVideoThumbnail(videoAbsolutePath, MediaStore.Images.Thumbnails.MINI_KIND);
        saveImage(thumbnail);
    }
    

    要在sdcard中保存位图,请使用以下代码

    Store Image

    private void storeImage(Bitmap image) {
        File pictureFile = getOutputMediaFile();
        if (pictureFile == null) {
            Log.d(TAG,
                    "Error creating media file, check storage permissions: ");// e.getMessage());
            return;
        } 
        try {
            FileOutputStream fos = new FileOutputStream(pictureFile);
            image.compress(Bitmap.CompressFormat.PNG, 90, fos);
            fos.close();
        } catch (FileNotFoundException e) {
            Log.d(TAG, "File not found: " + e.getMessage());
        } catch (IOException e) {
            Log.d(TAG, "Error accessing file: " + e.getMessage());
        }  
    }
    

    To Get the Path for Image Storage

    /** Create a File for saving an image or video */
    private  File getOutputMediaFile(){
        // To be safe, you should check that the SDCard is mounted
        // using Environment.getExternalStorageState() before doing this. 
        File mediaStorageDir = new File(Environment.getExternalStorageDirectory()
                + "/Android/data/"
                + getApplicationContext().getPackageName()
                + "/Files"); 
    
        // This location works best if you want the created images to be shared
        // between applications and persist after your app has been uninstalled.
    
        // Create the storage directory if it does not exist
        if (! mediaStorageDir.exists()){
            if (! mediaStorageDir.mkdirs()){
                return null;
            }
        } 
        // Create a media file name
        String timeStamp = new SimpleDateFormat("ddMMyyyy_HHmm").format(new Date());
        File mediaFile;
            String mImageName="MI_"+ timeStamp +".jpg";
            mediaFile = new File(mediaStorageDir.getPath() + File.separator + mImageName);  
        return mediaFile;
    }
    
  • 2

    您应该使用 Bitmap.compress() 方法将位图另存为文件 . 它将压缩(如果使用的格式允许)你的图片并将其推入OutputStream .

    以下是通过 getImageBitmap(myurl) 获得的Bitmap实例的示例,可以压缩为JPEG,压缩率为85%:

    // Assume block needs to be inside a Try/Catch block.
    String path = Environment.getExternalStorageDirectory().toString();
    OutputStream fOut = null;
    Integer counter = 0;
    File file = new File(path, "FitnessGirl"+counter+".jpg"); // the File to save , append increasing numeric counter to prevent files from getting overwritten.
    fOut = new FileOutputStream(file);
    
    Bitmap pictureBitmap = getImageBitmap(myurl); // obtaining the Bitmap
    pictureBitmap.compress(Bitmap.CompressFormat.JPEG, 85, fOut); // saving the Bitmap to a file compressed as a JPEG with 85% compression rate
    fOut.flush(); // Not really required
    fOut.close(); // do not forget to close the stream
    
    MediaStore.Images.Media.insertImage(getContentResolver(),file.getAbsolutePath(),file.getName(),file.getName());
    
  • 1

    实际上不是答案,而是评论 . 我在Mac上运行模拟器环境,并获得java.io.IOException:权限被拒绝 - 此代码出错:

    protected void onActivityResult(int requestCode, int resultCode, Intent imageReturnedIntent) {
        Log.d("DEBUG", "onActivityResult called");
        super.onActivityResult(requestCode, resultCode, imageReturnedIntent);
        if(requestCode == 0 && resultCode == RESULT_OK) {
            Log.d("DEBUG", "result is ok");
            try{
                Bitmap map = (Bitmap) imageReturnedIntent.getExtras().get("data");
                File sd = new File(Environment.getExternalStorageDirectory(), "test.png");
                sd.mkdirs();
                sd.createNewFile();
                FileOutputStream out = new FileOutputStream(sd);
                map.compress(Bitmap.CompressFormat.PNG, 90, out);
                out.flush();
                out.close();
            } catch(FileNotFoundException e){
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
    

    我还将uses-permission android.permission.WRITE_EXTERNAL_STORAGE添加到清单文件中(如其他人所述) .

  • 8
    Bitmap bbicon;
    
    bbicon=BitmapFactory.decodeResource(getResources(),R.drawable.bannerd10);
    //ByteArrayOutputStream baosicon = new ByteArrayOutputStream();
    //bbicon.compress(Bitmap.CompressFormat.PNG,0, baosicon);
    //bicon=baosicon.toByteArray();
    
    String extStorageDirectory = Environment.getExternalStorageDirectory().toString();
    OutputStream outStream = null;
    File file = new File(extStorageDirectory, "er.PNG");
    try {
        outStream = new FileOutputStream(file);
        bbicon.compress(Bitmap.CompressFormat.PNG, 100, outStream);
        outStream.flush();
        outStream.close();
    } catch(Exception e) {
    
    }
    
  • 13

    我发现发送PNG和透明度的方式 .

    String file_path = Environment.getExternalStorageDirectory().getAbsolutePath() +
                        "/CustomDir";
    File dir = new File(file_path);
    if(!dir.exists())
      dir.mkdirs();
    
    String format = new SimpleDateFormat("yyyyMMddHHmmss",
           java.util.Locale.getDefault()).format(new Date());
    
    File file = new File(dir, format + ".png");
    FileOutputStream fOut;
    try {
            fOut = new FileOutputStream(file);
            yourbitmap.compress(Bitmap.CompressFormat.PNG, 85, fOut);
            fOut.flush();
            fOut.close();
         } catch (Exception e) {
            e.printStackTrace();
     }
    
    Uri uri = Uri.fromFile(file);     
    Intent intent = new Intent(android.content.Intent.ACTION_SEND);
    intent.setType("image/*");
    intent.putExtra(android.content.Intent.EXTRA_SUBJECT, "");
    intent.putExtra(android.content.Intent.EXTRA_TEXT, "");
    intent.putExtra(Intent.EXTRA_STREAM, uri);
    
    startActivity(Intent.createChooser(intent,"Sharing something")));
    
  • 1

    我还想保存一张照片 . 但我的问题(?)是我想从我绘制的位图中保存它 .

    我这样做了:

    @Override
     public boolean onOptionsItemSelected(MenuItem item) {
                switch (item.getItemId()) {
                case R.id.save_sign:      
    
                    myView.save();
                    break;
    
                }
                return false;    
    
        }
    
    public void save() {
                String filename;
                Date date = new Date(0);
                SimpleDateFormat sdf = new SimpleDateFormat ("yyyyMMddHHmmss");
                filename =  sdf.format(date);
    
                try{
                     String path = Environment.getExternalStorageDirectory().toString();
                     OutputStream fOut = null;
                     File file = new File(path, "/DCIM/Signatures/"+filename+".jpg");
                     fOut = new FileOutputStream(file);
    
                     mBitmap.compress(Bitmap.CompressFormat.JPEG, 85, fOut);
                     fOut.flush();
                     fOut.close();
    
                     MediaStore.Images.Media.insertImage(getContentResolver()
                     ,file.getAbsolutePath(),file.getName(),file.getName());
    
                }catch (Exception e) {
                    e.printStackTrace();
                }
    
     }
    
  • 5
    outStream = new FileOutputStream(file);
    

    将在未经许可的情况下在AndroidManifest.xml中抛出异常(至少在os2.2中):

    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
    
  • 23

    为什么不用100调用 Bitmap.compress 方法(这听起来像是无损的)?

  • 6

    // | == |从位图创建PNG文件:

    void devImjFylFnc(String pthAndFylTtlVar, Bitmap iptBmjVar)
    {
        try
        {
            FileOutputStream fylBytWrtrVar = new FileOutputStream(pthAndFylTtlVar);
            iptBmjVar.compress(Bitmap.CompressFormat.PNG, 100, fylBytWrtrVar);
            fylBytWrtrVar.close();
        }
        catch (Exception errVar) { errVar.printStackTrace(); }
    }
    

    // | == |从文件中获取Bimap:

    Bitmap getBmjFrmFylFnc(String pthAndFylTtlVar)
    {
        return BitmapFactory.decodeFile(pthAndFylTtlVar);
    }
    
  • 8

    您想要将位图保存到您选择的目录中 . 我创建了一个库ImageWorker,使用户能够加载,保存和转换位图/ drawables / base64图像 .

    Min SDK - 14

    Pre-requisite

    • 保存文件需要WRITE_EXTERNAL_STORAGE权限 .

    • 检索文件需要READ_EXTERNAL_STORAGE权限 .

    保存位图/ Drawable / Base64

    ImageWorker.to(context).
        directory("ImageWorker").
        subDirectory("SubDirectory").
        setFileName("Image").
        withExtension(Extension.PNG).
        save(sourceBitmap,85)
    

    加载位图

    val bitmap: Bitmap? = ImageWorker.from(context).
        directory("ImageWorker").
        subDirectory("SubDirectory").
        setFileName("Image").
        withExtension(Extension.PNG).
        load()
    

    履行

    添加依赖项

    在项目级别Gradle中

    allprojects {
            repositories {
                ...
                maven { url 'https://jitpack.io' }
            }
        }
    

    在应用程序级别Gradle中

    dependencies {
                implementation 'com.github.1AboveAll:ImageWorker:0.51'
        }
    

    你可以在https://github.com/1AboveAll/ImageWorker/blob/master/README.md上阅读更多内容

  • 835

    某些格式,如无损的PNG,将忽略质量设置 .

  • 126

    以下是将位图保存到文件的示例代码:

    public static File savebitmap(Bitmap bmp) throws IOException {
        ByteArrayOutputStream bytes = new ByteArrayOutputStream();
        bmp.compress(Bitmap.CompressFormat.JPEG, 60, bytes);
        File f = new File(Environment.getExternalStorageDirectory()
                + File.separator + "testimage.jpg");
        f.createNewFile();
        FileOutputStream fo = new FileOutputStream(f);
        fo.write(bytes.toByteArray());
        fo.close();
        return f;
    }
    

    现在调用此函数将位图保存到内部存储器 .

    File newfile = savebitmap(bitmap) ;

    我希望它会对你有所帮助 . 快乐的编码生活 .

  • 0

    里面 onActivityResult

    String filename = "pippo.png";
    File sd = Environment.getExternalStorageDirectory();
    File dest = new File(sd, filename);
    
    Bitmap bitmap = (Bitmap)data.getExtras().get("data");
    try {
         FileOutputStream out = new FileOutputStream(dest);
         bitmap.compress(Bitmap.CompressFormat.PNG, 90, out);
         out.flush();
         out.close();
    } catch (Exception e) {
         e.printStackTrace();
    }
    
  • 8

    嘿只是给 .bmp 这个名字

    做这个:

    ByteArrayOutputStream bytes = new ByteArrayOutputStream();
    _bitmapScaled.compress(Bitmap.CompressFormat.PNG, 40, bytes);
    
    //you can create a new file name "test.BMP" in sdcard folder.
    File f = new File(Environment.getExternalStorageDirectory()
                            + File.separator + "**test.bmp**")
    

    听起来好像只是蠢蠢欲动但是一旦它被保存在bmp foramt中就试试吧 .

相关问题