I'm trying to find the size of the images being downloaded by a page; the obvious solution would be,
var imgs = [];
var imgTags = document.getElementsByTagName('img');
for (i = 0; i < imgTags.length; i++) {
var img = imgTags[i];
imgs.push({src: img.src, h: img.height, w: img.width});
}
but that will only retrieve the rendered size — for example, the ubiquitous spacer.gif will be 1x4, 4x4, etc., while it's obviously 1x1.
Moreover, that kind of document scanning doesn't seem to be able to pick the images that were downloaded, but not used in the img tags: CSS, backgrounds, etc.
The inspector in WebKit-based browsers seems to be pretty capable of rendering a preview — where does it take it from?
Hopefully, there two important properties for this : naturalWidth and naturalHeight (doc here)
Here is a sample script (first image of stackoverflow)
var page = require('webpage').create();
var url = 'http://www.stackoverflow.com/';
page.open(url, function(status) {
var first_image_dim = page.evaluate(function() {
return {width :$('img')[0].naturalWidth, height:$('img')[0].naturalHeight};
});
console.log(JSON.stringify(first_image_dim));
phantom.exit();
});
Related
How would I adapt #ghettovoice JSFiddle that saves a map to PDF to save the map to a JPEG or PNG? I have no idea how to attempt this problem so ideally if you know hoe to do it you can explain the logic behind it.
exportMap: function () {
var map = this.$refs.map
map.once('rendercomplete', function () {
var mapCanvas = document.createElement('canvas');
var size = map.getSize();
mapCanvas.width = size[0];
mapCanvas.height = size[1];
var mapContext = mapCanvas.getContext('2d');
Array.prototype.forEach.call(
document.querySelectorAll('.ol-layer canvas'),
function (canvas) {
if (canvas.width > 0) {
var opacity = canvas.parentNode.style.opacity;
mapContext.globalAlpha = opacity === '' ? 1 : Number(opacity);
var transform = canvas.style.transform;
// Get the transform parameters from the style's transform matrix
var matrix = transform
.match(/^matrix\(([^(]*)\)$/)[1]
.split(',')
.map(Number);
// Apply the transform to the export map context
CanvasRenderingContext2D.prototype.setTransform.apply(
mapContext,
matrix
);
mapContext.drawImage(canvas, 0, 0);
}
}
);
if (navigator.msSaveBlob) {
// link download attribuute does not work on MS browsers
navigator.msSaveBlob(mapCanvas.msToBlob(), 'map.png');
} else {
var link = document.getElementById('image-download');
link.href = mapCanvas.toDataURL();
link.click();
}
});
map.renderSync();
}
The problem was a combination of missing dependencies (namely FileSaver.js and fakerator.js) and a cross origin server block (CORS block) (Browsers automatically prevent httpRequests to a different domain name unless the server allows it). The first one is fixed by installing the packages while the second one is resolved by setting the crossOrigin Attribute of the ImageWMSLayer to null in my case but possibly to 'Anonymous' for other sources. Hope this helped someone else :)
Scenario
I'm contributing for a OSS project that is build on BlazorServerSide and ElectronNET.API Version 9.31.1.
In an Electron window we would like to show images from local storage UI via <img> tag.
What I have tried:
I have tried with:
<img src="file:///home/dani/pictures/someimage.jpg" />
But doesn't work. Image doesn't appear. I have then tried to create electron window with WebSecurity = false, but also doesn't help (images appears as broken on UI):
var browserWindowOptions = new BrowserWindowOptions
{
WebPreferences = new WebPreferences
{
WebSecurity = false,
},
};
Task.Run(async () => await Electron.WindowManager.CreateWindowAsync(
browserWindowOptions,
$"http://localhost:{BridgeSettings.WebPort}/Language/SetCultureByConfig"
));
Finally, as workaround, I'm sending the images as data base64 in img src's attribute, but it looks like a dirty approach.
My Question:
My question is, how can I show on electron window picture files from local storage.
Some irrelevant info:
The open source line where I need assistance.
There are several ways to go about this, so I will try to cover the most relevant use cases. Some of this depends on the context of your project.
Access to local files behave as cross origin requests by default. You could try using the crossorigin=anonymous attribute on your image tag, but doesn't work because your local file system will not be responding with cross origin headers.
Disabling the webSecurity option is a workaround, but is not recommended for security reasons, and will not usually work correctly anyway if your html is not also loaded from the local file system.
Disabling webSecurity will disable the same-origin policy and set allowRunningInsecureContent property to true. In other words, it allows the execution of insecure code from different domains.
https://www.electronjs.org/docs/tutorial/security#5-do-not-disable-websecurity
Here are some methods of working around this issue:
1 - Use the HTML5 File API to load local file resources and provide the ArrayBuffer to ImageData to write the image to a <canvas> .
function loadAsUrl(theFile) {
var reader = new FileReader();
var putCanvas = function(canvas_id) {
return function(loadedEvent) {
var buffer = new Uint8ClampedArray(loadedEvent.target.result);
document.getElementById(canvas_id)
.getContext('2d')
.putImageData(new ImageData(buffer, width, height), 0, 0);
}
}
reader.onload = putCanvas("canvas_id");
reader.readAsArrayBuffer(theFile);
}
1.b - It is also possible to load a file as a data URL. A data URL can be set as source (src) on img elements with JavaScript. Here is a JavaScript function named loadAsUrl() that shows how to load a file as a data URL using the HTML5 file API:
function loadAsUrl(theFile) {
var reader = new FileReader();
reader.onload = function(loadedEvent) {
var image = document.getElementById("theImage");
image.setAttribute("src", loadedEvent.target.result);
}
reader.readAsDataURL(theFile);
}
2 - Use the Node API fs to read the file, and convert it into a base64 encoded data url to embed in the image tag.
Hack - Alternatively you can try loading the image in a BrowserView or <webview>. The former overlays the content of your BrowserWindow while the latter is embedded into the content.
// In the main process.
const { BrowserView, BrowserWindow } = require('electron')
const win = new BrowserWindow({ width: 800, height: 600 })
const view = new BrowserView()
win.setBrowserView(view)
view.setBounds({ x: 0, y: 0, width: 300, height: 300 })
view.webContents.loadURL('file:///home/dani/pictures/someimage.jpg')
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);
}
);
});
};
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();
};
I'm trying to create a pdf but I have some SVG pictures. I found information about this problem, but I just have to use JavaScript, that's to say, no jQuery.
I found jsPDF here : https://github.com/MrRio/jsPDF
There is the plugin jspdf.plugin.sillysvgrenderer.js (in the same folder) and where we can find an exemple of PDF created in the folder test.
But when I try to generate the PDF on my own, it doesn't work and I don't understand why.
Do you know how to do it?
I got this plugin working, but only with SVG file from the tests and the I saw in the doc that only PATHs are supported :(
There is already the issue on github
https://github.com/MrRio/jsPDF/issues/384
If paths are ok for here is my code (it's more or less the code from the tests):
function demoSvgDocument() {
var doc = new jsPDF();
var test = $.get('013_sillysvgrenderer.svg', function(svgText){
var svgAsText = new XMLSerializer().serializeToString(svgText.documentElement);
doc.addSVG(svgAsText, 20, 20, doc.internal.pageSize.width - 20*2)
// Save the PDF
doc.save('TestSVG.pdf');
});
}
Another point to consider, you have to run all examples on a server. Otherwise you won't see any results probably because of the security
Try canvg for that to covert SVG to Canvas. Then convert the canvas to base64 string using .toDataURL().
More detailed answer is here https://stackoverflow.com/a/35788928/2090459
Check the demo here http://jsfiddle.net/Purushoth/hvs91vpq/
Canvg Repo: https://github.com/gabelerner/canvg
There now is svg2pdf.js which uses a fork of jsPDF.
It has been created to solve this exact task: Exporting an SVG to a PDF.
Also in the meantime, jsPDF also added a demo that shows how to possibly export SVG using canvg and the jsPDF canvas implementation.
The two solutions have different advantages and disadvantages, so you might want to try both and see if one of them suits your needs.
You can use the canvas plugin that comes with jsPDF to render the SVG on the PDF with canvg. I've had to set a few dummy properties on the jsPDF canvas implementation, and disable the interactive/animation features of canvg for this to work without errors:
var jsPdfDoc = new jsPDF({
// ... options ...
});
// ... whatever ...
// hack to make the jspdf canvas work with canvg
jsPdfDoc.canvas.childNodes = {};
jsPdfDoc.context2d.canvas = jsPdfDoc.canvas;
jsPdfDoc.context2d.font = undefined;
// use the canvg render the SVG onto the
// PDF via the jsPDF canvas plugin.
canvg(jsPdfDoc.canvas, svgSource, {
ignoreMouse: true,
ignoreAnimation: true,
ignoreDimensions: true,
ignoreClear: true
});
This seems to me a much better solution than the SVG plugin for jsPDF, as canvg has much better support of SVG features. Note that the width and height properties should be set on the <svg/> element of your SVG for canvg to render it correctly (or at least so it seemed to me).
I modified this from: https://medium.com/#benjamin.black/using-blob-from-svg-text-as-image-source-2a8947af7a8e
var yourSVG = document.getElementsByTagName('svg')[0];
//or use document.getElementById('yourSvgId'); etc.
yourSVG.setAttributeNS('http://www.w3.org/2000/xmlns/', 'xmlns', 'http://www.w3.org/2000/svg');
yourSVG.setAttributeNS('http://www.w3.org/2000/xmlns/', 'xmlns:xlink', 'http://www.w3.org/1999/xlink');
var serializer = new XMLSerializer();
var serialSVG = serializer.serializeToString(yourSVG);
var svg = serialSVG;
var blob = new Blob([svg], {type: 'image/svg+xml'});
var url = URL.createObjectURL(blob);
var image = document.createElement('img');
// image.addEventListener('load', () => URL.revokeObjectURL(url), {once: true});
//changed above line using babel to code below;
image.addEventListener('load', function () {
return URL.revokeObjectURL(url);
}, { once: true });
image.src = url;
//Then just use your pdf.addImage() function as usual;