I have a div containing an image and some text. The user is able to customize it. Once his modifications are done, I would like to save the div as an image with the text on it.
Just like if he took a screenshot.
I am able to save images from Base64 strings in my PHP side but I can't get the correct Base64 from the HTML.
So, I would like to know how to get the base64 from the HTML inside my div, using JavaScript or jQuery. I could also add plugins.
Try
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);
jsfiddle http://jsfiddle.net/guest271314/9mg5sf7o/
Try html2canvas
http://html2canvas.hertzen.com/examples.html
html2canvas($("#div"), {
onrendered: function(canvas) {
var myImage = canvas.toDataURL("img/png");
window.open(myImage);
}
});
Related
I am converting an image to Base64 from Image URL using canvas. The approach I am taking is similar to below 2 links but the converted Base64 string is not opening up the image when viewed in Chrome Tab.
Links
CONVERT Image url to Base64
(1st answer with 81 thumbs up).
https://jsfiddle.net/3qshvc54/
I tried consoling the img, canvas, ctx in fiddle and my code. The console output is the same. Please see below screenshots.
If I do it by fiddle the converted Base64 URL opens up fine in a new tab, but the one generated from my code does not display an image when opened up in a new tab.
I am using same Image URL in my code and Fiddle
Console screenshot when running from my code
Console screenshot when running from Fiddle
The Base64 generated from my code:
data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEQAAABDCAYAAAAlFqMKAAAApklEQVR4Xu3VsQ0AIAwEMbL/0tShQLrejHB6kzneKjB67AKCPIsQRJD/J2EhFmIh6ZAigwwyyKQCyCCTBuPKIIMMMqkAMsikwbgyyCCDTCqADDJpMK4MMsggkwogg0wajCuDDDLIpALIIJMG48oggwwyqQAyyKTBuDLIIINMKoAMMmkwrgwyyCCTCiCDTBqMK4MMMsikAsggkwbjyiCDDDKpADL/XBfFQABED54eAwAAAABJRU5ErkJggg==
I tried validating the same online it shows that the Base64 string is valid:
When I try to decode the same:
It seems that the result of decoding is a binary data (MIME type detected as “image/png”) and because of this the data from “Text” may be damaged during the output.
My code:
<div className='image-root'>
<img id={`imageBlock-${props.photoBoxID}`} className="multi-image-photo" src={props.imgUrl} alt="photo"></img>
</div>
getBase64Image = (img) => {
img.crossOrigin = 'Anonymous';
var canvas = document.createElement("CANVAS");
canvas.width = img.width;
canvas.height = img.height;
console.log('img', img);
var ctx = canvas.getContext("2d");
ctx.drawImage(img, 0, 0);
console.log('canvas', canvas);
console.log('ctx', ctx);
var dataURL = canvas.toDataURL();
console.log('dataURL', dataURL);
}
componentDidUpdate(prevProps, prevState){
if(this.props.isUploaded && (prevProps.isUploaded !== this.props.isUploaded)){
let imageRef = document.getElementById(`imageBlock-${this.props.photoBoxID}`);
imageRef.onload = this.getBase64Image(imageRef);
}
}
Can you suggest why the Base64 string generated is not opening up fine if converted from my code, though it opens up from Fiddle? Is it corrupted?
onload is an event you need function there and in that function you need to update src.
componentDidUpdate(prevProps, prevState){
if(this.props.isUploaded && (prevProps.isUploaded !== this.props.isUploaded)){
let imageRef = document.getElementById(`imageBlock-${this.props.photoBoxID}`);
imageRef.onload = () => {
delete imageRef.onload;
imageRef.src = this.getBase64Image(imageRef);
};
}
}
but better is to add base64 image to state and don't use getElementById directly in React applications.
EDIT:
for infinite loop I would create 2 images, if you need to render image on canvas you usually render outside of DOM:
componentDidUpdate(prevProps, prevState){
if(this.props.isUploaded && (prevProps.isUploaded !== this.props.isUploaded)){
let imageRef = document.getElementById(`imageBlock-${this.props.photoBoxID}`);
var srcImg = new Image();
srcImg.onload = () => {
imageRef.src = this.getBase64Image(srcImg);
};
srcImg.src = prevProps.imgUrl;
}
}
and remove the props from JSX template you will not need it.
And side note: if you have big image it's better to create object URL from blob, because there is limit of data that can be put into URL (for smaller images it should not matter):
function asObjectUrl(canvas) {
return new Promise(function(resolve) {
canvas.toBlob(function(blob) {
resolve(URL.createObjectURL(blob));
});
});
}
The object url need to be removed when not needed to not create memory leaks (use URL.revokeObjectURL)
change your img's src attribute adding src="data:image/jpeg;base64 tag with the encoded string like below:
<img id={`imageBlock-${props.photoBoxID}`} className="multi-image-photo" src="data:image/jpeg;base64, ${props.imgUrl}" alt="photo"></img>
This should work.
N.B.: Please check your imageString variable carefully, I might have used the wrong one, not sure.
I'm building a program that allows the user to choose an image to upload. Once the user chooses one, it triggers the previewFile() function, which uses FileReader to display the image.
Now I'm building a function that will download the same image that the user uploaded (and add some style changes). First, I created a new image element, but now I'm stuck, since I can't figure out how to reference the src value of the original image. Once I do get the src value, I can finish adding the styles, then download the edited image.
Here's what I have so far - can anyone help me out?
HTML:
<input type="file" onchange="previewFile()">
<img src="" alt="Preview File...">
JavaScript:
function previewFile() {
const preview = document.querySelector('img');
const file = document.querySelector('input[type=file]').files[0];
const reader = new FileReader();
reader.addEventListener("load", function () {
preview.src = reader.result;
}, false);
if (file) {
reader.readAsDataURL(file);
}
}
And the function I need help with:
function createAndDownload() {
const editedImage = document.createElement('img');
/*
Here's where I need help: I need to figure out how to get the image src
from the original image, and set it equal to editedImage.src
*/
//add styles
//download editedImage
}
You assigned it this way:
const preview = document.querySelector('img');
preview.src = reader.result;
So you do the same thing to read it back:
const preview = document.querySelector('img');
const something = preview.src;
I'm using jquery cropbox for a little project.
First the <img> is a default image, then i do a upload and FileReader for changing the image to a locally stored image.
like this
$('#selectfiledialog').change(function(evt){
var tgt = evt.target || window.event.srcElement,
files = tgt.files;
if (FileReader && files && files.length) {
var fr = new FileReader();
fr.onload = function () {
$('#the_image').attr('src', fr.result);
}
fr.readAsDataURL(files[0]);
}
});
However, when i will start the croping function on this image, it has the old values of the default image here, a 500x500 image.
So, when I will do the croping it has not got the new specs.
How can i now refresh that img element based on the new src? "add '?' + Math.random();" or date string is the only thing I've found but the new url is base64 encoded so that will not work.
Any ideas?
1 . Create a container for the image before all;
2 . Delete the image and add another image in the container you created.
Note: If you do this you will lost references to the element of the image because it'll be removed. Avoid making continued references to the image, var img = $('#the_image'), i.e.
Your HTML should be similiar to:
<div id="img_container">
<img id="the_image" src=""/>
</div>
Change the script line:
$('#the_image').attr('src', fr.result);
to:
$('#the_image').remove();
$('img_container')append('<img id="the_image" src="' + fr.result + '"/>');
I selected a svg file and read it via readDataUrl(<file>), I can set it to an html image element by setting the src to be the value read from the file. However the width and height attributes will be 0. How can I set the value read from a file to an svg element in order to be able to do a getBBox().width to obtain its width?
You can use XMLHttpRequest (or your favourite AJAX library) to read and parse the SVG file. I imagine you can even just pass the dataurl to it if you want.
Edit, because I misread the question :
If you can append the svg to your document, and need to use a FileReader, use its readAsText() method, then insert it in an html element.
function previewFile() {
var file = document.querySelector('input[type=file]').files[0];
var reader = new FileReader();
reader.onloadend = function () {
var parent = document.getElementById('container');
parent.innerHTML= reader.result;
}
if (file && file.type=="image/svg+xml") {
reader.readAsText(file);
} else {
alert("wrong file type or no file provided");
}
}
<div id="container"></div>
<input type="file" onchange="previewFile()">
If you don't need to use a FileReader (e.g if the file is saved on the server), Paul's answer is better.
If you don't want to actually append the svg file but only know its width/height, you can refer to my
original answer :
I don't think you can get the height from the data url.
As a workaround, you can use the readAsText()method of the fileReader API, combined with the DOMParser() method, in order to read the viewBox property of the svg.
function xlog(msg){
document.getElementById('log').textContent = msg;
}
function previewFile() {
var file = document.querySelector('input[type=file]').files[0];
var reader = new FileReader();
reader.onloadend = function () {
var doc = new DOMParser().parseFromString(reader.result, 'application/xml');
var viewBox = doc.documentElement.viewBox.baseVal;
xlog('height:'+viewBox.height+' width:'+viewBox.width);
}
if (file && file.type=="image/svg+xml") {
reader.readAsText(file);
} else {
xlog("wrong file type or no file provided");
}
}
<p id="log"></p><br>
<input type="file" onchange="previewFile()">
Note that you can append the doc.documentElement into your document and then get the element's BBox.
Using Dropzone.js, I need to detect the dimesions of the image when added files and apply them to its parent .details div. The following code code works and return an alert with the added image width.
myDropzone.on("addedfile", function(file, xhr) {
var fr;
fr = new FileReader;
fr.onload = function() {
var img;
img = new Image;
img.onload = function() {
return alert(img.width);
};
return img.src = fr.result;
};
return fr.readAsDataURL(file);
});
The thing is that I have no idea how to assign the width to its parent .details element which set the preview width of the preview.
I try replacing the alert for this code but it doesn't do anything.
$(this).parent('.details').css('height',img.height);
I'm a bit lost in how to relate the value inside the onload function to applying it to its parent class.
With the latest version of dropzone you don't have to write this code yourself.
Simply read the file.width and file.height properties that are set on the file object when the thumbnail is generated.
The problem, why your CSS doesn't affect the element, is because you didn't specify the unit, px in this case. So your code can be:
myDropzone.on("thumbnail", function(file) {
$(this.element).parent('.details').css('height', file.height + 'px');
});