functions processing not the last statement of a variable? - javascript

i working on this code that the objective is to: check if is a PNG, check if is 256X256, and transform img to base64 to upload to the server.
so if i select a 256 x 256 img it's loads but,if i load another img that is not a 256 x 256 after selecting a 256 x 256 it's loads and i don't know why!
Video Showing
How can i resolve it?
function isFileImage(file) {
const acceptedImageTypes = ['image/png'];
return file && acceptedImageTypes.includes(file['type'])
}
function importFileandPreview() {
var preview = document.querySelector('img');
var file = document.querySelector('input[type=file]').files[0];
var reader = new FileReader();
if (file) {
//read img
reader.readAsDataURL(file);
//verify type
var text = file.type;
if (text === "image/png") {
//load img
reader.addEventListener("load", function () {
//put img on <img> src
//console logs
//console.log(preview);
//console.log("pre_nat_height:"+preview.naturalHeight);
// console.log("pre_nat_width:"+preview.naturalWidth);
//technically check if img is 256 x 256
var old = preview.src;
preview.src = reader.result;
if(preview.naturalHeight === 256 && preview.naturalWidth === 256){
//create a hidden input (works but value is not from last img)
var element = document.getElementById("imga");
if(typeof(element) != 'undefined' && element != null){
document.getElementById("imga").remove();
}
input = document.createElement('input');
input.setAttribute("type","hidden");
input.setAttribute("id","imga");
input.setAttribute("name","img")
input.setAttribute("value",preview.src);
document.getElementById('count').appendChild(input);
delete preview;
}
//else if img is not 256 x 256
else {
preview.src = old;
alert("Must be a PNG and have 256px X 256px!");
delete preview;
}
}, false);// i don't know why false but ye
}
}
}
<input type="file" id="file" accept="image/PNG" onchange="importFileandPreview()"><br>
<img src=" data:image/png;base64,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" height="256" width="256">
<form id="count">
</form>

tl;dr: You need to perform the check against the natural dimensions of the image inside the handler for the preview's load event.
The problem you're facing is a consequence of bad timing rather than poor logic. More specifically, it lies in that you set the new src of your preview and then check against the loaded image's natural dimensions synchronously.
This approach is wrong because an image loads asynchronously and, therefore, your code doesn't wait for it to load before proceeding with your check. As a result, when, after selecting a valid image, you select an invalid one, you're still checking against the dimensions of the former as the latter hasn't yet loaded.
To correct this error, you have to perform your check inside the handler for the preview's load event, just as shown below.
Working Snippet:
(I've rewritten the function to make it easier to read)
function isFileImage (file) {
const acceptedImageTypes = ["image/png"];
return file && acceptedImageTypes.includes(file["type"])
}
function importFileandPreview () {
var preview = document.querySelector("img");
var file = document.querySelector("input[type=file]").files[0];
var reader = new FileReader();
/* Terminate the function prematurely if the file isn't an image. */
if (!isFileImage(file)) return;
/* Load the file into the reader. */
reader.readAsDataURL(file);
/* Set the 'load' event of the reader. */
reader.addEventListener("load", function () {
/* Create a temporary image to use for the check to avoid flashing. */
var tempPreview = new Image();
/* Set the 'load' event of the temporary preview. */
tempPreview.addEventListener("load", function () {
/* Check whether the selected image isn't 256x256 pixels. */
if (this.naturalHeight != 256 || this.naturalWidth != 256) {
/* Alert the user. */
alert("Must be a PNG and have 256px X 256px!");
/* Restore the default src to the preview. */
preview.src = preview.dataset.defaultSrc;
/* Terminate the function prematurely. */
return;
}
/* Set the result of the reader as the source of the preview. */
preview.src = reader.result;
/* Save the image to the form. */
saveImageToInput(reader.result);
});
/* Set the result of the reader as the source of the image. */
tempPreview.src = reader.result;
});
/* Save the default image in a data-* attribute to use again if needed. */
preview.dataset.defaultSrc = preview.dataset.defaultSrc || preview.src;
}
function saveImageToInput (image) {
/* Find the hidden input. */
var input = document.getElementById("imga");
/* Check whether the input doesn't exist. */
if (!input) {
/* Create a new hidden input. */
input = document.createElement("input");
input.setAttribute("id", "imga");
input.setAttribute("name", "img");
input.setAttribute("type", "hidden");
/* Place the input in the form. */
document.getElementById("count").appendChild(input);
}
/* Save the image as the input's value. */
input.setAttribute("value", image);
}
<input type="file" id="file" accept="image/PNG" onchange="importFileandPreview()"><br>
<img src=" data:image/png;base64,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" height="256" width="256">
<form id="count">
</form>
Notes:
It's a good idea to use a temporary preview to check if the selected image fulfils your criteria because, if you load it in the visible preview and then alert the user, the loaded image will show.
delete preview: Don't do this. Variables in JavaScript aren't supposed to be deleted like this.
The third argument passed to addEventListener determines whether the event is caught in the bubbling or the capturing phase. By default, it's false, so you can omit it.

Related

Storing the canvas as a image with .png extension but in a variable

I have two Webpages, one in which a user draws on the canvas and can download it as an image, the second webpages the image can be uploaded to be further processed. is there a way to remove this downloading and again uploading and do the whole process in a single step?
The second page requires an image with an extension of PNG
I tried using canvas.toDataURL but its not working
Update
i have added the functionality of the second webpage to the first
can i directly save the canvas in the same format when an image is uploaded
this is the function to upload the file on the second webpage
function handleFileSelect(evt) {
const file = evt.target.files[0];
// do nothing if no file is selected
if (file == null) {
postData.data = '';
postData.type = '';
return;
}
// only allow images
if (!file.type.match('image.*')) {
alert('Unsupported Image File');
resetForm();
return;
}
const reader = new FileReader();
reader.onload = (event) => {
postData.data = event.target.result;
postData.type = file.type;
};
// Read in the image file as binary string.
reader.readAsBinaryString(file);
}
how can i convert the canvas in the result to "event.target.result"

How should I crop an image at client side using jcrop and upload it?

I am working on a component in which there is file-upload HTML control, upon selecting an image using the file-upload element, the image would be rendered on the HTML5 Canvas element.
Here is JSFiddle with sample code: https://jsfiddle.net/govi20/spmc7ymp/
id=target => selector for jcrop element
id=photograph => selector for fileupload element
id=preview => selector for canvas element
id=clear_selection => selector for a button which would clear the canvas
Third-party JS libraries used:
<script src="./js/jquery.min.js"></script>
<script src="./js/jquery.Jcrop.js"></script>
<script src="./js/jquery.color.js"></script>
Setting up the JCrop:
<script type="text/javascript">
jQuery(function($){
var api;
$('#target').Jcrop({
// start off with jcrop-light class
bgOpacity: 0.5,
keySupport: false,
bgColor: 'black',
minSize:[240,320],
maxSize:[480,640],
onChange : updatePreview,
onSelect : updatePreview,
height:160,
width:120,
addClass: 'jcrop-normal'
},function(){
api = this;
api.setSelect([0,0,240,320]);
api.setOptions({ bgFade: true });
api.ui.selection.addClass('jcrop-selection');
});
});
clear canvas event which will be triggered on clear button click event:
jQuery('#clear_selection').click(function(){
$('#target').Jcrop({
setSelect: [0,0,0,0],
});
});
code that renders image on HTML5 Canvas:
function readURL(input) {
if (input.files && input.files[0]) {
var reader = new FileReader();
reader.onload = function (e) {
$('#target').attr('src', e.target.result);
setProperties();
}
reader.readAsDataURL(input.files[0]);
}
}
function setProperties(){
$('#target').Jcrop({
setSelect: [0,0,240,320]
});
}
$("#photograph").change(function(){
readURL(this);
});
code to crop and render an image on the canvas:
var canvas = document.getElementById('preview'),
context = canvas.getContext('2d');
make_base();
function updatePreview(c) {
console.log("called");
if(parseInt(c.w) > 0) {
// Show image preview
var imageObj = $("#target")[0];
var canvas = $("#preview")[0];
var context = canvas.getContext("2d");
context.drawImage(imageObj, c.x, c.y, c.w, c.h, 0, 0, canvas.width, canvas.height);
}
};
function make_base() {
console.log("make_base called");
var base_image = new Image();
base_image.src = '';
base_image.onload = function () {
context.drawImage(base_image, 0, 0);
}
}
Here are a bunch of issues I am facing with the above setup:
updatePreview function is not getting called on selection, hence the canvas is not getting rendered.
crop selection box is not draggable (I am using bootstrap CSS, I suspect it is due to missing/mismatching dependency).
Canvas is HTML5 element, which means the end-user must have an HTML5 compatible browser, I am working on an app that has millions of users. Forcing users to use the latest browser is not a feasible option. What should be the fallback mechanism here?
Here's basic html 5 code:
https://jsfiddle.net/zm7e0jev/
This code crops the image, shows a preview and sets the value of an input element to the base64 encoded cropped image.
You can fetch the image file in php the following way:
//File destination
$destination = "/folder/cropped_image.png";
//Get convertable base64 image string
$image_base64 = $_POST["png"];
$image_base64 = str_replace("data:image/png;base64,", "", $image_base64);
$image_base64 = str_replace(" ", "+", $image_base64);
//Convert base64 string to image data
$image = base64_decode($image_base64);
//Save image to final destination
file_put_contents($destination, $image);
Submitting base64 image string as a post variable has it's server post size limits and base64 encoding makes the cropped image file size even bigger (~33%) then the raw data of the cropped image would be which makes the upload take even longer.
To set the post size limit: What is the size limit of a post request?
Keep in mind that an increased post size limit can be abused for a DoS attack as example.
Instead I suggest converting the base64 cropped image to a data blob and then add it to the form on submit as a file:
https://jsfiddle.net/g3ysk6sf/
Then you can fetch the image file in php the following way:
//File destination
$destination = "/folder/cropped_image.png";
//Get uploaded image file it's temporary name
$image_tmp_name = $_FILES["cropped_image"]["tmp_name"][0];
//Move temporary file to final destination
move_uploaded_file($image_tmp_name, $destination);
Update:
FormData() is only partially support in IE10 and not supported in older versions of IE
So I suggest sending the base64 string as a fallback, though this will cause problems with bigger images so it needs to check the filesize and show an error popup when the image is above a specific size.
I'll post an update with the fallback code below when I've got it working.
Update 2:
I added a fallback for IE10 and below:
https://jsfiddle.net/oupxo3pu/
The only limitation is the image size that can be submitted when using IE10 and below, in case the image size is too big the js code will throw an error. The maximum size to work for post values is different between each server, the js code has a variable to set the maximum size.
The php code below is adapted to work with above fallback:
//File destination
$destination = "/folder/cropped_image.png";
if($_POST["png"]) {//IE10 and below
//Get convertable base64 image string
$image_base64 = $_POST["png"];
$image_base64 = str_replace("data:image/png;base64,", "", $image_base64);
$image_base64 = str_replace(" ", "+", $image_base64);
//Convert base64 string to image data
$image = base64_decode($image_base64);
//Save image to final destination
file_put_contents($destination, $image);
} else if($_FILES["cropped_image"]) {//IE11+ and modern browsers
//Get uploaded image file it's temporary name
$image_tmp_name = $_FILES["cropped_image"]["tmp_name"][0];
//Move temporary file to final destination
move_uploaded_file($image_tmp_name, $destination);
}
There is no fallback code for the canvas element yet, I'm looking into it.
The post size limitation in the fallback for older browsers is one of the reasons I dropped support for older browsers myself.
Update 3:
The fallback I recommend for the canvas element in IE8:
http://flashcanvas.net/
It supports all the canvas functions the cropping code needs.
Keep in mind it requires flash. There is a canvas fallback (explorercanvas) that does not require flash but it does not support the function toDataURL() which we need to save our cropped image.
Seahorsepip's answer is fantastic. I made a lot of improvements on the non-fallback answer.
http://jsfiddle.net/w1Lh4w2t/
I would recommend not doing that strange hidden png thing, when an Image object works just as well (so long as we're not supporting fallbacks).
var jcrop_api;
var canvas;
var context;
var image;
var prefsize;
Though even then we are, you're better off getting that data out of the canvas at the end and putting it in that field only at the end.
function loadImage(input) {
if (input.files && input.files[0]) {
var reader = new FileReader();
reader.onload = function(e) {
image = new Image();
image.src = e.target.result;
validateImage();
}
reader.readAsDataURL(input.files[0]);
}
}
But, if you want more functions than just crop, if we attach the jcrop to an inserted canvas (which we destroy with the jcrop on refresh). We can easily do anything we can do with a canvas, then validateImage() again and have the updated image visible in place.
function validateImage() {
if (canvas != null) {
image = new Image();
image.src = canvas.toDataURL('image/png');
}
if (jcrop_api != null) {
jcrop_api.destroy();
}
$("#views").empty();
$("#views").append("<canvas id=\"canvas\">");
canvas = $("#canvas")[0];
context = canvas.getContext("2d");
canvas.width = image.width;
canvas.height = image.height;
context.drawImage(image, 0, 0);
$("#canvas").Jcrop({
onSelect: selectcanvas,
onRelease: clearcanvas,
boxWidth: crop_max_width,
boxHeight: crop_max_height
}, function() {
jcrop_api = this;
});
clearcanvas();
}
Then on submit we submit any pending operations, like applyCrop() or applyScale(), adding data into hidden fields for fallback stuff, if we have those things needed. We then have a system we can easily just modify the canvas, in any way, then when we submit the canvas data gets sent properly.
function applyCrop() {
canvas.width = prefsize.w;
canvas.height = prefsize.h;
context.drawImage(image, prefsize.x, prefsize.y, prefsize.w, prefsize.h, 0, 0, canvas.width, canvas.height);
validateImage();
}
The canvas is added to a div views.
<div id="views"></div>
To catch the attached file in PHP (drupal), I used something like:
function makeFileManaged() {
if (!isset($_FILES['croppedfile']))
return NULL;
$path = $_FILES['croppedfile']['tmp_name'];
if (!file_exists($path))
return NULL;
$result_filename = $_FILES['croppedfile']['name'];
$uri = file_unmanaged_move($path, 'private://' . $result_filename, FILE_EXISTS_RENAME);
if ($uri == FALSE)
return NULL;
$file = File::Create([
'uri' => $uri,
]);
$file->save();
return $file->id();
}

Browse Image and Insert into Iframe

I was wondering if this is possible.
I want to create a function to retrieve an image and insert into an iframe. The user must be able to choose a file (image/video) and it will be inserted into an iframe.
main.html
<input type="file" id="addImage"> I have used this for the user to choose a file.
<iframe class="frame" id="frame" src="insert.html"></iframe> And this for the iframe. The iframe src is another html document.
insert.html
<span id="edit"></span> is within the insert.html where the image needs to be inserted to.
I don't quite understand how javascript can be used to retrieve the image from the users selection and insert into the iframe.
Is this possible?
Yes, here is an example. The key is to hook onto the iframe and then use its contentWindow.
EDIT
Additionally, I don't know if you meant the browse for file or the drag'n'drop API so I implemented both.
Lots of help from these sources:
file-api : How to interact with the file-api
drag-drop events : Events to key off of when dragging and dropping
And here is a fiddle:
JSFiddle
CSS
*{
font-family: Arial;
}
.section{
width: 400px;
padding: 20px;
margin: auto;
}
#dragDiv{
background-color: #ffffcc;
}
#browseDiv{
background-color: #ccffcc;
}
#iframeDiv{
background-color: #ffcccc;
}
#dropTarget{
width: 300px;
height: 300px;
border-style: dashed;
border-width: 5px;
}
.dropEnabled{
border-color: #999999;
}
.dropEnabled:hover{
border-color: #ff9933;
}
.dropMe{
border-color: #99ff99;
}
JS
/**
* I set up the listeners for dragging and dropping as well
* as creating an iFrame for holding dragged in images
* #returns {undefined}
*/
function main() {
// The div that receives drops and the new iFrame
var targetDiv = document.getElementById("dropTarget"),
iframe = document.createElement("iframe");
// Set the iframe to a blank page
iframe.src = "about:blank";
// Append it to the target
document.getElementById("iframeTarget").appendChild(iframe);
// Drag over is when an object is hovering over the div
// e.preventDefault keeps the page from changing
targetDiv.addEventListener("dragover", function(e) {
e.preventDefault();
this.className = "dropMe";
}, false);
// Drag leave is when the object leaves the div but isn't dropped
targetDiv.addEventListener("dragleave", function(e) {
e.preventDefault();
this.className = "dropEnabled";
}, false);
// Drop is when the click is released
targetDiv.addEventListener("drop", function(e) {
e.preventDefault();
this.className = "dropEnabled";
loadFile(e.dataTransfer.files[0], iframe);
}, false);
document.getElementById("upload").addEventListener("click", function() {
var file = document.getElementById("browsedFile").files[0];
loadFile(file, iframe);
}, false);
}
/**
* Load a file and then put it on an ifrmae
* #param {Element} f The file that needs to get loaded
* #param {Element} destination The iframe that the file is appended to
* #returns {undefined}
*/
function loadFile(f, destination) {
// Make a file reader to interpret the file
var reader = new FileReader();
// When the reader is done reading,
// Make a new image tag and append it to the iFrame
reader.onload = function(event) {
var newImage = document.createElement("img");
newImage.src = event.target.result;
destination.contentWindow.document.getElementsByTagName("body")[0].appendChild(newImage);
};
// Tell the reader to start reading asynchrounously
reader.readAsDataURL(f);
}
// Run the main script
window.onload = main;
HTML
<!DOCTYPE html>
<html>
<head>
<title>I framed it</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width">
</head>
<body>
<div id="dragDiv" class="section">
<div>The div below receives dragged in files</div>
<div id="dropTarget" class="dropEnabled"></div>
</div>
<div id="browseDiv" class="section">
<div>I upload stuff the boring way</div>
<input type="file" id="browsedFile"><button id="upload">Upload</button>
</div>
<div id="iframeDiv" class="section">
<div>And below me, an iFrame gets created</div>
<div id="iframeTarget"></div>
</div>
</body>
</html>
And here is the result:
And the DOM:
EDIT
A comment was made about how to do this with videos as well. There are several ways to do it, but here is one way that I would do it using the HTML5 <vido> tag which you can find more information on here: HTML Videos.
One tricky thing that I'm sure is rather cludgy is how to say what kind of file you should be loading. I use a switch() on the file's type attribute which usually evaluates to something like: image/png or video/mp4 for MP4 videos. However, this ties you to a specific file format. A better way to do it would be to make a regular expression that figures out if it's just an image or a video and ignore the format since the process is rougly the same for all files of those types.
I added my own regular expression implementation. Probably, not the best, but it allows all appropriate image types to come through now.
Also, I tried using some sample videos from Apple which can be found here: Sample QuickTime Movies. However, those did not work for some reason. So after that, I just downloaded the sample videos that W3Schools uses in their tutorial. I'm telling you this so that in case you try it and it doesn't work, it might be the file itself and not your code.
Edited loadFile() Function
/**
* Load a file and then put it on an ifrmae
* #param {Element} f The file that needs to get loaded
* #param {Element} destination The iframe that the file is appended to
* #returns {undefined}
*/
function loadFile(f, destination) {
// Make a file reader to interpret the file
var reader = new FileReader(),
loaderFunc = null,
typeRegEx = /^(\w+)\//,
contentType = f.type.match(typeRegEx)[1];
// Figure out how to load the data
switch (contentType) {
case "video":
loaderFunc = function(event) {
var newVideo = document.createElement("video"),
newVideoSource = document.createElement("source");
newVideo.width = 300;
newVideo.height = 300;
newVideo.setAttribute("controls");
newVideoSource.src = event.target.result;
newVideoSource.type = f.type;
destination.contentWindow.document.getElementsByTagName("body")[0].appendChild(newVideo);
newVideo.appendChild(newVideoSource);
};
break;
case "image":
loaderFunc = function(event) {
var newImage = document.createElement("img");
newImage.src = event.target.result;
destination.contentWindow.document.getElementsByTagName("body")[0].appendChild(newImage);
};
break;
default:
console.log("Unknown file type");
return;
}
// We should have returned, but just make sure
if (loaderFunc) {
// When the reader is done reading,
// Make a new image tag and append it to the iFrame
reader.onload = loaderFunc;
// Tell the reader to start reading asynchrounously
reader.readAsDataURL(f);
}
}
You can manipulate directly an iframe from an other if they are from same domain.
See jQuery/JavaScript: accessing contents of an iframe
What you can do if this is not the case is :
Setting up a communication process between both pages (see How to communicate between iframe and the parent site?)
or
Uploading your file to a server, and refresh the "insert.html" page to display the uploaded image.

Javascript image onload not firing when loading from local file

I'm trying to give the user a preview of how an image will look when combined with another image before they upload the image (think gun shooting a bullet). I can get the image to load into an image element, but then the onload event doesn't fire (tested in chrome and firefox). I've tried using setTimeout as a dirty hack, but unfortunately bullet.image.height does not appear to be set within a relatively short space of time.
Here is an example of what I'm trying to do:
if (input.target.files && input.target.files[0]) {
var file = new FileReader();
file.onload = function (event) {
// this part works fine
var bullet = {};
bullet.id = 0;
bullet.image = new Image();
bullet.image.onload = function () {
// This never fires
bullet.offset_y = bullet.image.height / 2;
$('#modal-weapons-field-bullet').append('<option value="0">' + bullet.title + '</option>');
$('#modal-weapons-field-bullet').val(0);
};
bullet.src = event.target.result;
bullet.offset_x = 0;
bullet.title = input.target.files[0].name;
}
file.readAsDataURL(input.target.files[0]);
}
bullet.src should be bullet.image.src

how to validate image size and dimensions before saving image in database

I am using ASP.NET C# 4.0, my web form consist of input type file to upload images.
i need to validate the image on client side, before saving it to my SQL database
since i am using input type= file to upload images, i do not want to post back the page for validating the image size, dimensions.
Needs your assistance
Thanks
you can do something like this...
You can do this on browsers that support the new File API from the W3C, using the readAsDataURL function on the FileReader interface and assigning the data URL to the src of an img (after which you can read the height and width of the image). Currently Firefox 3.6 supports the File API, and I think Chrome and Safari either already do or are about to.
So your logic during the transitional phase would be something like this:
Detect whether the browser supports the File API (which is easy: if (typeof window.FileReader === 'function')).
If it does, great, read the data locally and insert it in an image to find the dimensions.
If not, upload the file to the server (probably submitting the form from an iframe to avoid leaving the page), and then poll the server asking how big the image is (or just asking for the uploaded image, if you prefer).
Edit I've been meaning to work up an example of the File API for some time; here's one:
<!DOCTYPE HTML>
<html>
<head>
<meta http-equiv="Content-type" content="text/html;charset=UTF-8">
<title>Show Image Dimensions Locally</title>
<style type='text/css'>
body {
font-family: sans-serif;
}
</style>
<script type='text/javascript'>
function loadImage() {
var input, file, fr, img;
if (typeof window.FileReader !== 'function') {
write("The file API isn't supported on this browser yet.");
return;
}
input = document.getElementById('imgfile');
if (!input) {
write("Um, couldn't find the imgfile element.");
}
else if (!input.files) {
write("This browser doesn't seem to support the `files` property of file inputs.");
}
else if (!input.files[0]) {
write("Please select a file before clicking 'Load'");
}
else {
file = input.files[0];
fr = new FileReader();
fr.onload = createImage;
fr.readAsDataURL(file);
}
function createImage() {
img = document.createElement('img');
img.onload = imageLoaded;
img.style.display = 'none'; // If you don't want it showing
img.src = fr.result;
document.body.appendChild(img);
}
function imageLoaded() {
write(img.width + "x" + img.height);
// This next bit removes the image, which is obviously optional -- perhaps you want
// to do something with it!
img.parentNode.removeChild(img);
img = undefined;
}
function write(msg) {
var p = document.createElement('p');
p.innerHTML = msg;
document.body.appendChild(p);
}
}
</script>
</head>
<body>
<form action='#' onsubmit="return false;">
<input type='file' id='imgfile'>
<input type='button' id='btnLoad' value='Load' onclick='loadImage();'>
</form>
</body>
</html>
Works great on Firefox 3.6. I avoided using any library there, so apologies for the attribute (DOM0) style event handlers and such.
function getImgSize(imgSrc) {
var newImg = new Image();
newImg.onload = function() {
var height = newImg.height;
var width = newImg.width;
alert ('The image size is '+width+'*'+height);
}
newImg.src = imgSrc; // this must be done AFTER setting onload
}

Categories

Resources