I have a DIV container with an image set as background-image (specified by url). Is there any way how to redraw this background-image into canvas (without re-contacting or re-downloading from server -- as the content image is once-to-show)?
Yes. You can get the URL of the background image, request the image file as Blob, create an <img> element, set src to Blob URL of response, at load event of created img element call .drawImage() with img as first parameter.
The background image could be cached, depending on browser settings. If the image is not cached at browser, you can request image first, then set both css background-image and <canvas> using single request.
You can use fetch() or XMLHttpResponse() to request background-image url(), FileReader(), FileReader.prototype.readAsDataURL() to set src of <img> to .result of FileReader at load event.
You can also use URL.createObjectURL() to create a Blob URL from response Blob. URL.revokeObjectURL() to revoke the Blob URL.
Check Network tab at DevTools or Developer Tools, the image should be retrieved
(from cache)
#bg {
width:50px;
height:50px;
background-image:url(http://placehold.it/50x50);
}
<div id="bg"></div>
<br>
<canvas id="canvas" width="50px" height="50px"></canvas>
<script>
window.onload = function() {
var bg = document.getElementById("bg");
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
var img = new Image;
img.width = canvas.width;
img.height = canvas.height;
img.onload = (e) => ctx.drawImage(e.target,0,0);
var background = getComputedStyle(bg).getPropertyValue("background-image");
var src = background.replace(/^url|["()]/g, "");
var reader = new FileReader;
reader.onload = (e) => img.src = e.target.result;
fetch(src)
.then(response => response.blob())
.then(blob => {
reader.readAsDataURL(blob);
// const url = URL.createObjectURL(blob); img.src = url;
})
}
</script>
Related
For some reason,I can't use any xhr request in my webview,so all the src of img can be loaded when I open the html, but if I want to save them to a pdf using something like jsPDF, all the img will be missing because of xhr request fail.So I want to ask is there any way to convert img src to base64 after page loaded without xhr request? And after page loaded,I think the images are already downloaded, so is it possible to find it locally and convert to base64 then set them back to src?
maybe use canvas to change srcs to base64?
const images = document.querySelectorAll("img");
images.forEach(img => {
img.onload = function() {
const canvas = document.createElement("canvas");
const ctx = canvas.getContext("2d");
canvas.width = img.width;
canvas.height = img.height;
ctx.drawImage(img, 0, 0);
const dataURL = canvas.toDataURL("image/jpeg");
img.setAttribute("src", dataURL);
};
});
I want to save an image of the canvas tag, but when i try create an image from the canvas it tells me "SecurityError: The operation is insecure", which i believe is problems with the canvas coming from another domain than what im on. This canvas is a map which is generated with openlayers3.
var canvas = document.getElementsByClassName('ol-unselectable')[0];
var dataURL = canvas.toDataURL('image/png');
var window = window.open();
window.document.write('<img src='+dataURL+'/>');
I've also tried
canvas.toBlob(function(blob) {
saveAs(blob, 'map.png')
}
Is there an easy work around so the canvas is not tainted?
You tried write in new browser window from another window this is impossible without https protocol or localhost. But you can create new img in currently window.
var canvas = document.getElementsByClassName('ol-unselectable')[0];
var dataURL = canvas.toDataURL('image/png');
var img = new Image();
img.width = 1000;
img.height = 1000;
img.src = dataURL;
img.onload = function () {
document.body.append(img);
}
I want to create picture editor in js+jquery. At the first step i ask user to give image url. But I come across problem when i try load image data inside JS (to generate base64 image uri). I get error in console: … has beeb blocked by CORS policy: Access-Control-Allow-Origin …. But I wonder why? If in html file i create for instance (image hotlink):
<img src="https://static.pexels.com/photos/87293/pexels-photo-87293.jpeg" />
The browser load image without any CORS problems ! Here is my JS code which for the same image throw CORS problem:
function downloadFile(url) {
console.log({url});
var img = new Image();
img.onload = function() {
console.log('ok');
// never execute because cors error
// … make base64 uri with image data needed for further processing
};
img.crossOrigin = "Anonymous";
img.src = url;
}
So the question is - how to force JS to load image (as html-tag load it) and convert it to base64 url avoiding CORS problem?
https://static.pexels.com/photos/87293/pexels-photo-87293.jpeg
I try to found solution my self (JS ES6) but find only-partially. We are able to load img from no-CORS support src into canvas but browser switch cavnas into 'taint mode' which not allow us to call toDataURL (and any other access to content).
function loadImgAsBase64(url, callback) {
let canvas = document.createElement('CANVAS');
let img = document.createElement('img');
//img.setAttribute('crossorigin', 'anonymous');
img.src = url;
img.onload = () => {
canvas.height = img.height;
canvas.width = img.width;
let context = canvas.getContext('2d');
context.drawImage(img, 0, 0);
let dataURL = canvas.toDataURL('image/png');
canvas = null;
callback(dataURL);
};
}
let url = 'http://lorempixel.com/500/150/sports/9/';
this.loadImgAsBase64(url, (dataURL) => {
msg.innerText = dataURL.slice(0,50)+'...';
});
IMAGE DATA: loading...<br>
<div id="msg"></div>
So only way to overcome this obstacle is to create proxy server (e.g. in PHP) which will have CORS 'on' and it will download images for given url and send back to our app in JS. I found some free server https://cors-anywhere.herokuapp.com which we can use to in development to tests. Below there is full functional code which return dataUri from given image url:
function loadImgAsBase64(url, callback) {
let canvas = document.createElement('CANVAS');
let img = document.createElement('img');
img.setAttribute('crossorigin', 'anonymous');
img.src = 'https://cors-anywhere.herokuapp.com/' + url;
img.onload = () => {
canvas.height = img.height;
canvas.width = img.width;
let context = canvas.getContext('2d');
context.drawImage(img, 0, 0);
let dataURL = canvas.toDataURL('image/png');
canvas = null;
callback(dataURL);
};
}
let url = 'http://lorempixel.com/500/150/sports/9/';
this.loadImgAsBase64(url, (dataURL) => {
msg.innerText = dataURL.slice(0,50)+'...';
// show pic
document.body.innerHTML += `<img src="${dataURL}">`
});
IMAGE DATA Loading...<br>
<div id="msg"></div>
Thats all :) (I tested it on chrome, firefox and safari)
I had a similar issue and my issue was solved when I passed query parameter as part of the image url.
sample:
http://example.com/image.jpeg?test=123
The only way to avoid CORS is to make changes to avoid cross-origin sharing, at least let the browser thinks that it is cross-origin.
Or, you have to modify the server to support CORS.
I'm using a plugin (dom-to-image) to generate a SVG content from a div.
It returns me a dataURL like this:
data image/xml, charset utf-8, <svg...
If a put this on a <img src the image is shown to normally.
The intent is to grab this dataURL, convert it to base64 so I can save it as an image.png on a mobile app.
Is it possible?
I tryied this solution https://stackoverflow.com/a/28450879/1691609
But coudn't get to work.
The console fire an error about the dataUrl
TypeError: Failed to execute 'serializeToString' on 'XMLSerializer': parameter 1 is not of type 'Node'.
==== UPDATE :: PROBLEM EXPLANATION/HISTORY ====
I'm using Ionic Framework, so my project is an mobile app.
The dom-to-image is already working cause right now, its rendering a PNG through toPng function.
The problem is the raster PNG is a blurry.
So I thought: Maybe the SVG will have better quality.
And it IS!! Its 100% perfect, actually.
On Ionic, I'm using 2 step procedure to save the image.
After get the PNG generated by the dom-to-img(base64) dataURL, I convert it to a Blob and then save into device.
This is working, but the final result, as I said, is blurry.
Then with SVG maybe it will be more "high quality" per say.
So, in order to do "minimal" change on a process that s already working :D I just need to convert an SVG into base64 dataURL....
Or, as some of you explained to me, into something else, like canvas...
I don't know any much :/
===
Sorry for the long post, and I really, really thank your help guys!!
EDIT COUPLE OF YARS LATER
Use JS fiddle for a working example: https://jsfiddle.net/msb42ojx/
Note, if you don't own DOM content (images), and those images don't have CORS enabled for everyone (Access-Control-Allow-Origin header), canvas cant render those images
I'm not trying to find out why is your case not working, here is how I did when I had something similar to do:
get the image sourcce (dom-to-image result)
set up a canvas with that image inside (using the image source)
download the image from canvas in whatever image you like: png, jpeg whatever
by the way you can resize the image to a standard format
document.getElementById('mydownload').onclick= function(){
var wrapper = document.getElementById('wrapper');
//dom to image
domtoimage.toSvg(wrapper).then(function (svgDataUrl) {
//download function
downloadPNGFromAnyImageSrc(svgDataUrl);
});
}
function downloadPNGFromAnyImageSrc(src)
{
//recreate the image with src recieved
var img = new Image;
//when image loaded (to know width and height)
img.onload = function(){
//drow image inside a canvas
var canvas = convertImageToCanvas(img);
//get image/png from convas
var pngImage = convertCanvasToImage(canvas);
//download
var anchor = document.createElement('a');
anchor.setAttribute('href', pngImage.src);
anchor.setAttribute('download', 'image.png');
anchor.click();
};
img.src = src;
// Converts image to canvas; returns new canvas element
function convertImageToCanvas(image) {
var canvas = document.createElement("canvas");
canvas.width = image.width;
canvas.height = image.height;
canvas.getContext("2d").drawImage(image, 0, 0);
return canvas;
}
// Converts canvas to an image
function convertCanvasToImage(canvas) {
var image = new Image();
image.src = canvas.toDataURL("image/png");
return image;
}
}
#wrapper{
background: red;
color: blue;
}
<script src="https://rawgit.com/tsayen/dom-to-image/master/src/dom-to-image.js"></script>
<button id='mydownload'>Download DomToImage</button>
<div id="wrapper">
<img src="http://i.imgur.com/6GvKdxY.jpg"/>
<div> DUDE IS WORKING</div>
<img src="http://i.imgur.com/6GvKdxY.jpg"/>
</div>
I translated #SilentTremor's solution into React/JS-Class:
class SVGToPNG {
static convert = function (src) {
var img = new Image();
img.onload = function () {
var canvas = SVGToPNG.#convertImageToCanvas(img);
var pngImage = SVGToPNG.#convertCanvasToImage(canvas);
var anchor = document.createElement("a");
anchor.setAttribute("href", pngImage.src);
anchor.setAttribute("download", "image.png");
anchor.click();
};
img.src = src;
};
static #convertImageToCanvas = function (image) {
var canvas = document.createElement("canvas");
canvas.width = image.width;
canvas.height = image.height;
canvas.getContext("2d").drawImage(image, 0, 0);
return canvas;
};
static #convertCanvasToImage = function (canvas) {
var image = new Image();
image.src = canvas.toDataURL("image/png");
return image;
};
}
export default SVGToPNG;
Usage:
let dataUrl = someCanvas.toDataURL("image/svg+xml");
SVGToPNG.convert(dataUrl);
I'm working on an offline mode for a simple application, and I'm using Indexeddb (PounchDB as a library), I need to convert an Image to Base64 or BLOB to be able to save it.
I have tried this code which works for only one Image (the Image provided) I don't know why it doesn't work for any other image:
function convertImgToBase64URL(url, callback, outputFormat){
var img = new Image();
img.crossOrigin = 'Anonymous';
img.onload = function(){
var canvas = document.createElement('CANVAS'),
ctx = canvas.getContext('2d'), dataURL;
canvas.height = img.height;
canvas.width = img.width;
ctx.drawImage(img, 0, 0);
dataURL = canvas.toDataURL(outputFormat);
callback(dataURL);
canvas = null;
};
img.src = url;
}
convertImgToBase64URL('http://upload.wikimedia.org/wikipedia/commons/4/4a/Logo_2013_Google.png', function(base64Img){
alert('it works');
$('.output').find('img').attr('src', base64Img);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="output"> <img> </div>
It works fine, but only with one Image, If I try any other Image it doesn't work
The image you're using has CORS headers
Accept-Ranges : bytes
Access-Control-Allow-Origin : * // this one
Age : 69702
Connection : keep-alive
which is why it can be modified in a canvas like that.
Other images that don't have CORS headers are subject to the same-origin policy, and can't be loaded and modified in a canvas in that way.
I need to convert Image URL to Base64
See
Understanding the HTML5 Canvas image security rules
Browser Canvas CORS Support for Cross Domain Loaded Image Manipulation
Why does canvas.toDataURL() throw a security exception?
One possible workaround would be to utilize FileReader to convert img , or other html element to a data URI of html , instead of only img src; i.e.g., try opening console at jsfiddle http://jsfiddle.net/guest271314/9mg5sf7o/ , "right-click" on data URI at console, select "Open link in new tab"
var elem = $("div")[0].outerHTML;
var blob = new Blob([elem], {
"type": "text/html"
});
var reader = new FileReader();
reader.onload = function (evt) {
if (evt.target.readyState === 2) {
console.log(
// full data-uri
evt.target.result
// base64 portion of data-uri
, evt.target.result.slice(22, evt.target.result.length));
// window.open(evt.target.result)
};
};
reader.readAsDataURL(blob);
Another possible workaround approach would be to open image in new tab , window ; alternatively an embed , or iframe element ; utilize XMLHttpRequest to return a Blob , convert Blob to data URI
var xhr = new XMLHttpRequest();
// load `document` from `cache`
xhr.open("GET", "", true);
xhr.responseType = "blob";
xhr.onload = function (e) {
if (this.status === 200) {
// `blob` response
console.log(this.response);
var reader = new FileReader();
reader.onload = function(e) {
// `data-uri`
console.log(e.target.result);
};
reader.readAsDataURL(this.response);
};
};
xhr.send();
Do you need something like this?
http://www.w3docs.com/tools/image-base64