Puppeteer full page screenshot, getting extra white space rendered at bottom of page - screenshot

I'm playing with Puppeteer v1.3.0 to generate some screenshots at various breakpoints during build/deploy. I don't seem to understand how to generate a full page screenshot properly.
I can get a full page screenshot exactly as I want it, but I have to set the viewport dimensions twice which seems very odd to me (I just set an arbitrary height, then evaluate the clientHeight):
//xl
await page.setViewport({
width: 1201,
height: 600
});
await page.setViewport({
width: 1201,
height: await page.evaluate(() => document.body.clientHeight),
isMobile: true //whether the meta viewport tag is taken into account
});
await page.screenshot({path: 'xl.png');
I've tried setting waitUntil networkidle, just evaluating the clientHeight and setting fullPage to true in the page.screenshot:
await page.goto('my-url-here', {
waitUntil: 'networkidle2'
});
await page.setViewport({
width: 1201,
height: await page.evaluate(() => document.body.clientHeight),
isMobile: true //whether the meta viewport tag is taken into account
});
await page.screenshot({path: 'arrowdental_xl.png', fullPage: true});
And I get a full page screenshot, but there's a bunch of extra white space at the bottom, which I don't want.
What's the proper way to get a full page screenshot in Puppeteer? Again, the first method above works, but it feels dumb I have to set the viewport dimensions twice. I'd like to have cleaner code, if possible.

With puppeteer sharp v 1.11.2
await new BrowserFetcher().DownloadAsync(BrowserFetcher.DefaultRevision);
var browser = await Puppeteer.LaunchAsync(new LaunchOptions
{
Headless = true,
});
var page = await browser.NewPageAsync();
await page.GoToAsync("https://www.google.com/");
await page.ScreenshotAsync(#"c:\temp\google.png", new ScreenshotOptions {FullPage = true});
so passing ScreenshotOptions.FullPage to ScreenshotAsync()

Related

MediaRecorder has a delay of multiple seconda

I'm trying to use a MediaRecorder to record a MediaStream and display it in a video element using a MediaSource. So the setup looks like:
Request a MediaStream from the browser
Add it to the MediaRecorder
Add the recorded blobs to the MediaSource Buffer
The result looks very good but there is one problem: There is a delay in the playback.
When displaying the MediaStream directly there is no delay so I sorted out the first bulletpoint as the problem.
Nevertheless, it seems like either the MediaRecorder or the MediaSource is adding a delay of about 3 seconds to the stream.
this.screenRecording = await mediaDevices.getDisplayMedia({ video: { frameRate: 60, resizeMode: 'none' } });
const mediaRecorder = new MediaRecorder(this.screenRecording);
mediaRecorder.ondataavailable = async (event: any) => {
if (this.screenReceiving.readyState === 'open') {
if (this.screenReceivingBuffer == null) {
this.screenReceivingBuffer = this.screenReceiving.addSourceBuffer('video/webm;codecs=vp8');
}
if (!this.screenReceivingBuffer.updating) {
this.screenReceivingBuffer.appendBuffer(await new Response(event.data).arrayBuffer());
}
}
};
mediaRecorder.start(16);
The above code is only copy & paste from the actual project so please don't expect it to work by copy & paste ;)
Does anyone have an idea why this delay exists?
Any ideas on how to tweak the browser to not add this delay?

Sharing image generated from html canvas on FB

This one I've been banging my head against for a few weeks now.
Scenario:
Let user generate an image out of layers they select
Convert image to canvas
Share image from canvas on facebook wall using share_open_graph (along with the image, a short text and title will be shared)
I've already had a solution in place using publish_actions but that was recently removed from the API and is no longer available.
I am using js and html for all code handling.
The issue is that I can generate a png image from the canvas but that is saved as base64 and share_open_graph doesn't allow this type of image, it needs a straight forward url such as './example.png'. I have tried using several approaches and with canvas2image, converting and saving image using file-system but all of these fail.
Does anyone have similar scenario and possible solution from April/May 2018 using share_open_graph ?
My current code looks like this - it fails at the image conversion and save to a file (Uncaught (in promise) TypeError: r.existsSync is not a function at n (file-system.js:30)). But I am open to different solutions as this is clearly not working.
html2canvas(original, { width: 1200, height: 628
}).then(function(canvas)
{
fb_image(canvas);
});
var fb_image = function(canvas) {
canvas.setAttribute('id', 'canvas-to-share');
document.getElementById('img-to-share').append(canvas);
fbGenerate.style.display = 'none';
fbPost.style.display = 'block';
var canvas = document.getElementById('canvas-to-share');
var data = canvas.toDataURL('image/png');
var encodedPng = data.substring(data.indexOf(',') + 1, data.length);
var decodedPng = base64.decode(encodedPng);
const buffer = new Buffer(data.split(/,\s*/)[1], 'base64');
pngToJpeg({ quality: 90 })(buffer).then(output =>
fs.writeFile('./image-to-fb.jpeg', output));
var infoText_content = document.createTextNode('Your image is being
posted to facebook...');
infoText.appendChild(infoText_content);
// Posting png from imageToShare to facebook
fbPost.addEventListener('click', function(eve) {
FB.ui(
{
method: 'share_open_graph',
action_type: 'og.shares',
href: 'https:example.com',
action_properties: JSON.stringify({
object: {
'og:url': 'https://example.com',
'og:title': 'My shared image',
'og:description': 'Hey I am sharing on fb!',
'og:image': './image-to-fb.jpeg',
},
}),
},
function(response) {
console.log(response);
}
);
});
};

phantomjs - running render after loading the page, but loading never fires

I'm trying to create a graph-to-png converter with phantomjs, but having a hard time getting it to work. Almost every example I see out there uses some external URL as if all you ever do with it is scraping, and the documentation is terribly lacking.
To test out things, I created a very simple d3 function that adds an <svg> tag and a blue circle inside. Looking at other questions on SO and examples, I hooked it to onLoadFinish but that event never triggers.
I'm guessing I need to open the page, but open only uses a url, which isn't relevant for me (and again, the docs are completely lacking in information. Even when I see something I think might be relevant, my only choice is guesswork. This is ridiculous )
Here's my code:
var page = require('webpage').create();
var content = '<html>';
content += '<body>';
content += '<h1> test title </h1>';
content += '<div id="graph">';
content += '</div>';
content += '</body></html>';
page.content = content;
page.injectJs('lib/d3/d3.min.js');
page.onLoadFinish = function(status) {
console.log('loading finished'); // this never happens!
var svg = d3.select('#graph')
.append('svg')
.attr({'width': 100, 'height': 100});
var circle = svg
.append('circle')
.attr({ 'cx': 10, 'cy': 10, 'r': 10, 'fill': 'blue' });
page.render('test.png');
phantom.exit();
};
Any suggestions?
It's evaluate. That was the function I was looking for. It "evaluates the given function in the context of the web page".
Finally, it's working:
page.content = content;
page.injectJs('lib/d3/d3.min.js');
page.evaluate(function() {
var svg = d3.select('#graph')
.append('svg')
.attr({'width': 100, 'height': 100});
var circle = svg
.append('circle')
.attr({ 'cx': 10, 'cy': 10, 'r': 10, 'fill': 'blue' });
page.render('test.png');
phantom.exit();
};

Cropping PhantomJS screen capture sized to content

PhantomJS is doing a great job of capturing web pages into image files for me. I am using a script based on rasterize.js.
However, for certain web elements of a fixed size, I need the resulting image to match the size of the web element.
e.g. I have a page like this:
<html>
<body>
<div id="wrapper" style="width:600px; height:400px;">
Content goes here...
</div>
</body>
</html>
In this example, I need it to produce an image sized at 600x400. Is thre a way to get the viewport size dynamically based on a web element in the page I am rasterizing.
I know this one is not a easy one... Ideas?
Thanks
Wow. Not that hard after all. Just set the viewport really big and use the cropRect function. What a great tool!
Mods to rasterize.js:
page.open(address, function (status) {
if (status !== 'success') {
console.log('Unable to load the address!');
} else {
var height = page.evaluate(function(){
return document.getElementById('wrapper').offsetHeight;
});
var width = page.evaluate(function(){
return document.getElementById('wrapper').offsetWidth;
});
console.log('Crop to: '+width+"x"+height);
page.clipRect = { top: 0, left: 0, width: width, height: height };
window.setTimeout(function () {
page.render(output);
phantom.exit();
}, 200);
}
});

Facebook Canvas App Height less than 800px

I have 2 facebook app one that is 872px height and another one that is 712px height. For the 827px app I have successfully re-sized the app from 800 to 872px using the facebook JS SDK. But for the 712px I haven't been able to get it down from 800px. Is there a minimum height for facebook canvas app or I'm doing something wrong?
Apparently Canvas APP can't go lower than 800 px.
have you tried to set the height dynamically? this worked for me as i am attempting to display multiple pages that are less than 800px in height. the usual height of my page tabs were ~700px.
window.fbAsyncInit = function() {
FB.init({
appId: window.FB_APP_ID
});
// set height dependent on page (min height is 800px)
// but we are attempting to get it shorter
var body_height = $('body').first().outerHeight();
FB.Canvas.setSize({
height: body_height
});
}
what also worked for me, if not grabbing the body height is to set the height to something shorter than any of your pages at load, then triggering the setAutoGrow() function to expand it to the proper height with some delay. though this will cause your canvas to be the initial set height (eg. 480px) then will expand to size whenever your timeout fires.
window.fbAsyncInit = function() {
FB.init({
appId: window.FB_APP_ID
});
FB.Canvas.setSize({
height: 480 // some height shorter than necessary
});
setTimeout(function(){
FB.Canvas.setAutoGrow();
}, 500);
}
To deal with it:
FB.Canvas.getPageInfo(
function(info) {
// console.log(info);
if (info.clientHeight< 800) FB.Canvas.setSize({ height: 800 });
}
);