Javascript: Simulate cropping and get file image fro memory - javascript

I upload an image using a file input:
<input type="file" id="product_images-0"/>
Then I get the file with javascript:
var element = document.getElementById('product_images-1');
console.log(element.files[0]);
I want to get the image file from memory, show it to user, simulate an image crop to get the coordinates and show the "cropped-simulated" image to the user, by using css transform/translate.
After cropping if the user doesn't like the image can remove it.
It is possible. I don't want to use Ajax because the user can remove an image before submits, and deleting this "remove" image from backend is hard to do it.

Please see simple proof-of-concept below. Once file is submitted you need to create new HTMLImageElement and append it to your preview. Then you can draw cropped image on canvas using drawImage.
Remember to validate if file you are submitting is image type!
var fileInput = document.getElementById('product_images-0');
var preview = document.querySelector('div.preview');
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
fileInput.onchange = function (event) {
var curFiles = fileInput.files;
if (curFiles.length > 0) {
while (preview.firstChild) {
preview.removeChild(preview.firstChild);
}
var image = document.createElement('img');
image.src = window.URL.createObjectURL(curFiles[0]);
preview.appendChild(image);
image.onload = function () {
ctx.drawImage(image, 0.2 * image.width, 0.2 * image.height, 0.5 * image.width, 0.5 * image.height, 0, 0, canvas.width, canvas.height);
};
}
};
<input type="file" id="product_images-0"/>
<div class="preview">
<p>No files currently selected for upload</p>
</div>
<canvas id="canvas" width="200" height="200"></canvas>

Related

How do I resize temporary image files for increased performance?

I am building an Instagram app where you can upload images and add filters to them. When uploading an image, you get a preview of that selected image with the filters. On the desktop, the filter display works smoothly, but on an iPhone 6S, scrolling through the filters is laggy and slow. The filters are just css classes from CSSGram.
An image to visualize: https://1drv.ms/u/s!AuzQwOkGzbwfmZZbYMI6V-Kxk4Myig
I know how to resize the file before saving. When inspecting the filter images, the size isn't that large so I don't understand why it's so slow on an iPhone.
// the javascript file
var uploader = document.getElementById('image');
image.addEventListener("change", function(event){
// select all hidden elements and show them as soon as an image is selected
var elements = document.querySelector(".filters");
var imageWrapper = document.querySelector(".imageWrapper");
elements.style.display="block";
imageWrapper.style.display="block";
var image = document.getElementById('output');
var F_nofilter = document.querySelector(".F_nofilter");
var F_1977 = document.querySelector(".F_1977");
var F_aden = document.querySelector(".F_aden");
var img = event.target.files[0];
image.src = URL.createObjectURL(img);
F_nofilter.src=URL.createObjectURL(img);
F_1977.src=URL.createObjectURL(img);
})
// some of the html code as an example
<div class="formField">
<label for="image">Upload a picture</label>
<div class="uploadFileWrapper">
<input type="file" id="image" name="image"">
</div>
</div>
<div class="imageWrapper">
<figure>
<img id="output" class="uploadedImage" visibility="hidden"/>
</figure>
</div>
<div class="filters">
<label for="filters">Select a filter</label>
<div class="filterContainer">
<div class="caption">
<p>normal</p>
<div class="filterButtons">
<div class="nofilter">
<img class="filterOptions F_nofilter" visibility="hidden"/>
</div>
</div>
</div>
<div class="caption">
<p>_1977</p>
<div class="filterButtons">
<div class="_1977">
<img class="filterOptions F_1977" visibility="hidden"/>
</div>
</div>
</div>
I want better performance on mobile devices by resizing the filter images.
Even if the image appears small on the screen, the representation of it in the memory is still the same. I'm assuming that performing calculations for each filter for a single image is what is bogging it down.
If you are using an external library to which you send image to for adding filters, then you could use canvas to truly resize the image and and get an image object out of canvas to feed to your external filter adding function.
function generateSmallPreviewImage(image, saclingFactor) {
// Create an empty canvas and get its context
var canvas = document.createElement('canvas');
var context = canvas.getContext('2d');
// This sets the size of the canvas based on the image size and a scaling factor
// For example: scalingFactor = 0.5 will half the image size on canvas
canvas.width = image.width * saclingFactor;
canvas.height = image.height * saclingFactor;
// This sets the fill color as white
context.fillStyle = '#fff';
// This fills the bg with white color in case a png is uploaded with transparency
context.fillRect(0, 0, canvas.width, canvas.height);
// Draw image on the canvas. This also scales(resizes) it.
context.drawImage(image, 0, 0, image.width, image.height, 0, 0, canvas.width, canvas.height);
// Create an empty image object
var image = new Image();
// Set the image source as a base64 encoded image from canvas
image.src = canvas.toDataURL('image/jpeg');
// Return the image
return image;
}
Now call this function whenever an image is selected from the <input type="file"/> and call this function to get a resized image.
This is one way to call the function:
element_to_append_image_to.appendChild(generateSmallPreviewImage(image_element, 0.5));
Let me know if you need more clarification.

How to wait for the multiple images to load in the canvas and convert to base64?

I'm trying to get a base64 version of a canvas in HTML5.
Currently, the base64 image that I get from the canvas is blank.
I have found similar questions for example this one:
HTML Canvas image to Base64 problem
However, the issue that I have is that because I am adding 2 images in the canvas, I cannot use the example provided in those answers as most of them are using single image.
I understand that I have to wait until the canvas image is loaded properly before trying to get the base64 image. But I don't know how in my case.
This is my code:
var canvas = document.getElementById('myCanvas');
var context = canvas.getContext('2d');
context.canvas.width = 1000;
context.canvas.height = 1000;
var imageObj1 = new Image();
imageObj1.src = "http://www.offthegridnews.com/wp-content/uploads/2017/01/selfie-psuDOTedu.jpg";
imageObj1.onload = function() {
context.drawImage(imageObj1, 0, 180, canvas.width, canvas.height);
};
var imageObj2 = new Image();
imageObj2.src = "http://www.publicdomainpictures.net/pictures/150000/velka/banner-header-tapete-145002399028x.jpg"
imageObj2.onload = function() {
context.drawImage(imageObj2, 0, 0, canvas.width, 180);
};
// get png data url
//var pngUrl = canvas.toDataURL();
var pngUrl = canvas.toDataURL('image/png');
// get jpeg data url
var jpegUrl = canvas.toDataURL('image/jpeg');
$('#base').val(pngUrl);
<div class="contents" style="overflow-x:hidden; overflow-y:scroll;">
<div style="width:100%; height:90%;">
<canvas id="myCanvas" class="snap" style="width:100%; height:100%;" onclick="takephoto()"></canvas>
</div>
</div>
<p>
This is the base64 image
</p>
<textarea id="base">
</textarea>
and this is a working FIDDLE:
https://jsfiddle.net/3p3e6Ldu/1/
Can someone please advice on this issue?
Thanks in advance.
EDIT:
As suggested in the comments bellow, i tried to use a counter and when the counter reaches a specific number, I convert the canvas to base64.
Like so:https://jsfiddle.net/3p3e6Ldu/4/
In both your examples (the one from the question and the one from the comments), the order of commands does not really respect the async nature of the task at hand.
In your later example, you should put the if( count == 2 ) block inside the onload callbacks to make it work.
However, even then you will run into the next problem: You are loading the images from different domains. You can still draw them (either into the canvas or using an <img> tag), but you are not able to access their contents directly. Not even with the detour of using the <canvas> element.
I changed to code so it would work, if the images are hosted on the same domain. I also used a function to load the image and promises to handle the callbacks. The direct way of using callbacks and a counting variable, seem error-prone to me. If you check out the respective fiddle, you will notice the SecurityError shown. This is the result of the aforementioned problem with the Same-Origin-Policy I mentioned.
A previous question of mine in a similar direction was about how to detect, if I can still read the contents of a <canvas> after adding some images.
const canvas = document.getElementById('myCanvas');
const context = canvas.getContext('2d');
context.canvas.width = 1000;
context.canvas.height = 1000;
// function to retrieve an image
function loadImage(url) {
return new Promise((fulfill, reject) => {
let imageObj = new Image();
imageObj.onload = () => fulfill(imageObj);
imageObj.src = url;
});
}
// get images
Promise.all([
loadImage("http://www.offthegridnews.com/wp-content/uploads/2017/01/selfie-psuDOTedu.jpg"),
loadImage("http://www.publicdomainpictures.net/pictures/150000/velka/banner-header-tapete-145002399028x.jpg"),
])
.then((images) => {
// draw images to canvas
context.drawImage(images[0], 0, 180, canvas.width, canvas.height);
context.drawImage(images[1], 0, 0, canvas.width, 180);
// export to png/jpg
const pngUrl = canvas.toDataURL('image/png');
const jpegUrl = canvas.toDataURL('image/jpeg');
// show in textarea
$('#base').val(pngUrl);
})
.catch( (e) => alert(e) );

HTML Canvas Will Not Draw Image

Okay, I know that there are loads of subjects that look identical to this one on SO, but none of them have fixed my issue...
I'm trying to grab an image from a file input and throw it onto a canvas so that I can later turn it into a base-64 image... But I've hit a snag in the process that I was not expecting, in drawing the image to the canvas...
Taking the following HTML:
<input type="file" id="fileIn" onchange="preview()"><br>
<img id="filePreview"><br>
<canvas id="fileCanvas"></canvas>
And the following script:
var dataurl = '';
function preview(){
document.getElementById('filePreview').src = URL.createObjectURL(document.getElementById('fileIn').files[0]);
document.getElementById('filePreview').onload = showInCanvas;
cnv = document.getElementById('fileCanvas');
ctx = cnv.getContext('2d');
}
function showInCanvas(){
cnv.style.width = document.getElementById('filePreview').naturalWidth + 'px';
cnv.width = document.getElementById('filePreview').naturalWidth;
cnv.style.height = document.getElementById('filePreview').naturalHeight + 'px';
cnv.height = document.getElementById('filePreview').naturalHeight + 'px';
ctx.clearRect(0, 0, cnv.width, cnv.height);
ctx.drawImage(document.getElementById('filePreview'), 0, 0);
dataurl = cnv.toDataURL('image/png');
}
The problem I'm having is that the image simply refuses to draw onto the canvas. Even going into the console and drawing the image to the canvas manually, after the script has run, it still refuses to draw. Because of this, the image data simply runs through as data:,
It's an https site, if that affects anything.
For clarification, here's my question:
Why is the canvas refusing to render this image? How can I fix this issue?
If the intent is to convert the image to Data-URI ("base64"), the FileReader can be used - no need for canvas (which can also alter the image/final compression):
fileIn.onchange = function(e) {
var fr = new FileReader();
fr.onload = done.bind(fr);
fr.readAsDataURL(e.target.files[0]);
}
function done() {
var dataURI = filePreview.src = this.result;
alert(dataURI.substr(0, 35) + "...")
}
<input type="file" id="fileIn"><br>
<img id="filePreview"><br>
<canvas id="fileCanvas"></canvas>

html5-canvas: Conversion of Image file to DataURL throws Uncaught TypeError

I'm trying to get the Base64/Data URL of a chosen image file in Javascript. The user basically selects an image via the File Input control and the Data URL is generated. However, I get this error:
Uncaught TypeError: Failed to execute 'drawImage' on
'CanvasRenderingContext2D': The provided value is not of type
'(HTMLImageElement or HTMLVideoElement or HTMLCanvasElement or
ImageBitmap)'
HTML:
<body>
<form id="form1">
<div>
<input type="file" id="imageinput" onchange="testit(event)" />
<canvas width="300" height="300" id="mycanvas" style="display: none;"></canvas>
</div>
</form>
</body>
Javascript:
function testit(event) {
var myImage = URL.createObjectURL(event.target.files[0]);
var myCanvas = document.getElementById('mycanvas');
var ctx = myCanvas.getContext('2d');
ctx.drawImage(myImage, 0, 0);
var mydataURL = myCanvas.toDataURL('image/jpg');
alert(mydataURL);
}
Why isn't this code working, guys?
You can not draw an image from url directly to canvas. You have to create a image element/object to do that.
var myCanvas = document.getElementById('mycanvas');
var ctx = myCanvas.getContext('2d');
var img = new Image();
img.onload = function(){
ctx.drawImage(img, 0, 0);
alert(myCanvas.toDataURL('image/jpeg'));
};
img.src = URL.createObjectURL(event.target.files[0]);
Here we have created a image object and set the src to user selected image url. After the image is loaded we are adding it to the canvas.
EDIT:
Here we have one more problem. Whatever the image size is, you will always get 300x300 cropped dataurl of the image because of the static canvas width and height. So we can set the width and height to the canvas dynamically after the image loaded. We can use console.log() instead of alert() so that you can open and see the image from your console in your browser itself.
myCanvas.width = img.width;
myCanvas.height = img.height;
Here is the final code:
var myCanvas = document.getElementById('mycanvas');
var ctx = myCanvas.getContext('2d');
var img = new Image();
img.onload = function(){
myCanvas.width = img.width;
myCanvas.height = img.height;
ctx.drawImage(img, 0, 0);
console.log(myCanvas.toDataURL('image/jpeg'));
};
img.src = URL.createObjectURL(event.target.files[0]);
Here is the fiddle (i have made the canvas visible so that you can see the whole image and width and height change in canvas):
UPDATE:
As #Kaiido mentioned, It will produce PNG image since the 'image/jpg' is not the mimetype. 'image/jpeg' is the mimetype for both JPG and JPEG images.
Updated Fiddle:
http://jsfiddle.net/k7moorthi/r8soo95p/4/
You're trying to draw an object URL to the canvas. you need to create an image in memory first
http://jsfiddle.net/zmtu6t6c/4/
var myImageUrl = URL.createObjectURL(event.target.files[0]);
var myImage = new Image();
myImage.src = myImageUrl;
myImage.onload = function(){
... then do the canvas stuff
}

Save Canvas image on Ipad

The webpage is being run on Safari on an iPad.
I have a canvas with the id "canvas1div". I would like to be able to receive this canvas as an image either by email or directly into the photo library.
Via Photo Library
With regards to the photo library, I found this question
Save canvas image on local mobile storage for IOS/Android
This is the function that I would like to call to save the image
function saveimage() {
window.canvas2ImagePlugin.saveImageDataToLibrary(
document.getElementById('canvas1div')
);
}
I don't know how to manually add the plug in to javascript so any advice here would be greatly appreciated.
Email
Again I don't know how to convert the canvas to an image and email it.
Thank you for your help
Don't know if this helps you but here you can find download but email send from JavaScript with email cannot be done:
Example with download file below http://jsfiddle.net/oa2s5eu7/1/
Javscript:
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
ctx.fillStyle = "#FF0000";
ctx.fillRect(0,0,150,75);
// 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;
}
document.getElementById('mydownload').onclick= function(){
var image = convertCanvasToImage(document.getElementById("myCanvas"));
var anchor = document.createElement('a');
console.log(anchor);
anchor.setAttribute('href', image.src);
anchor.setAttribute('download', 'image.png');
anchor.click();
}
document.getElementById('sendEmail').onclick= function(){
var image = convertCanvasToImage(document.getElementById("myCanvas"));
window.open('mailto:test#example.com?subject=subject&body=you cann send only txt from javscript in email ', '_blank');
}
Html:
<canvas id="myCanvas" width="200" height="100" style="border:1px solid #c3c3c3;">
Your browser does not support the HTML5 canvas tag.
</canvas>
<button id='mydownload'>Download Image</button>
<button id='sendEmail'>Send Email</button>

Categories

Resources