【问题标题】:Save bitmap to file function将位图保存到文件功能
【发布时间】:2012-07-01 17:57:34
【问题描述】:

我正在尝试使用我创建的函数直接将位图保存到文件和特定位置。它不工作。它在 bitmap.compress 部分(here3 之前)之后崩溃。

    File dir = new File(filepath);

    if(!dir.exists())dir.mkdirs();

    File file = new File(Environment.getExternalStorageDirectory() + filepath, side + ".png");
    FileOutputStream fOut = new FileOutputStream(file);

    bitmap.compress(Bitmap.CompressFormat.PNG, 85, fOut);
    fOut.flush();
    fOut.close();

    System.out.println(filepath);

    bitmap.recycle();
    System.gc();

错误日志:

06-29 00:16:38.089: D/AndroidRuntime(3260): Shutting down VM
06-29 00:16:38.089: W/dalvikvm(3260): threadid=1: thread exiting with uncaught exception (group=0xb587f4f0)
06-29 00:16:38.089: E/AndroidRuntime(3260): FATAL EXCEPTION: main
06-29 00:16:38.089: E/AndroidRuntime(3260): java.lang.RuntimeException: Failure delivering result ResultInfo{who=null, request=0, result=-1, data=Intent { act=android.intent.action.VIEW dat=content://org.openintents.filemanager/mimetype//mnt/sdcard/download/02977_awreckedboatintheocean_1280x1024.jpg }} to activity {com.polygonattraction.testbirds/com.polygonattraction.testbirds.functions.SelectImageSource}: java.lang.IllegalStateException: Can't compress a recycled bitmap
06-29 00:16:38.089: E/AndroidRuntime(3260):     at android.app.ActivityThread.deliverResults(ActivityThread.java:2532)
06-29 00:16:38.089: E/AndroidRuntime(3260):     at android.app.ActivityThread.handleSendResult(ActivityThread.java:2574)
06-29 00:16:38.089: E/AndroidRuntime(3260):     at android.app.ActivityThread.access$2000(ActivityThread.java:117)
06-29 00:16:38.089: E/AndroidRuntime(3260):     at android.app.ActivityThread$H.handleMessage(ActivityThread.java:961)
06-29 00:16:38.089: E/AndroidRuntime(3260):     at android.os.Handler.dispatchMessage(Handler.java:99)
06-29 00:16:38.089: E/AndroidRuntime(3260):     at android.os.Looper.loop(Looper.java:130)
06-29 00:16:38.089: E/AndroidRuntime(3260):     at android.app.ActivityThread.main(ActivityThread.java:3683)
06-29 00:16:38.089: E/AndroidRuntime(3260):     at java.lang.reflect.Method.invokeNative(Native Method)
06-29 00:16:38.089: E/AndroidRuntime(3260):     at java.lang.reflect.Method.invoke(Method.java:507)
06-29 00:16:38.089: E/AndroidRuntime(3260):     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:839)
06-29 00:16:38.089: E/AndroidRuntime(3260):     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:597)
06-29 00:16:38.089: E/AndroidRuntime(3260):     at dalvik.system.NativeStart.main(Native Method)
06-29 00:16:38.089: E/AndroidRuntime(3260): Caused by: java.lang.IllegalStateException: Can't compress a recycled bitmap
06-29 00:16:38.089: E/AndroidRuntime(3260):     at android.graphics.Bitmap.checkRecycled(Bitmap.java:180)
06-29 00:16:38.089: E/AndroidRuntime(3260):     at android.graphics.Bitmap.compress(Bitmap.java:581)
06-29 00:16:38.089: E/AndroidRuntime(3260):     at com.polygonattraction.testbirds.functions.Functions.SaveToFile(Functions.java:144)
06-29 00:16:38.089: E/AndroidRuntime(3260):     at com.polygonattraction.testbirds.functions.SelectImageSource.onActivityResult(SelectImageSource.java:113)
06-29 00:16:38.089: E/AndroidRuntime(3260):     at android.app.Activity.dispatchActivityResult(Activity.java:3908)
06-29 00:16:38.089: E/AndroidRuntime(3260):     at android.app.ActivityThread.deliverResults(ActivityThread.java:2528)

【问题讨论】:

  • "无法压缩回收的位图。"。你调用了 bitmap.recycle();在此之前的任何地方?
  • 旁注,如果您不需要立即收集该位图,则应尽可能延迟主要收集以提高应用程序的性能,我会标记您需要的所有内容收集,然后在您标记完所有内容后调用收集。

标签: android file-io android-intent bitmap android-file


【解决方案1】:
  1. 您需要manifest.xml 中的适当权限:

    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
    
  2. out.flush() 检查out 不为空..

  3. String file_path = Environment.getExternalStorageDirectory().getAbsolutePath() + 
                                "/PhysicsSketchpad";
    File dir = new File(file_path);
    if(!dir.exists())
        dir.mkdirs();
    File file = new File(dir, "sketchpad" + pad.t_id + ".png");
    FileOutputStream fOut = new FileOutputStream(file);
    
    bmp.compress(Bitmap.CompressFormat.PNG, 85, fOut);
    fOut.flush();
    fOut.close();
    

【讨论】:

  • sorry not get ,如果文件不存在,你要写文件吗?
  • PNG 将跳过压缩率 85,因为 JPEG - 90 是最佳的。
【解决方案2】:

在科特林中:

private fun File.writeBitmap(bitmap: Bitmap, format: Bitmap.CompressFormat, quality: Int) {
    outputStream().use { out ->
        bitmap.compress(format, quality, out)
        out.flush()
    }
}

用法示例:

File(exportDir, "map.png").writeBitmap(bitmap, Bitmap.CompressFormat.PNG, 85)

【讨论】:

    【解决方案3】:

    两个例子对我有用,供你参考。

    Bitmap bitmap = Utils.decodeBase64(base64);
    try {
        File file = new File(filePath);
        FileOutputStream fOut = new FileOutputStream(file);
        bitmap.compress(Bitmap.CompressFormat.PNG, 85, fOut);
        fOut.flush();
        fOut.close();
    }
    catch (Exception e) {
        e.printStackTrace();
        LOG.i(null, "Save file error!");
        return false;
    }
    

    还有这个

    Bitmap savePic = Utils.decodeBase64(base64);
    File file = new File(filePath);
    File path = new File(file.getParent());
    
    if (savePic != null) {
        try {
            // build directory
            if (file.getParent() != null && !path.isDirectory()) {
                path.mkdirs();
            }
            // output image to file
            FileOutputStream fos = new FileOutputStream(filePath);
            savePic.compress(Bitmap.CompressFormat.PNG, 90, fos);
            fos.close();
            ret = true;
        } catch (Exception e) {
            e.printStackTrace();
        }
    } else {
        LOG.i(TAG, "savePicture image parsing error");
    }
    

    【讨论】:

      【解决方案4】:

      这里有帮助你的功能

      private void saveBitmap(Bitmap bitmap,String path){
              if(bitmap!=null){
                  try {
                      FileOutputStream outputStream = null;
                      try {
                          outputStream = new FileOutputStream(path); //here is set your file path where you want to save or also here you can set file object directly
      
                          bitmap.compress(Bitmap.CompressFormat.PNG, 100, outputStream); // bitmap is your Bitmap instance, if you want to compress it you can compress reduce percentage
                          // PNG is a lossless format, the compression factor (100) is ignored
                      } catch (Exception e) {
                          e.printStackTrace();
                      } finally {
                          try {
                              if (outputStream != null) {
                                  outputStream.close();
                              }
                          } catch (IOException e) {
                              e.printStackTrace();
                          }
                      }
                  } catch (Exception e) {
                      e.printStackTrace();
                  }    
              }
          }
      

      【讨论】:

        【解决方案5】:

        实现直接保存位图和加载位图。在 mfc 类上快速轻松

        void CMRSMATH1Dlg::Loadit(TCHAR *destination, CDC &memdc)
        {
        CImage img;
        PBITMAPINFO bmi;
        BITMAPINFOHEADER Info;
        BITMAPFILEHEADER bFileHeader;
        CBitmap bm;     
        CFile file2;
        file2.Open(destination, CFile::modeRead | CFile::typeBinary);
        file2.Read(&bFileHeader, sizeof(BITMAPFILEHEADER));
        file2.Read(&Info, sizeof(BITMAPINFOHEADER));    
        BYTE ch;
        int width = Info.biWidth;
        int height = Info.biHeight;
        if (height < 0)height = -height;
        int size1 = width*height * 3;
        int size2 = ((width * 24 + 31) / 32) * 4 * height;
        int widthnew = (size2 - size1) / height;
        BYTE * buffer = (BYTE *)GlobalAlloc(GPTR, size2);
        //////////////////////////
        HGDIOBJ old;
        unsigned char alpha = 0;    
        int z = 0;  
        z = 0;
        int gap = (size2 - size1) / height;
        for (int y = 0;y < height;y++)
        {
            for (int x = 0;x < width*3;x++)
            {
                file2.Read(&ch, 1);
                buffer[z] = ch;
                z++;
            }
            for (int z1 = 0;z1 <gap;z1++)
            {
                file2.Read(&ch,1);
            }
        }
        bm.CreateCompatibleBitmap(&memdc, width, height);
        bm.SetBitmapBits(size1,buffer);
        old = memdc.SelectObject(&bm);   
        ///////////////////////////  
         //bm.SetBitmapBits(size1, buffer);     
         GetDC()->BitBlt(1, 95, width, height, &memdc, 0, 0, SRCCOPY);
         memdc.SelectObject(&old);
         bm.DeleteObject();
         GlobalFree(buffer);     
         file2.Close();
         }
         void CMRSMATH1Dlg::saveit(CBitmap &bit1, CDC &memdc, TCHAR *destination)
          {     
        BITMAP bm;
        PBITMAPINFO bmi;
        BITMAPINFOHEADER Info;
        BITMAPFILEHEADER bFileHeader;
        CFile file1;
                    CSize size = bit1.GetBitmap(&bm);
         int z = 0;  
         BYTE ch = 0;
         size.cx = bm.bmWidth;
         size.cy = bm.bmHeight;
         int width = size.cx;    
         int size1 = (size.cx)*(size.cy);
         int size2 = size1 * 3;  
         size1 = ((size.cx * 24 + 31) / 32) *4* size.cy;     
         BYTE * buffer = (BYTE *)GlobalAlloc(GPTR, size2);               
         bFileHeader.bfType = 'B' + ('M' << 8); 
         bFileHeader.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
         bFileHeader.bfSize = bFileHeader.bfOffBits + size1;
         bFileHeader.bfReserved1 = 0;
         bFileHeader.bfReserved2 = 0;   
         Info.biSize = sizeof(BITMAPINFOHEADER);
         Info.biPlanes = 1;
         Info.biBitCount = 24;//bm.bmBitsPixel;//bitsperpixel///////////////////32
         Info.biCompression = BI_RGB;
         Info.biWidth =bm.bmWidth;
         Info.biHeight =-bm.bmHeight;///reverse pic if negative height
         Info.biSizeImage =size1;
         Info.biClrImportant = 0;
         if (bm.bmBitsPixel <= 8)
         {
             Info.biClrUsed = 1 << bm.bmBitsPixel;
         }else
         Info.biClrUsed = 0;
         Info.biXPelsPerMeter = 0;
         Info.biYPelsPerMeter = 0;
         bit1.GetBitmapBits(size2, buffer);      
         file1.Open(destination, CFile::modeCreate | CFile::modeWrite |CFile::typeBinary,0);
         file1.Write(&bFileHeader, sizeof(BITMAPFILEHEADER));
         file1.Write(&Info, sizeof(BITMAPINFOHEADER));
         unsigned char alpha = 0;    
         for (int y = 0;y<size.cy;y++)
         {
             for (int x = 0;x<size.cx;x++)
             {
                 //for reverse picture below
                 //z = (((size.cy - 1 - y)*size.cx) + (x)) * 3;          
             z = (((y)*size.cx) + (x)) * 3;
             file1.Write(&buffer[z], 1);
             file1.Write(&buffer[z + 1], 1);
             file1.Write(&buffer[z + 2], 1);
             }               
             for (int z = 0;z < (size1 - size2) / size.cy;z++)
             {
                 file1.Write(&alpha, 1);
             }
         }   
         GlobalFree(buffer);     
         file1.Close();  
         file1.m_hFile = NULL;
                }
        

        【讨论】:

        • 请注意问题中的android标签
        猜你喜欢
        • 2013-03-16
        • 1970-01-01
        • 2011-05-08
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-05-25
        相关资源
        最近更新 更多