简体   繁体   English

Android位图和捕获屏幕

[英]Android bitmaps and capturing screen

I have an app that generates a report in a TableLayout with a variable number of TableRows. 我有一个可在TableLayout中使用可变数量的TableRows生成报告的应用程序。

I use the following code to capture the Table into a bitmap: 我使用以下代码将表捕获到位图中:

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

After I capture the screen as a bitmap, I attach it to an email using: 将屏幕捕获为位图后,可以使用以下命令将其附加到电子邮件中:

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

The problem is that sometimes the table can get quite large, such as 1600x2400dp. 问题在于有时表可能会变得很大,例如1600x2400dp。 I have gotten an OutOfMemoryError on the line "Bitmap.createBitmap(...)" Is there an alternative method to capture the screen while not overflowing the VM heap? 我在“ Bitmap.createBitmap(...)”行上收到一个OutOfMemoryError,有没有一种替代方法可以在不溢出VM堆的情况下捕获屏幕? If I understand correctly, calling Bitmap.createBitmap(...) is creating a bitmap the full size that is all just plain white. 如果我理解正确,则调用Bitmap.createBitmap(...)会创建一个全尺寸的纯白色位图。 Is it possible to create it with NO pixel data and only fill it in once I called csr.compress(...) so that way it stays small? 是否可以不使用像素数据来创建它,而仅在我调用csr.compress(...)后才填充它,以使它保持较小的尺寸? Any ideas/suggestions are greatly appreciated! 任何想法/建议都将不胜感激! Thanks in advance! 提前致谢!

Unfortunately there was no way to avoid my issue. 不幸的是,没有办法避免我的问题。 I simply had to use a lower quality setting and hope the size did not become too big. 我只是不得不使用较低的质量设置,并希望尺寸不会太大。 Trying to scale the bitmap did not work properly and ended up with a distorted image. 尝试缩放位图无法正常工作,并最终导致图像失真。

Some days before i have the same task to do. 在几天前,我要做同样的任务。 If you want to capture the Screen and that image should be post via Email then please study the below code that i have used to do it: 如果您想捕获屏幕,并且该图像应该通过电子邮件发布,那么请研究以下我曾经使用过的代码:

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

Function that take screenShot and and save to the sdcard 取screenShot并保存到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())));

}

Class that handle the main save image process and show the progressbar till image is saved: 用于处理主要保存图像过程并显示进度条直到保存图像的类:

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

Hope this will surly help you. 希望这对您有帮助。

Let me know if you want amy other help. 如果您需要其他帮助,请告诉我。

Enjoy. 请享用。 :) :)

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

While creating the bitmap, why dont you hardcore the width and height. 创建位图时,为什么不硬化宽度和高度。

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

Try this out, let me know if this is of any help or not. 试试看,让我知道这是否有帮助。

Try to combine your solution and iDroid Explorer's one. 尝试将您的解决方案与iDroid Explorer的解决方案结合起来。 Check if you can write to file straight from drawing cache. 检查是否可以直接从图形缓存写入文件。 You code will look this way: 您的代码将如下所示:

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

Maybe, you'll need to recycle csr after switching off drawing cache. 也许,您需要在关闭图形缓存后回收csr

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM