【问题标题】:Android bitmaps and capturing screenAndroid 位图和截屏
【发布时间】:2012-02-11 18:53:09
【问题描述】:

我有一个应用程序可以在 TableLayout 中生成具有可变数量的 TableRows 的报告。

我使用以下代码将表格捕获为位图:

TableLayout tl = (TableLayout)findViewById(R.id.CSRTableLayout);
Bitmap csr = Bitmap.createBitmap(tl.getWidth(), tl.getHeight(), Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(csr);
tl.draw(canvas);

将屏幕捕获为位图后,我将其附加到电子邮件中:

//folder already exists
File file = new File(folder.getAbsolutePath()+"/CSR"+csrnum+".jpg");
BufferedOutputStream bos = null;
FileOutputStream fos = null;
try {
    fos=new FileOutputStream(file);
    bos=new BufferedOutputStream(fos);
    if(bos!=null) {
        try {
            csr.compress(Bitmap.CompressFormat.JPEG, 60, bos);
        } catch (OutOfMemoryError e) {
            Toast.makeText(CustomerReportActivity.this, "Out of Memory!", Toast.LENGTH_SHORT).show();
        } finally {
            fos.flush();
            fos.close();
            bos.flush();
            bos.close();
        }
    }
} catch (Exception e) {
    e.printStackTrace();
}
if(file.exists()) {
    Intent i = new Intent(Intent.ACTION_SEND);
    i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    i.setType("message/rfc822");
    String emailTo[] = {"***@****.***"}; 
    i.putExtra(Intent.EXTRA_EMAIL,emailTo);
    i.putExtra(Intent.EXTRA_SUBJECT,"...");
    i.putExtra(Intent.EXTRA_TEXT, "...");
    i.putExtra(Intent.EXTRA_STREAM,Uri.parse("file://"+file.getAbsolutePath()));
    startActivity(i);
} else {
    Toast.makeText(CustomerReportActivity.this, "Error attaching report to email!", Toast.LENGTH_SHORT).show();
}

问题是有时表格会变得非常大,例如 1600x2400dp。我在“Bitmap.createBitmap(...)”行上得到了 OutOfMemoryError 是否有替代方法可以在不溢出 VM 堆的情况下捕获屏幕?如果我理解正确,调用 Bitmap.createBitmap(...) 正在创建一个全尺寸的位图,全都是纯白色的。是否可以在没有像素数据的情况下创建它,并且只有在我调用 csr.compress(...) 后才填充它,这样它才能保持很小?非常感谢任何想法/建议!提前致谢!

【问题讨论】:

  • 我认为这是你的好友stackoverflow.com/questions/5663671/…,我建议在开始时使用 Bitmap.Config.ARGB_8 然后更新它。
  • 尝试将 添加到清单文件中
  • @iLate: largeHeap=true 仅适用于 Android 3.0+ 我应该指定我们在 Android 2.3.3 平板电脑上运行它
  • 为什么需要发送位图格式的表格?为什么不生成表格数据的文本表示,这样您就不必生成巨大的位图了?

标签: java android bitmap out-of-memory


【解决方案1】:

您为什么不将图像分割成多个较小的区域并发送....然后您可以将它们缝合回来....或者如果您有耐心和技巧...您可以通过阅读保存在磁盘上的较小图像文件并发送拼接图像...您可以在发送到 draw() 方法之前使用翻译和剪辑画布来获取所需的区域

【讨论】:

  • 您能提供一个示例或示例代码吗?不幸的是,所有这些都需要在应用程序内完成,而其他地方的服务器无法完成。我对您的回答的理解是将屏幕捕获为多个位图,然后将它们组合起来并将其附加到电子邮件中。那是对的吗?当我重新组合然后将其传递给电子邮件意图时,应用程序中的内存是否会出现任何问题?
  • 我没有这方面的示例/来源...只是有一个想法...而且我认为您不会遇到内存问题,因为您将使用文件一旦您将零件图像存储在磁盘上...您可以使用缓冲文件流来处理它...再次所有这些都是理论上的...您在开发时可能会遇到其他一些我无法保证的问题。 ..
【解决方案2】:

在创建位图时,为什么不硬核一下宽度和高度。

Bitmap result = Bitmap.createScaledBitmap(bitmapPicture,
                        640, 480, false);

试试这个,让我知道这是否有任何帮助。

【讨论】:

    【解决方案3】:

    尝试将您的解决方案与 iDroid Explorer 的解决方案结合起来。检查您是否可以直接从图形缓存写入文件。你的代码看起来是这样的:

    try {
        BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(file));
        if(bos!=null) {
            try {
                TableLayout tl = (TableLayout)findViewById(R.id.CSRTableLayout);
                tl.setDrawingCacheEnabled(true);
                Bitmap csr = tl.getDrawingCache();
                csr.compress(Bitmap.CompressFormat.JPEG, 60, bos);
                tl.setDrawingCacheEnabled(false);
            } catch (OutOfMemoryError e) {
                Toast.makeText(CustomerReportActivity.this, "Out of Memory!", Toast.LENGTH_SHORT).show();
            } finally {
                bos.close();
            }
        }
    } catch (Exception e) {
        e.printStackTrace();
    }
    

    也许,您需要在关闭绘图缓存后回收csr

    【讨论】:

    • 我明天将对此进行测试。显然你无法捕捉到 OutOfMemoryError,所以测试起来很痛苦!我会在完成后立即报告并选择一个答案!
    【解决方案4】:

    前几天我有同样的任务要做。 如果您想捕获屏幕并且该图像应通过电子邮件发布,那么请研究以下我曾经做过的代码:

    saveImageInLandscapFunction(); // function to save the Image
    
                                Intent picMessageIntent = new Intent(android.content.Intent.ACTION_SEND);   
                                picMessageIntent.setType("image/jpeg");   
                                File f = new File(APP_FILE_PATH + "/"+filename+".jpg");
                                picMessageIntent.putExtra(Intent.EXTRA_STREAM, Uri.fromFile(f));
                                startActivity(picMessageIntent);
    

    截屏并保存到sdcard的功能

    protected void saveImageInLandscapFunction() {
        View root = findViewById(android.R.id.content);
        root.setDrawingCacheEnabled(true);
        Bitmap bm = Bitmap.createBitmap(root.getDrawingCache());
        //Bitmap bm = Bitmap.createBitmap(root.getDrawingCache(), 0, 0, display.getWidth(), display.getHeight());
        root.setDrawingCacheEnabled(false);
    
       // Bitmap overlayBitmap = overlay(photoBitmap, mBitmap); // overlay the Bitmap
    
        new ExportBitmapToFile(DrawMainActivity.this, bm).execute(); 
        sendBroadcast(new Intent(Intent.ACTION_MEDIA_MOUNTED, Uri.parse("file://"+ Environment.getExternalStorageDirectory())));
    
    }
    

    处理主要保存图像过程并在保存图像之前显示进度条的类:

    // for to saw progressBar
    public static class ExportBitmapToFile extends AsyncTask<Intent,Void,Boolean> {
        private Context mContext;
        private Handler mHandler;
        private Bitmap nBitmap;
        private ProgressDialog  m_progressDialog = null; 
        @Override     
        protected void onPreExecute(){         
            m_progressDialog = new ProgressDialog(mContext);  
            m_progressDialog.setTitle("Draw");
            m_progressDialog.setMessage("Please wait...");
            m_progressDialog.setCancelable(false);         
            m_progressDialog.show();     
        }
    
        public ExportBitmapToFile(Context context,Bitmap bitmap) {
            mContext = context;
            nBitmap = bitmap;
    
        }
    
        @Override
        protected Boolean doInBackground(Intent... arg0) {
            try {
                if (!APP_FILE_PATH.exists()) {
                    APP_FILE_PATH.mkdirs();
                }
                final FileOutputStream out = new FileOutputStream(new File(APP_FILE_PATH + "/"+filename+".jpg"));
                nBitmap.compress(Bitmap.CompressFormat.JPEG, 100, out);
                out.flush();
                out.close();
                return true;
            }catch (Exception e) {
                e.printStackTrace();
            }
            //mHandler.post(completeRunnable);
            return false;
        }
    
        @Override
        protected void onPostExecute(Boolean bool) {
            super.onPostExecute(bool);
            if ( bool ){
                //mHandler.sendEmptyMessage(1);
            }
            if (m_progressDialog.isShowing()) {             
                m_progressDialog.dismiss();          
            }  
        }
    }
    

    希望这会对您有所帮助。

    如果您需要其他帮助,请告诉我。

    享受。 :)

    【讨论】:

    • 您的解决方案没有解决内存问题。这和我现在做的基本一样
    【解决方案5】:

    不幸的是,没有办法避免我的问题。我只需要使用较低质量的设置,并希望尺寸不会变得太大。尝试缩放位图无法正常工作,最终导致图像失真。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-07-12
      • 2017-10-04
      • 1970-01-01
      • 1970-01-01
      • 2017-11-15
      • 1970-01-01
      • 2022-09-28
      • 2017-10-09
      相关资源
      最近更新 更多