简体   繁体   中英

Android bitmaps and capturing screen

I have an app that generates a report in a TableLayout with a variable number of 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. 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? If I understand correctly, calling Bitmap.createBitmap(...) is creating a bitmap the full size that is all just plain white. 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? 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

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. 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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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