Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using Spatie's Browsershot/Headless Chrome to capture extremely long screenshots

I periodically run into scenarios where I need to use Spatie's Browsershot to capture extremely tall web pages. However, when I do this, the resultant screenshot repeats every 16,384 pixels. (You can see an example of the repetition here: https://github.com/GoogleChrome/puppeteer/issues/1576)

This is a known limitation of Puppeteer (documented here). The recommended workaround for now seems to be taking several screenshots, and using clip() to offset the screenshot by increments of 16,384px. You can see an example of this approach using Node.js here.

Now, on the client side, that approach seems to work well enough, but that doesn't really help us in the context of the Browsershot library. As far as I know, there's no viable way to get the height of a page within PHP; can anyone think of any potential workarounds on the server side to hack an extremely long screenshot?

I know this isn't really the intended use of the library, and at the end of the day, it's not even the library's limitation, but I thought I'd throw it out there regardless.

like image 956
Cameron Scott Avatar asked Nov 07 '22 11:11

Cameron Scott


1 Answers

With the new contributions to the Spatie's Browsershot you can capture extremely tall web pages with the approach in your provided example easily.

$url = 'http://www.spiegel.de';

//Get scrollWidth and scrollHeight of the body in the emulated device
$browsershot = new Browsershot($url, true);
$dimensions = $browsershot
    ->device('iPhone 6')
    ->waitUntilNetworkIdle() // ensuring all additional resources are loaded
    ->evaluate("JSON.stringify({height: document.body.scrollHeight, width: document.body.scrollWidth})");

$dimensions = json_decode($dimensions); 

// iphone 6 scale factor is equal to 2
// https://github.com/GoogleChrome/puppeteer/blob/master/DeviceDescriptors.js#L288
$dpr = 2; 
$maxScreenshotHeight = floor(16 * 1024 / $dpr);

for ($ypos = 0; $ypos < $dimensions->height; $ypos += $maxScreenshotHeight) {
    $height = min($dimensions->height - $ypos, $maxScreenshotHeight);
    $browsershot = new Browsershot($url, true);
    $browsershot
        ->device('iPhone 6')
        ->waitUntilNetworkIdle()
        ->clip(0, $ypos, $dimensions->width, $height)
        ->timeout(120000) // handling timeout
        ->save('screenshot-@' . $ypos . 'px.png');
}
like image 163
shahabphp Avatar answered Nov 15 '22 05:11

shahabphp