Html2canvas: facebook plugin comments - javascript

I have a website witch uses facebook plugin comments. I'm looking for a way to have those comments inside a screenshot. If I use the simple html2canvas I get a blank box instead of them. So I try to use html2canvasproxy but now it print some javascript console log instead of the facebook comments.
It shoud be like but I get . I noticed that the html2canvasproxy.php saves the facebook plugin html correctly.
I can't find any javascript error in the console log.
I'm using the following code to take the screenshot:
html2canvas(document.body, {
"logging": true, //Enable log (use Web Console for get Errors and Warnings)
"proxy":"js/html2canvasproxy.php",
"onrendered": function(canvas) {
var img = new Image();
img.onload = function() {
img.onload = null;
document.body.appendChild(img);
};
img.onerror = function() {
img.onerror = null;
if(window.console.log) {
window.console.log("Not loaded image from canvas.toDataURL");
} else {
alert("Not loaded image from canvas.toDataURL");
}
};
img.src = canvas.toDataURL("image/png");
}
});
And I have this settings in html2canvasproxy.php:
//Turn off errors because the script already own uses "error_get_last"
error_reporting(0);
//setup
define('JSLOG', 'console.log'); //Configure alternative function log, eg. console.log, alert, custom_function
define('PATH', '../screenshots');//relative folder where the images are saved
define('CCACHE', 60 * 5 * 1000);//Limit access-control and cache, define 0/false/null/-1 to not use "http header cache"
define('TIMEOUT', 30);//Timeout from load Socket
define('MAX_LOOP', 10);//Configure loop limit for redirect (location header)
define('CROSS_DOMAIN', 0);//Enable use of "data URI scheme"
//constants
define('EOL', chr(10));
define('WOL', chr(13));
define('GMDATECACHE', gmdate('D, d M Y H:i:s'));

First idea I got while reading is to include some timeout - waiting a bit longer (let's say 200ms) - so that you have more probability for things to get loaded.
But after reading this on plugin site: "The script allows you to take "screenshots" of webpages or parts of it, directly on the users browser. The screenshot is based on the DOM and as such may not be 100% accurate to the real representation as it does not make an actual screenshot, but builds the screenshot based on the information available on the page." it could not help.
Personally I would investigate using another solution - like for example PhantomJS:
"PhantomJS is a headless WebKit scriptable with a JavaScript API. It has fast and native support for various web standards: DOM handling, CSS selector, JSON, Canvas, and SVG."
It's easy like this:
var page = require('webpage').create();
page.open('http://github.com/', function() {
page.render('github.png');
phantom.exit();
});

Related

Adding img.crossOrigin = "*" interferes with img.complete

I have a function that reads map tile images. I want to keep track of whether or not a certain image has already been cached. I'm using this function from this thread:
function is_cached(src) {
var image = new Image();
image.src = src;
return image.complete;
}
This was working great. But then I needed to do some image processing. In order to copy the image data to a canvas and process it pixel by pixel, I need to use CanvasRenderingContext2D.drawImage(image, 0, 0). But it bugs me with a cross-origin error. So I can add a image.crossOrigin = "*", which solves that problem, and I can write to a canvas and do the image processing I need. That bit looks like this:
imageOutput.crossOrigin = "*"
var demCtx;
imageOutput.onload = function(){
var c = document.createElement('canvas')
c.width = c.height = 256
demCtx = c.getContext('2d')
demCtx.drawImage(imageOutput, 0, 0)
var imageData = demCtx.getImageData(0, 0, 256, 256)
}
The issue that arises is that every time I run the larger function which contains these two bits of code, the is_cached function returns false every time, except the first time. But I know that even though is_cached is returning false, the images are indeed cached, as they are loading with 0 lag (as opposed to when a novel image is called and it takes a moment to grab it from the server).
Why might .crossOrigin = "*" be interfering with the .complete status of an image?
This is happening within an ObservableHQ notebook. Might that have something to do with it? ObservaleHQ gets weird sometimes.
ObservableHQ Notebook with the problem
You can find this code in the getTileUrl cell at the bottom. This notebook is not yet finished. You can see the cached status at the Tile Previously Cached line after you click around the map of submit changes to the inputs.
Thanks for reading.
Maybe fetch api can enforce cache using the param {cache:"force-cache"}, however images should be cached as expected. You can fetch the image and pass its blob as an image source.
replace your imageOutput.src with
imageOutput.src = URL.createObjectURL(await fetch(imageUrl, {cache:"force-cache"}).then(r => r.blob()));
make your getTileURL function async as we have to await fetch and blob to be ready to be passed as image source
async function getTileURL(latArg, lngArg, zoomArg) {
Use devtools to inspect network and see tile images coming from disk cache
edit:
just try your original code and inspect network via devtools. The tiles images are cache as expected. So no need to hack into fetch blob src.

How to take a snapshot of webpage from the url?

I want to take a snapshot of the webpage from the url. The url is an html web page which is dynamic. Basically we needed an img of that webpage.
I thought to convert the html page to image in c# but din't work.
I first read the html using streamreader and using NReco.ImageGenerator tried to convert into bytes and finally image. This isnt working.
Finally I am trying to convert html to canvas using javascript from inside the html web page.
function report() {
let region = document.querySelector("body");
html2canvas(
$('body'),
{allowTaint: true, logging: true,'onrendered': function (canvas)
{}}).then( //getting problem here at then
function (canvas) {
let jpgUrl = canvas.toDataURL();
console.log(jpgUrl);
var text = "bottom-right Brochure1";
var imageName = text + '.jpg';
download(jpgUrl,imageName, "image/png");
}
Code explained - It will take a snpashot of the body element in the html page using js. Take the url and create the canvas from the url. and automatically download. But i face a issue ------- " html2canvas(...),then is not a function" .. I dont know why its happening. Please help.
Because of Cross-Origin Resource Sharing (CORS) restrictions in all modern browsers, this can't be done purely on the clientside. You need something on the server-side to accomplish this. To do it in javascript on the server use NodeJS there are several npm packages that can help like: node-server-screenshot, PhantomJS etc

Printing a PDF file with Electron JS

I am trying to create an Electron JS app that has the purpose to print letter size PDFs.
This is my snippet of code for printing:
win = new BrowserWindow({
width: 378,
height: 566,
show: true,
webPreferences: {
webSecurity: false,
plugins: true
}
});
// load PDF
win.loadURL('file://' + __dirname + '/header1_X_BTR.pdf');
// if pdf is loaded start printing
win.webContents.on('did-finish-load', () => {
win.webContents.print({silent: true, printBackground:true});
});
My issues are: if I have print({silent:true}) my printer prints an empty page. If I have print({silent:false}), the printer prints in the same way as the screenshot, with headers, controls, etc.
I need a silent print of the PDF content, and I can't manage to do it for days. Did anyone experience the same thing with Electron?
If you have already have the pdf file or you save the pdf before printing "I assuming it is", then you can grab the file location then you can use externals process to do the printing using child_process.
You can use lp command or PDFtoPrinter for windows
const ch = require('os');
switch (process.platform) {
case 'darwin':
case 'linux':
ch.exec(
'lp ' + pdf.filename, (e) => {
if (e) {
throw e;
}
});
break;
case 'win32':
ch.exec(
'ptp ' + pdf.filename, {
windowsHide: true
}, (e) => {
if (e) {
throw e;
}
});
break;
default:
throw new Error(
'Platform not supported.'
);
}
I hope it helps.
Edit:
You can also use SumatraPDF for windows https://github.com/sumatrapdfreader/sumatrapdf
The easiest way to do this is to render the PDF pages to individual canvas elements on a page using PDF.js and then call print.
I fixed this gist to use the PDF.js version (v1) it was designed for and its probably a good starting point.
This is essentially what the electron/chrome pdf viewer is doing but now you have full control over the layout!
<html>
<body>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/pdf.js/1.10.90/pdf.js"></script>
<script type="text/javascript">
function renderPDF(url, canvasContainer, options) {
var options = options || { scale: 1 };
function renderPage(page) {
var viewport = page.getViewport(options.scale);
var canvas = document.createElement('canvas');
var ctx = canvas.getContext('2d');
var renderContext = {
canvasContext: ctx,
viewport: viewport
};
canvas.height = viewport.height;
canvas.width = viewport.width;
canvasContainer.appendChild(canvas);
page.render(renderContext);
}
function renderPages(pdfDoc) {
for(var num = 1; num <= pdfDoc.numPages; num++)
pdfDoc.getPage(num).then(renderPage);
}
PDFJS.disableWorker = true;
PDFJS.getDocument(url).then(renderPages);
}
</script>
<div id="holder"></div>
<script type="text/javascript">
renderPDF('//cdn.mozilla.net/pdfjs/helloworld.pdf', document.getElementById('holder'));
</script>
</body>
</html>
I'm facing the same issue. It appears the PDF printing to a printer is just not implemented in Electron, despite it's been requested since 2017. Here is another related question on SO and the feature request on GitHub:
Silent printing in electron
Support printing in native PDF rendering
One possible solution might be to use Google PDFium and a wrapping NodeJS library which appears to allow conversion from PDF to a set of EMFs, so the EMFs can be printed to a local/network printer, at least on Windows.
As another viable option, this answer provides a simple C# solution for PDF printing using PdfiumViewer, which is a PDFium wrapper library for .NET.
I'm sill looking at any other options. Utilizing a locally installed instance of Acrobat Reader for printing is not an acceptable solution for us.
UPDATED. For now, PDF.js solves the problem with rendering/previewing individual pages, but as to printing itself, it appears Electron (at the time of this posting) just lacks the proper printing APIs. E.g., you can't set paper size/landscape portrait mode etc. Moreover, when printing, PDF.js produces rasterized printouts - thanks to how HTML5 canvas work - unlike how Chrome PDF Viewer does it. Here is a discussion of some other PDF.js shortcomings.
So for now I think we might go on with a combination of PDF.js (for UI in the Electron's Renderer process) and PDFium (for actual printing from the Main process).
Based on Tim's answer, here's a version of the PDF.js renderer using ES8 async/await (supported as of the current version of Electron):
async function renderPDF(url, canvasContainer, options) {
options = options || { scale: 1 };
async function renderPage(page) {
let viewport = page.getViewport(options.scale);
let canvas = document.createElement('canvas');
let ctx = canvas.getContext('2d');
let renderContext = {
canvasContext: ctx,
viewport: viewport
};
canvas.height = viewport.height;
canvas.width = viewport.width;
canvasContainer.appendChild(canvas);
await page.render(renderContext);
}
let pdfDoc = await pdfjsLib.getDocument(url);
for (let num = 1; num <= pdfDoc.numPages; num++)
{
if (num > 1)
{
// page separator
canvasContainer.appendChild(document.createElement('hr'));
}
let page = await pdfDoc.getPage(num);
await renderPage(page);
}
}
Since your are using contents.print([options], [callback]) I will assume that you want to print on paper and not on your Disk.
The answer to your issue is simple. It is the event you are listening on which is causing the error. So if you simply do this:
winObject.webContents.on('did-frame-finish-load', () => {
setTimeout(() => {winObject.webContents.print({silent: true, printBackground:true})}, 3000);
});
everything will work fine if the default printer is the right one. I did test this and it will do its job more or less. You can change my event to whatever event you like, the important part is the waiting with setTimeout. The PDF you are trying to print is simply not available in the frame when using silent:true.
However let me get into detail here a little bit to make things clear:
Electron will load Files or URLs into a created window (BrowserWindow) which is bound to events. The problem is that every event "can" behave differently on different systems.
We have to live with that and cannot change this easily. But knowing this will help improve the development of custom Apps.
If you load urls or htmls everything will work without setting any custom options. Using PDFs as source we have to use this:
import electron, { BrowserWindow } from 'electron';
const win = new BrowserWindow({
// #NOTE I did keep the standard options out of this.
webPreferences: { // You need this options to load pdfs
plugins: true // this will enable you to use pdfs as source and not just download it.
}
});
hint: without webPreferences: { plugins: true } your source PDF will be downloaded instead of loaded into the window.
That said you will load your PDF into the webContents of your window. So we have to listen on events compatible with BrowserWindow. You did everything right, the only part you missed was that printing is another interface.
Printing will capture your webContents as it is when you press "print". This is very inportant to know when working with printers. Because if something will load slightly longer on a different system, for example the PDFs viewer will be still dark grey without the letters, then your printing will print the dark grey background or even the buttons.
That little issue is easily fixed with setTimeout().
Useful Q&A for printing with electron:
Silent printing in electron
Print: How to stick footer on every page to the bottom?
However there are alot more possible issues with printing, since most of the code is behind closed doors without worldwide APIs to use. Just keep in mind that every printer can behave differently so testing on more machines will help.
This is 2021 and here is the simplest way ever.
Let's begin
First of all, install the pdftoprinter
npm install --save pdf-to-printer
import the library into your file
const ptp require('pdf-to-printer') // something like this
Then call the method into your function
ptp.print('specify your route/url');
It should work!
So it seems like you're trying to download the pdf file rather than print a pdf of the current screen which is what print tries to do. As such, you have a couple of options.
1) Disable the native pdf viewer in electron:
If you don't care about the electron window displaying the pdf, disabling the native pdf viewer in electron should instead cause it to treat the file as a download and attempt to download it.
new BrowserWindow({
webPreferences: {
plugins: false
}
})
You may also want to checkout electron's DownloadItem api to do some manipulation on where the file will be saved.
2) Download the pdf through some other api
I'm not gonna give any specifics for this one because you should be able to find some information on this yourself, but basically if you want to download the file from somewhere, then you can use some other download API like an AJAX library to download the file and save it somewhere. This would potentially allow you to render the document in an electron window as well, since once you initiate the download you can probably redirect the window to the pdf url and have the native viewer handle it.
Long story short, it sounds to me like you don't really want to print from electron, you just want to save the pdf file that you're displaying. Printing from electron will render what you see on the screen, not the pdf document itself so I think you just misunderstood what the goal of print was. Hopefully this helps you, good luck!
=== EDIT ===
Unfortunately, I don't believe that there is a way to print the file directly from electron since electron printing is for printing the contents of electrons display. But you should be able to download the file via a simple request for the file (see above).
My recommendation for you would be to create a page for previewing the file. This would be an independent page, not the built in pdf viewer. You can then insert a button somewhere on the page to download the pdf via some means and skip any save location prompts (this should be easy enough to find documentation for).
Then, in order to have your preview, on the same page you can have a webview tag into your page, which will display the native pdf viewer. In order for the native pdf viewer to work in the webview tag, you must include the plugins attribute in the tag. It's a boolean tag, so it's mere presence is all that is needed such as <webview ... plugins> This turns on plugin support for that webview's renderer which is required for the pdf viewer.
You can modify the size styling of this tag on the page as you wish to suit your needs. A trick to get rid of the download and print options so that a user cannot press them is to append #toolbar=0 to the end of the pdf url to prevent the native pdf viewer from displaying the top toolbar with these buttons.
So, this way you can have your preview, ensure that the user can't use the built in download or print from the pdf viewer with the extra ui, and you can add another button to download it so it can be printed later.

Javascript: How to check if image is already cached

I just started to learn a little bit of JavaScript and i wondered if there is a way to check if an image is already loaded to cache.
In my script im loading some random images from another webpage and display them.
When the same image will be displayed the second time, the script won't use the already loaded image, but instead load the same image again, so that there are two of them stored in my cache.
Now I want to check if the image is already stored in cache and if so, use the cached one instead of loading it again.
My code:
<script>
var img = document.createElement('img');
var index;
//On Click create random 3digit number between 1 and 100
document.getElementById('image').onclick = function(){
var index = '' + Math.floor(Math.random() * 100 +1);
while(index.length < 3) {
index = '0' + index;
}
loadImages(index);
};
//Load the image with the created number
function loadImages(id) {
var src = 'someWebPage/' + id +'.png';
img.onload = function () {
document.getElementById('image').getContext("2d").drawImage(img, 0, 0, 300, 300);
}
img.src = src;
}
</script>
Picture of my cache:
As you can see 030.png and 032.png are twice in cache.
Hope you can give me some advice.
EDIT:
Just for anyone else that faces this problem, it actually isnĀ“t one at all.
Chrome already did everything right, i only did not notice.
As you can see in the column Size the pictures were already loaded from my cache.
The way caching (in this context) is handled is by the browser negotiating with the server using a set of headers to basically tell the server "I already have this version of this resource", to which the server can then respond "OK, that is still valid, no need to download anything new". So you shouldn't be concerned about the caching in the JavaScript side, but instead make sure you are setting the correct Cache-Control headers on the server side. There are likely already questions/answers for your server/framework of choice on how to setup the caching there.

build a chrome extension in order to upload images (from clipboard)

I wanted to write a simple chrome extension in order to substitute the following sequence of steps which i have to do very often for university:
make screenshot of something
edit screenshot in Paint
save unnamend.png to harddrive
upload unnamed.png to imageshack.us/pic-upload.de or any
other website
share link of image with others.
I don't care which image upload service to use, i just want automize this use-case in order to save time (I already red and did a getting-started chrome extension and checked out their API, but that's it, this page: http://farter.users.sourceforge.net/blog/2010/11/20/accessing-operating-system-clipboard-in-chromium-chrome-extensions/ seemed useful, but i couldn't make it overwrite my systems clipboard - moreover i can't find a tutorial which helps me further).
To answer your questions, I will give you some hints and resources to do what you want:
1 - Screenshot using Chrome Extensions API
You can use chrome.tabs.captureVisibleTab to screenshot what you see.
chrome.tabs.captureVisibleTab(null, {format:'png'}, function(dataURL) {
// Your image is in the dataURL
});
2 - Edit Screenshot using HTML5
Well, here is a tricky one, why do you want to use Paint while you can use HTML5 or a web service? If you want to use paint, then the only way doing this is natively through NPAPI (C++). Exposing something natively is really discouraged since it poses additional security risks to users. And it requires manual review for submission and a deadly warning when installing.
Why can't you use HTML5 Canvas to modify the screenshot? Or even, use Picnik online photo editing http://www.picnik.com/
var image_buffer = document.createElement('img');
image_buffer.src = dataURL; // From #1 capture tab
image_buffer.onload = function() {
var canvas = document.createElement('canvas');
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
var ctx = canvas.getContext('2d');
ctx.drawImage(image_buffer, 0, 0);
// Draw something extra ontop of it such as a circle.
ctx.beginPath();
ctx.arc(0, 0, 10, 0, Math.PI*2, true);
ctx.closePath();
ctx.fill();
// Convert that back to a dataURL
var dataURL = canvas.toDataURL('image/png');
// Base64 image only.
var image64 = dataURL.replace(/data:image\/png;base64,/, '');
};
3 - Save Image to Hard drive
This is another tricky one, right now, if you use a "service" like Picnick, then you can use their saving utility to save to your harddrive, otherwise you can use HTML5 FileWriter API which is currently being developed.
If you really want to with your MSPaint route, then you would need to use NPAPI as mentioned above.
But when you use HTML5, you can do the following, but it is still early in spec:
var bb = new BlobBuilder();
bb.append(image64); // From #2 when done editing.
var blob = bb.getBlob();
location.href = createObjectURL(blob);
4 - Upload image to an Online Image Service
You can use http://imgurl.com to upload too, it has a neat API that you can use. All you need to know is plain old javascript, just send an XHR request to request the service and communicate with it.
To do that, just use their API:
var xhr = new XMLHttpRequest();
xhr.open('POST', 'http://api.imgur.com/2/upload.json?key=' + apikey, true);
xhr.setRequestHeader('Cache-Control', 'no-cache');
xhr.onreadystatechange = function() {
if (this.readyState == 4) {
var response = JSON.parse(xhr.response);
if (response.error) {
alert('Error: ' + response.error.message);
return;
}
var image_url = response.upload.links.original;
}
};
xhr.send(image64); // From #2 where we edit the screenshot.
5 - Share link of image with others.
Same as above, this is just plain old javascript, depends on the service (Facebook, Twitter, Buzz), you use their API or another service does that already for you to share the images.
Note:
I would say the best way to do this extension is using HTML5. You can use XHR to communicate to external websites, Canvas to edit the photos, and FileWriter to persist that to disk.
I would highly discourage the NPAPI approach for such extension since it isn't needed. Plus, if you go through NPAPI, you would need to make it cross platform and develop plugins for each browser.

Categories

Resources