32

I think the title pretty much covers it, but I have a webview in my activity. I've loaded a url into the webview and I'd like to take a screenshot of the full page (whatever is in the viewport and the stuff "below the fold" as well).

I've got code that works to snapshot the viewport, and I know this can be done in iOS by enlarging the webview before snapshotting it. I've tried to use the same technique here:

    WebView browserView = (WebView) findViewById(R.id.browserView);

    //Resize the webview to the height of the webpage
    int pageHeight = browserView.getContentHeight();
    LayoutParams browserParams = browserView.getLayoutParams();
    browserView.setLayoutParams(new LinearLayout.LayoutParams(LayoutParams.FILL_PARENT, pageHeight));

    //Capture the webview as a bitmap
    browserView.setDrawingCacheEnabled(true);
    Bitmap bitmap = Bitmap.createBitmap(browserView.getDrawingCache());
    browserView.setDrawingCacheEnabled(false);

    //Create the filename to use
    String randomFilenamepart = String.valueOf(new SecureRandom().nextInt(1000000));
    String filename = Environment.getExternalStorageDirectory().toString() + "/Screenshot_" + randomFilenamepart + ".jpg";
    File imageFile = new File(filename);
    //Stream the file out to external storage as a JPEG
    OutputStream fout = null;
    try {
        fout = new FileOutputStream(imageFile);
        bitmap.compress(Bitmap.CompressFormat.JPEG, 100, fout);
        fout.flush();
        fout.close();
    } catch (FileNotFoundException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    } finally {
        browserView.setLayoutParams(browserParams);
    }

But I'm still only capturing just the viewport. Disregarding things like running out of memory because the page is too large, does anyone know what I'm doing wrong or how I can include the portion outside the viewport?

Rob Hruska
  • 118,520
  • 32
  • 167
  • 192
Mark Rausch
  • 512
  • 2
  • 5
  • 9
  • 2
    possible duplicate of [Capture picture from android webview](http://stackoverflow.com/questions/7702565/capture-picture-from-android-webview) – CommonsWare Mar 17 '12 at 00:06
  • I'm not sure this is a duplicate. The method described there has a big problem with it, PictureListener.onNewPicture() is deprecated. According to the docs - "Due to internal changes, the picture does not include composited layers such as fixed position elements or scrollable divs. While the PictureListener API can still be used to detect changes in the WebView content, you are advised against its usage until a replacement is provided in a future Android release". That doesn't sound like I'm going to get all the elements on the page. – Mark Rausch Mar 20 '12 at 21:11

3 Answers3

26

Try this one

import java.io.FileOutputStream;

import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Picture;
import android.os.Bundle;
import android.view.Menu;
import android.webkit.WebView;
import android.webkit.WebViewClient;

public class MainActivity extends Activity {

    WebView w;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        w = new WebView(this);
        w.setWebViewClient(new WebViewClient() {
            public void onPageFinished(WebView view, String url) {
                Picture picture = view.capturePicture();
                Bitmap b = Bitmap.createBitmap(picture.getWidth(),
                        picture.getHeight(), Bitmap.Config.ARGB_8888);
                Canvas c = new Canvas(b);

                picture.draw(c);
                FileOutputStream fos = null;
                try {

                    fos = new FileOutputStream("mnt/sdcard/yahoo.jpg");
                    if (fos != null) {
                        b.compress(Bitmap.CompressFormat.JPEG, 100, fos);

                        fos.close();
                    }
                } catch (Exception e) {

                }
            }
        });

        setContentView(w);
        w.loadUrl("http://search.yahoo.com/search?p=android");
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.activity_main, menu);
        return true;
    }
}

Add INTERNET PERMISSION and WRITE_EXTERNAL_STORAGE in AndroidManifest.xml file.

Need to ask permission at run time for file write if app is running on or above Marshmallow.

Natig Babayev
  • 3,128
  • 15
  • 23
avinash
  • 1,744
  • 24
  • 40
  • 1
    thanks. worked for me too. voted! How do I get rid of the additional whitespace in the captured image. Kindly let me know. I have posted a question here: http://stackoverflow.com/questions/14833051/android-webview-screenshot-white-border – pixelscreen Feb 12 '13 at 12:57
  • @avinash thakur I am keep getting FATAL Exception. I was trying to get your email from your profile , but could not find any. Would you please share a little more then listed here. I really need to solve this issue asap. Thanks in advance – Reaz Patwary Jan 27 '14 at 22:30
  • 1
    This codes actually works, you just forget to mention to add – ralphgabb Mar 14 '15 at 09:47
  • @avinash thanks for ur answer..but its not working in lollipop version.. can you update the answer plz? – user512 May 23 '15 at 09:38
  • @avinashthakur See [here](http://developer.android.com/reference/android/webkit/WebView.html#capturePicture()) for updated documentation. `#capturePicture()` was deprecated in API level 19. Docs recommend `#onDraw(Canvas)` or `#saveWebArchive(String)` instead. – boxed__l Jul 20 '15 at 09:44
  • Hey Guys, Im looking do the same in iOS device. Can someone guide me through that ? http://stackoverflow.com/questions/32436284/screenshot-ios-webview-context-full-page-screenshot-and-not-just-visible-view – Nikhil Nanjappa Sep 07 '15 at 10:16
  • 11
    It doesn't work in Android L and M unless you put this before setContentView(): `if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { WebView.enableSlowWholeDocumentDraw(); }` – Serdar Büyükkanlı May 11 '16 at 11:03
  • Writing to `/mnt/sdcard` won't work if your app is built for Android 6.0 and up without requesting permission from the user first. https://developer.android.com/training/permissions/requesting.html – Nick Shvelidze Oct 03 '16 at 12:42
  • Also, do not hardcode external storage path and use `context.getExternalStorageDirectory()` https://developer.android.com/reference/android/os/Environment.html#getExternalStorageDirectory() – Nick Shvelidze Oct 03 '16 at 12:42
  • 2
    capturePicture is now deprecated – Cyph3rCod3r Apr 30 '18 at 07:27
8

webview.capturePicture() is deprecated, use below way can do:

Bitmap bitmap = Bitmap.createBitmap(webview.getWidth(), webview.getHeight(), Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
webview.draw(canvas);
return bitmap;
Amos
  • 2,222
  • 1
  • 26
  • 42
  • This one doesn't seem to capture the content that is out of sight off the bottom of the screen on a long page, unless I'm missing something? – Matt B Jun 24 '21 at 16:37
  • 1
    Further to my last comment, and just in case it's useful for anyone in future - I found that using webView.getContentHeight() rather than getHeight() gave a good result. Also - this was fine for Android 9+. For earlier versions a slightly different technique was required where the webview needed to be programatically scrolled within a framelayout, and seperate images combined as the scroll progressed. – Matt B Jun 29 '21 at 14:04
2

@avinash thakur codes actually works, you just forget to mention to add <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> at Android Manifest file, otherwise, android wont allow your stream to write data / file on device.

cheers.

ralphgabb
  • 10,298
  • 3
  • 47
  • 56