How to make html div with text over image downloadable/savable for users? - javascript

I have a div that takes a user image and places user text over it. My goal is for the users to, after seeing the preview and customizing the image/text to their like, be able to download or save the image with the click of a button. Is this possible? Here's my code: (I'm new to html/css so please forgive ugly formatting/methods)
HTML:
<script `src="https://cdnjs.cloudflare.com/ajax/libs/html2canvas/0.4.1/html2canvas.min.js"></script>`
<p>DOM-rendered</p>
<p> </p>
<div id="imagewrap" class="wrap" style="border-style: solid;">
<img src="../images/environment.gif" id="img_prev" width="640" height="640" />
<h3 class="desc">Something Inspirational</h3>
</div>
<div id="canvasWrapper" class="outer">
<p>Canvas-rendered (try right-click, save image as!)</p>
<p>Or, <a id="downloadLink" download="cat.png">Click Here to Download!</a>
</div>
CSS:
.desc {
text-align: center;
}
.outer, .wrap, .html2canvas, .image_text {
display: inline-block;
vertical-align: top;
}
.wrap {
text-align: center;
}
#imagewrap {
background-color: white;
}
JavaScript:
window.onload = function() {
html2canvas(document.getElementById("imagewrap"), {
onrendered: function(canvas) {
canvas.className = "html2canvas";
document.getElementById("canvasWrapper").appendChild(canvas);
var image = canvas.toDataURL("image/png");
document.getElementById("downloadLink").href = image;
},
useCORS: true
});
}
function changePicture(image) {
var at = $(image).attr('at');
var newpath = '../images/' + at;
$("#img_prev").attr('src', newpath);
}
function readURL(input) {
if (input.files && input.files[0]) {
var reader = new FileReader();
reader.onload = function (e) {
$('#img_prev')
.attr('src', e.target.result)
.width(640)
.height(640);
};
reader.readAsDataURL(input.files[0]);
}
};
$(document).on("click", '.font-names li a', function() {
$("#imagewrap h3").css("font-family", $(this).parent().css("font-family"));
$("#new_tile_font_style").val($(this).parent().css("font-family"));
});
$(document).on("click", '.font-sizes li a', function() {
$("#imagewrap h3").css("font-size", $(this).parent().css("font-size"));
$("#new_tile_font_size").val($(this).parent().css("font-size") + "px");
});
$(document).on("click", '.font-colors li a', function() {
$("#imagewrap h3").css("color", $(this).parent().css("color"));
$("#new_tile_font_color").val($(this).parent().css("color"));
});
$("#new_tile_quote").on('keyup', function() {
var enteredText = $("#new_tile_quote").val().replace(/\n/g, "<br>");
$("#imagewrap h3").html(enteredText);
});

What you're trying to accomplish is entirely possible using just HTML, JS, and CSS, with no server-side code. Here is a simplified demo that uses the html2canvas library to render your entire DOM element to a canvas, where the user can then download it.
Be sure to click "Full page" on the demo so you can see the whole thing!
window.onload = function() {
html2canvas(document.getElementById("imagewrap"), {
onrendered: function(canvas) {
canvas.className = "html2canvas";
document.getElementById("canvasWrapper").appendChild(canvas);
var image = canvas.toDataURL("image/png");
document.getElementById("downloadLink").href = image;
},
useCORS: true
});
}
.desc {
text-align: center;
}
.outer, .wrap, .html2canvas, .image_text {
display: inline-block;
vertical-align: top;
}
.wrap {
text-align: center;
}
#imagewrap {
background-color: white;
}
#wow {
color: red;
display: block;
transform: translate(0px, -12px) rotate(-10deg);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/html2canvas/0.4.1/html2canvas.min.js"></script>
<div class="outer">
<p>DOM-rendered</p>
<p> </p>
<div id="imagewrap" class="wrap" style="border-style: solid;">
<img src="https://i.imgur.com/EFM76Qe.jpg?1" id="img_prev" width="170" />
<h3 class="desc">Something <br /><span style="color: blue;">Inspirational</span></h3>
<span id="wow">WOW!</span>
</div>
</div>
<div id="canvasWrapper" class="outer">
<p>Canvas-rendered (try right-click, save image as!)</p>
<p>Or, <a id="downloadLink" download="cat.png">Click Here to Download!</a>
</div>

Here's a quick demo that shows how to use JavaScript to convert your markup into a canvas, then render that into an image and replace it on the page.
document.getElementById('generate').onclick = generateImage;
function generateImage() {
var container = document.getElementById('image_text');
var imgPrev = document.getElementById('img_prev');
var desc = document.getElementById('desc');
var canvas = document.createElement('canvas');
var context = canvas.getContext('2d');
canvas.setAttribute('width', container.clientWidth);
canvas.setAttribute('height', container.clientHeight);
context.drawImage(imgPrev, 0, 0);
context.font = "bold 20px serif";
context.fillText(desc.innerHTML, 0, container.clientHeight-20);
context.strokeRect(0, 0, canvas.width, canvas.height);
var dataURL = canvas.toDataURL();
var imgFinal = new Image();
imgFinal.src = dataURL;
container.parentNode.insertBefore(imgFinal, container.nextSibling);
container.remove();
document.getElementById('generate').remove();
}
#image_text {
display: inline-block;
border: 1px solid #000;
}
<div id="image_text">
<div class="wrap">
<img src= "https://placekitten.com/g/200/300" id="img_prev" crossorigin="anonymous" />
<h3 id="desc" contenteditable>Something Inspirational</h3>
</div>
</div>
<button id="generate">Generate Image</button>
You can replace the image file with anything you like. I've added a crossorigin property to the img tag, and this is because canvases that use resources from other sites cannot be exported unless a crossorigin attribute is specified (if your scripts and images are on the same domain, this is unnecessary).
I've also made the h3 tag editable. You can click on the text and start typing to change what it says, then click "generate image" and save the rendered output.
This script is just a demonstration. It is not bulletproof, it is only a proof-of-concept that should help you understand the techniques being used and apply those techniques yourself.
The javascript creates a canvas element (detached from the DOM), and sizes it according to the container div in your markup. Then it inserts the image into the canvas (it inserts it at the top-left corner), loads the text from your h3 tag and puts it near the bottom-left of the canvas, and converts that canvas to a data-uri. Then it creates a new img element after the container and deletes the container and button.

Related

How to take a screenshot of HTML Node with clip-path CSS property? (html2canvas not working for this)

I'm using html2canvas library to take a screenshot of a HTML Node, but it simply doesnt recognize the clip-path property.
(i'm getting cross-origin issue trying to replicate the error here, so i made a jsfiddle)
https://jsfiddle.net/1Ly9wn6k/
<div id="root">
<div class="star-mask">
<div class="square"></div>
</div>
</div>
<button onclick="capture()">Capture</button>
.star-mask {
clip-path: path('m55,237 74-228 74,228L9,96h240');
}
.square {
background-color: red;
width: 200px;
height: 150px
}
function capture() {
let node = document.querySelector('.star-mask')
html2canvas(node)
.then(canvas => {
document.querySelector('#root').appendChild(canvas)
})
}
Every time i click on "Capture" the canvas screenshot completely ignores the clip-path of the star shape and display only the red square. I already tried html2image library and got the same issue.
There is some other solution that can solve this issue? Or is currently impossible to capture the clip-path property using JavaScript?
Using dom-to-image works for me
function capture() {
let node = document.querySelector('.star-mask')
domtoimage.toPng(node)
.then(dataUrl => {
var img = new Image();
img.src = dataUrl;
document.body.appendChild(img);
})
}
.star-mask {
clip-path: path('m55,237 74-228 74,228L9,96h240');
}
.square {
background-color: red;
width: 200px;
height: 150px
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/dom-to-image/2.6.0/dom-to-image.js"></script>
<div id="root">
<div class="star-mask">
<div class="square"></div>
</div>
</div>
<button onclick="capture()">Capture</button>
Check out html-to-image
var node = document.getElementById('my-node');
htmlToImage.toPng(node)
.then(function (dataUrl) {
var img = new Image();
img.src = dataUrl;
document.body.appendChild(img);
})
.catch(function (error) {
console.error('oops, something went wrong!', error);
});
(from https://www.npmjs.com/package/html-to-image).

How to add a close button to base64 image preview?

In a form I'd like to let users to upload multiple images, one by one, and also let them to remove each image by clicking on a x button:
Here is my javascript/jQuery which adds the Base64 image previews to the DOM:
function readURL(input) {
if (input.files && input.files[0]) {
var reader = new FileReader();
reader.onload = function (e) {
let image = new Image();
image.src = `${e.target.result}`;
image.className = "img-thumbnail add-image-thumb";
let closeBtn = `<button type="button" class="close" aria-label="Close">
<span aria-hidden="true">×</span> </button>`;
$('#images-to-upload').append(image);
$('#images-to-upload').append(closeBtn);
}
reader.readAsDataURL(input.files[0]);
}
}
$("#imgInp").change(function () {
readURL(this);
});
And the html part:
<div id="images-to-upload" class="mb-3"> </div>
<div class="input-group mb-3">
<div class="custom-file">
<input type="file" class="custom-file-input" id="imgInp" >
<label class="custom-file-label" for="image-input"></label>
</div>
</div>
<small class="form-text text-muted">Upload one or more images</small>
<br>
CSS:
.add-image-thumb{
max-height: 64px;
margin: 10px;
padding: 5px;
}
This works fine for one image, but for multiple images, all x go to the right side of the page.
The problem is how can I put the x button at the top left corner of each image.
I could not construct a div out of Base64 images, otherwise I could mangage to acheive that through CSS.
I could not construct a div out of Base64 images, otherwise I could mangage to acheive that through CSS.
Wrap a div around the image
let wrapper = $('<div class="image-wrapper" />');
$('#images-to-upload').append(wrapper)
$(wrapper).append(image);
$(wrapper).append(closeBtn);
Use the below CSS
.image-wrapper {
display: inline-block;
position: relative;
}
.image-wrapper button {
position: absolute;
top: 0;
right: 0;
}

How to fit image in canvas using cropperJS

I am new using cropperjs library. But I'm struggling on how can I configure it.
What I have
https://jsfiddle.net/kaeqxfjL/
What I need
I want to integrate a full image crop where you just need to drag the photo inside the canvas instead of having a square to crop the photo. I also need to make the width of the photo fit to the width of the canvas so you cannot drag it left/right; you could only drag it up/down.
var canvas = $("#canvas"),
context = canvas.get(0).getContext("2d"),
$result = $('#result');
$('#fileInput').on( 'change', function(){
if (this.files && this.files[0]) {
if ( this.files[0].type.match(/^image\//) ) {
var reader = new FileReader();
reader.onload = function(evt) {
var img = new Image();
img.onload = function() {
context.canvas.height = img.height;
context.canvas.width = img.width;
context.drawImage(img, 0, 0);
var cropper = canvas.cropper({
aspectRatio: 16 / 9,
dragMode: 'move'
});
$('#btnCrop').click(function() {
// Get a string base 64 data url
var croppedImageDataURL = canvas.cropper('getCroppedCanvas').toDataURL("image/png");
$result.append( $('<img>').attr('src', croppedImageDataURL) );
});
$('#btnRestore').click(function() {
canvas.cropper('reset');
$result.empty();
});
};
img.src = evt.target.result;
};
reader.readAsDataURL(this.files[0]);
}
else {
alert("Invalid file type! Please select an image file.");
}
}
else {
alert('No file(s) selected.');
}
});
/* Limit image width to avoid overflow the container */
img {
max-width: 100%; /* This rule is very important, please do not ignore this! */
}
#canvas {
height: 290px;
width: 650px;
background-color: #ffffff;
cursor: default;
border: 1px solid black;
}
<link href="https://cdnjs.cloudflare.com/ajax/libs/cropper/2.3.3/cropper.css" rel="stylesheet"/>
<p>
<!-- Below are a series of inputs which allow file selection and interaction with the cropper api -->
<input type="file" id="fileInput" accept="image/*" />
<input type="button" id="btnCrop" value="Crop" />
<input type="button" id="btnRestore" value="Restore" />
</p>
<div>
<canvas id="canvas">
Your browser does not support the HTML5 canvas element.
</canvas>
</div>
<div id="result"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/cropper/2.3.3/cropper.js"></script>
Set image width using class:
.img-container img {
width: 100%;
}
And set viewMode and aspectRatio as below.
var cropper = canvas.cropper({
aspectRatio: 16 / 9,
dragMode: 'move',
viewMode: 3,
aspectRatio: 1
});
var canvas = $("#canvas"),
context = canvas.get(0).getContext("2d"),
$result = $('#result');
$('#fileInput').on('change', function() {
if (this.files && this.files[0]) {
if (this.files[0].type.match(/^image\//)) {
var reader = new FileReader();
reader.onload = function(evt) {
var img = new Image();
img.onload = function() {
context.canvas.height = img.height;
context.canvas.width = img.width;
context.drawImage(img, 0, 0);
var cropper = canvas.cropper({
aspectRatio: 16 / 9,
dragMode: 'move',
viewMode: 3,
aspectRatio: 1
});
$('#btnCrop').click(function() {
// Get a string base 64 data url
var croppedImageDataURL = canvas.cropper('getCroppedCanvas').toDataURL("image/png");
$result.append($('<img>').attr('src', croppedImageDataURL));
});
$('#btnRestore').click(function() {
canvas.cropper('reset');
$result.empty();
});
};
img.src = evt.target.result;
};
reader.readAsDataURL(this.files[0]);
} else {
alert("Invalid file type! Please select an image file.");
}
} else {
alert('No file(s) selected.');
}
});
/* Limit image width to avoid overflow the container */
img {
max-width: 100%;
/* This rule is very important, please do not ignore this! */
}
#canvas {
height: 290px;
width: 650px;
background-color: #ffffff;
cursor: default;
border: 1px solid black;
}
.img-container img {
width: 100%;
}
<link href="https://cdnjs.cloudflare.com/ajax/libs/cropper/2.3.3/cropper.css" rel="stylesheet" />
<p>
<!-- Below are a series of inputs which allow file selection and interaction with the cropper api -->
<input type="file" id="fileInput" accept="image/*" />
<input type="button" id="btnCrop" value="Crop" />
<input type="button" id="btnRestore" value="Restore" />
</p>
<div>
<canvas id="canvas" class="img-container">
Your browser does not support the HTML5 canvas element.
</canvas>
</div>
<div id="result"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/cropper/2.3.3/cropper.js"></script>

upload with multiple image preview

I am using this source: http://opoloo.github.io/jquery_upload_preview/
until now, I can upload one image with preview.
<style type="text/css">
.image-preview {
width: 200px;
height: 200px;
position: relative;
overflow: hidden;
background-color: #000000;
color: #ecf0f1;
}
input[type="file"] {
line-height: 200px;
font-size: 200px;
position: absolute;
opacity: 0;
z-index: 10;
}
label {
position: absolute;
z-index: 5;
opacity: 0.7;
cursor: pointer;
background-color: #bdc3c7;
width: 200px;
height: 50px;
font-size: 20px;
line-height: 50px;
text-transform: uppercase;
top: 0;
left: 0;
right: 0;
bottom: 0;
margin: auto;
text-align: center;
}
</style>
<script type="text/javascript">
$(document).ready(function() {
$("image-preview").each(
function(){
$.uploadPreview({
input_field: $(this).find(".image-upload"),
preview_box: this,
label_field: $(this).find(".image-label")
});
}
);
});
</script>
<!--| catatan penting: yang penting action="" & input type="file" name="image" |-->
<form action="upload.php" method="POST" enctype="multipart/form-data">
<div class="image-preview">
<label for="image-upload" class="image-label">+ GAMBAR</label>
<input type="file" name="my_field[]" class="image-upload" />
</div>
<div class="image-preview">
<label for="image-upload" class="image-label">+ GAMBAR</label>
<input type="file" name="my_field[]" class="image-upload" />
</div>
<input type="submit"/>
</form>
then try to add more div class image preview, i want add another button with image preview. i don't want multiple upload with one button.
$(document).ready(function() {$.uploadPreview => use id, of course when change to class and add more div, when upload a button, another button will change. i am confused with the logic. Anyone can help? maybe using array but, i don't know how..
Since upload button is dependent on state of uploadPreview you need to initialize for each div separately to get separate upload buttons.
Change your html like this give each container a class say imgBox
<div class="imgBox">
<label for="image-upload" class="image-label">Choose File</label>
<input type="file" name="image" class="image-upload" />
</div>
.....
....
...
<div class="imgBox">
<label for="image-upload" class="image-label">Choose File</label>
<input type="file" name="image" class="image-upload" />
</div>
..
Now initialize each one using jquery each()
$(".imgBox").each(
function(){
$.uploadPreview({
input_field: $(this).find(".image-upload"),
preview_box: this,
label_field: $(this).find(".image-label")
});
});
I created a simple image uploading index.html file for image uploading and preview.
Needs j-query.No need of extra plugins.
If you have any questions ask me ;)
//to preview image you need only these lines of code
var imageId=idOfClicked;
var output = document.getElementById(imageId);
output.src = URL.createObjectURL(event.target.files[0]);
Check it here:
https://jsfiddle.net/chs3s0jk/6/
I have one better option for the file upload it's easy to use and you can try it.
window.onload = function(){
if(window.File && window.FileList && window.FileReader){
$(document).on("change",'.file', function(event) {
var files = event.target.files; //FileList object
var output = document.getElementById("upload-preview");
$("#upload-preview").html("");
if(files.length>5){
$(".file").after("<div class='alert alert-error'><span class='close'></span>Maximum 5 files can be uploaded.</div>");
$(this).val("");
return false;
}
else{
$(".file").next(".alert").remove();
}
for(var i = 0; i< files.length; i++)
{
var file = files[i];
//Only pics
// if(!file.type.match('image'))
if(file.type.match('image.*')){
if(this.files[0].size < 2097152){
// continue;
var picReader = new FileReader();
picReader.addEventListener("load",function(event){
var picFile = event.target;
var div = document.createElement("div");
div.className = "upload-preview-thumb";
div.style.backgroundImage = 'url('+picFile.result+')';
output.insertBefore(div,null);
});
//Read the image
$('#clear, #upload-preview').show();
picReader.readAsDataURL(file);
}else{
alert("Image Size is too big. Minimum size is 1MB.");
$(this).val("");
}
}else{
alert("You can only upload image file.");
$(this).val("");
}
}
});
$(".file2").change(function(event){
var err=0;
var input = $(event.currentTarget);
var ele = $(this);
var file = input[0].files[0];
var u = URL.createObjectURL(this.files[0]);
var w = ele.attr("data-width");
var h = ele.attr("data-height");
var img = new Image;
img.onload = function(){
if(w){
if(img.width!=w || img.height!=h){
ele.parent().find(".alert").remove();
ele.parent().find(".upload-preview").before("<div class='alert alert-error'>Please upload a image with specified dimensions.</div>");
ele.val("");
}
else{
ele.parent().find(".alert").remove();
}
}
};
img.src = u;
var nh;
if($(this).attr('data-preview')=='full')
nh = (h/w*150)
else
nh=150
var preview = ele.parent().find(".upload-preview");
var reader = new FileReader();
preview.show();
reader.onload = function(e){
image_base64 = e.target.result;
preview.html("<div class='upload-preview-thumb' style='height:"+nh+"px;background-image:url("+image_base64+")'/><div>");
};
reader.readAsDataURL(file);
});
}
else
{
console.log("Your browser does not support File API");
}
}
above code save as one js file like file-upload.js
then link it to your file where you want perview.
i.e.
<script src="js/file-upload.js" type="text/javascript"></script>
use this kind of example for the input type
<input type="file" class="file2" name="page-image" id="page-image"/>
that works on the class that name is "file2" that class you given to the input field that able to create preview.
full structure something like below.
HTML Code you can try
<input type="file" class="file2" name="page-image[]" id="page-image"/>
<div class="clearfix"></div>
<div class="upload-preview" style="display: block;">
<div class="upload-preview-thumb">
// perview genereate here
// you can display image also here if uploaded throw the php condition in edit image part
</div>
</div>
<input type="file" class="file2" name="page-image[]" id="page-image"/>
<div class="clearfix"></div>
<div class="upload-preview" style="display: block;">
<div class="upload-preview-thumb">
// perview genereate here
// you can display image also here if uploaded throw the php condition in edit image part
</div>
</div>
CSS
.upload-preview {
border: 1px dashed #ccc;
display: block;
float: left;
margin-top: 10px;
padding: 5px;
}
.upload-preview-thumb {
background-position: 50% 25%;
background-size: cover;
float: left;
margin: 5px;
position: relative;
width: 139px;
}
Hope this works and in future it's helpful for you.
Thanks.

How to put a default image in a img

I want to do is make a default image to the img tag if the user has not choose a profile picture on his account.
current output:http://jsfiddle.net/LvsYc/2973/
http://s38.photobucket.com/user/eloginko/media/profile_male_large_zpseedb2954.jpg.html
script:
function readURL(input) {
if (input.files && input.files[0]) {
var reader = new FileReader();
reader.onload = function (e) {
$('#blah').attr('src', e.target.result);
}
reader.readAsDataURL(input.files[0]);
}
}
$("#imgInp").change(function(){
readURL(this);
});
Here's a fiddle showing what was mentioned in the comments:
HTML
<form id="form1" runat="server">
<input type='file' id="imgInp" />
<div class="img">
<img id="blah" src="#" alt="your image" />
</div>
</form>
CSS
img {
width: 120px;
height: 120px;
}
img[src="#"] {
display: none;
}
.img {
background: url('http://i38.photobucket.com/albums/e149/eloginko/profile_male_large_zpseedb2954.jpg');
background-position: -20px -10px;
width: 120px;
height: 120px;
display: inline-block;
}
The javascript is the same.
I wrote a quick little script to somewhat handle this:
JSFiddle: http://jsfiddle.net/LvsYc/3102/
$(function () {
var loader = 'http://i38.photobucket.com/albums/e149/eloginko/profile_male_large_zpseedb2954.jpg';
$('img[data-src]:not([src])').each(function () {
var $img = $(this).attr('src', loader),
src = $img.data('src'),
$clone = $img.clone().attr('src', src);
$clone.on('load', function () {
$img.attr('src', src);
});
});
});
Basically, here's what happens:
On load, iterate through all image tags that have a data-src but no src set.
Clone the img tag and set its src to the data-src.
Once the cloned img has loaded, set the original img tag's src to the data-src.
There are tons of ways to handle this scenario, and I'm sure there are better ones out there than this, but this should do the trick.
Handle the onError event for the image to reassign its source using JavaScript:
function imgError(image) {
image.onerror = "";
image.src = "/images/noimage.gif";
return true;
}
<img src="image.png" onerror="imgError(this);"/>
Or without a JavaScript function:
<img src="image.png" onError="this.onerror=null;this.src='/images/noimage.gif';" />

Categories