Android位图和捕获屏幕

时间:2012-01-16 21:41:15

标签: java android bitmap out-of-memory

我有一个应用程序,它在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(...)时填充它以便它保持小?任何想法/建议都非常感谢!提前谢谢!

5 个答案:

答案 0 :(得分:0)

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

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);

使用screenShot并保存到SD卡的功能

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();          
        }  
    }
}

希望这对你很有帮助。

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

享受。 :)

答案 1 :(得分:0)

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

答案 2 :(得分:0)

在创建位图时,为什么不用硬度来表示宽度和高度。

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

试试这个,请告诉我这是否有任何帮助。

答案 3 :(得分:0)

尝试将您的解决方案和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

答案 4 :(得分:0)

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