javascript resize image [reduce size] and upload - javascript

Is it possible to resize the image with javascript or Flash ?
My requirement:
A user uploading a image with 10MB in size,i want to re size the image on client side using Javascript or flash,after resizing the image,it need to be uploaded to the server.
If it is possible i can save the bandwidth.
I am using uploadify for upload images and Codeigniter on the Server Side.
is there any other methods to do this ?
Note : Reference to some Libraries are really helpful.
Thank you.

Yes, it is possible in Flash Player 10 and later.
This is an old blog post, from when Flash Player 10 and the FileReference.load() function was new, back in 2008, and it doesn't cover all steps needed, but it's a start:
http://www.mikechambers.com/blog/2008/08/20/reading-and-writing-local-files-in-flash-player-10/
You would probably also need to look into how to resize a bitmap in ActionScript, how to encode the bitmap as JPEG or PNG (using as3corelib) and how to upload the result to the server.
Edit: http://www.plupload.com seems to have support for resizing. There's also http://resize-before-upload.com/

Yes it's possible to resize an image in javascript using the HTML5 canvas API. You, however, will need to save it somewhere after being resized.
The first API you will need to check is drawImage.
The second one is toDataURL.
Depending on what you want to do, you can either:
Make the user save the smaller image using this client side script.
Store it yourself using a server-side language, to convert a Base64 Encoded Image to an actual image file, and save it on your server. Check out Example 1.
Example 1: PHP5 based solution:
<?php
define('UPLOAD_DIR', 'images/');
$img = $_POST['img'];
$img = str_replace('data:image/png;base64,', '', $img);
$img = str_replace(' ', '+', $img);
$data = base64_decode($img);
$file = UPLOAD_DIR . uniqid() . '.png';
$success = file_put_contents($file, $data);
print $success ? $file : 'Unable to save the file.';
?>
UPDATE #2:
As stated in the comments below, this method requires a modern browser that supports File APIs to work. Use the flash method instead to support both modern and non-html5 browsers.

If you using JSON to upload use the following code
function UploadPhoto(img) {
var uri = "http://domain/App/AppService.svc/GetImg/New";
var imgElem = document.getElementById(img);
var imgData = JSON.stringify(getBase64Image(imgElem));
alert(imgData);
$.ajax({
url: uri,
contentType: 'application/json',
dataType: 'json',
type: 'POST',
data: imgData,
error: function () {
alert('failed');
},
success: function () {
alert('Sucess');
}
});
}
function getBase64Image(imgElem) {
var width = 100;
var height = 150;
// imgElem must be on the same server otherwise a cross-origin error will be thrown "SECURITY_ERR: DOM Exception 18"
var canvas = document.createElement("canvas");
canvas.width = width;
canvas.height = height;
var ctx = canvas.getContext("2d");
ctx.drawImage(imgElem, 0, 0, width, height);
ctx.scale(width, height)
var dataURL = canvas.toDataURL("image/png");
return dataURL.replace(/^data:image\/(png|jpg);base64,/, "");
}

Related

ToDataURL (JavaScript) of Canvas is Creating a Corrupt PNG File After Upload to Server Thru PHP

I tried to give a working example of my code on JSFiddle, but I could only get the dataURL of the image to go into an input. (JS Fiddle: http://jsfiddle.net/dyt943s0/38/.) (EDIT: I was able to make a link that sends you to the DataURL image.)
Here is a copy of the corrupted image, (if you try opening in photoshop, it will not work, and gives the error: "Could not complete your request because the file-format module cannot parse the file"):
Or view http://mcgroup.freshfocuscrm.com/img/phot.png for a copy of the original photo.
Here is my JavaScript code (as it is on my actual web page):
var img=new Image();
img.crossOrigin='anonymous';
img.onload=start;
img.src="../../ffm.freshfocuscrm.com/Driving Log/tmp/background-lines.png";
function start(){
var bottleCanvas = document.getElementById('bottleCanvas');
// var designCanvas = $("#chartContainer .canvasjs-chart-canvas").get(0);
var ctxb=bottleCanvas.getContext('2d');
//var ctxd=editorCanvas.getContext('2d');
ctxb.drawImage(img,0,0);
//ctxd.fillRect(5,5,5,5);
downloadCanvas();
}
function downloadCanvas() {
var bottleCanvas = document.getElementById('bottleCanvas');
var designCanvas = $("#chartContainer .canvasjs-chart-canvas").get(0);
var bottleContext = bottleCanvas.getContext('2d');
bottleContext.drawImage(designCanvas, 0, 0);
var dataURL = bottleCanvas.toDataURL("image/png");
console.log(dataURL);
$(".dataurl").val(dataURL);
$(".submit-create-pdf").click();
}
Then my PHP Code to download the image onto my server:
$img = $_POST['dataurl_image'];
$img = str_replace('data:image/png;base64,', '', $img);
$img = str_replace(' ', '+', $img);
$fileData = base64_decode($img);
//saving
$fileName = 'photos.png';
file_put_contents(WEBSITE_URL.'/Driving Log/tmp/'.$fileName, $fileData);
However, I am almost sure that this is due to a PHP error, since if I put the DataURL code directly into my URL bar, and save the image manually, I can open it in PhotoShop. I just can't seem to figure out what that error is.
Some additional info:
The image seems to get created properly, for example, I can open it in Windows Photo Viewer and I can display it in an tag on my site.
If I open in MS Paint, and save the image, then the image becomes uncorrupted.
I have also tried using the following PHP code to create the image, which does not work either:
$image_url = $_POST['dataurl_image'];
$image = #file_get_contents($image_url);
$filename = 'uniqqid.png';
file_put_contents(WEBSITE_URL.'/Driving Log/tmp/'.$filename, $image);
The image was uncorrupted when I used the following JS code (instead of the one above):
var canvas = $("#chartContainer .canvasjs-chart-canvas").get(0);
var dataURL = canvas.toDataURL('image/png');
console.log(dataURL);
$("#btn-download").attr("href", dataURL);
$(".dataurl").val(dataURL);
Also, please note: I am trying all of this code on my Localhost Wamp Server, if that makes a difference?
Thank you!
This was caused by Google Chrome limiting the number of characters allowed inside of an input (type=text) tag. My DataURL code was close to 600,000 characters, but the input was cutting the code off at a number less than that, which caused my image to be corrupt.
To solve this, I went into my JS code and tried to shorten the DataURL code.
So, instead of:
var dataURL = bottleCanvas.toDataURL("image/png");
I used:
var dataURL = bottleCanvas.toDataURL("image/jpeg", 0.5);
And it shrunk the number of characters to less than 100,000.
This allowed the full DataURL code to get passed thru to my PHP server, which then allowed me to create an uncorrupted image.

Saving canvas with background image to server with html2canvas

I currently have a script that successfully creates an image from canvas including its containing Div background image by using html2canvas. I also have a script that can save the canvas as an image to the server using the canvas2image plugin but the background doesn't show up.
The problem I'm having is when I try to combine the two so that I can save the Div bg and canvas as an image to the server, nothing happens which I believe is due to the canvas2image plugin not firing.
The code I have with both plugins combined is here.
function exportAndSaveCanvas() {
html2canvas($("#containingDiv"), {
background:'#fff',
onrendered: function(canvas) {
// var imgData = canvas.toDataURL('image/jpeg'); <--This would create the image needed
//but I replaced with the line below to tie in the two plugins
var screenshot = Canvas2Image.saveAsPNG(canvas, true);
canvas.parentNode.appendChild(screenshot);
screenshot.id = "canvasimage";
data = $('#canvasimage').attr('src');
canvas.parentNode.removeChild(screenshot);
// Send the screenshot to PHP to save it on the server
var url = 'upload/export.php';
$.ajax({
type: "POST",
url: url,
dataType: 'text',
data: {
base64data : data
}
});
}
});
}
The code for export.php which upload the image to the server is here
<?php
$data = $_REQUEST['base64data'];
//echo $data;
$image = explode('base64,',$data);
file_put_contents('../uploadimg/myImage.jpg', base64_decode($image[1]));
?>
I was hoping to be able to combine the two plugins to work together and get my canvas with Div background save to the server but it looks like the canvas2image plugin doesn't fire.
Thanks!
Write the background image into the canvas before you write the other image. The MDN page about writing an image to a canvas should have you covered: https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API/Tutorial/Using_images
As an aside, I'm not sure why you're using a plugin to do anything you get for free with the native canvas API.
dtanders said "As an aside, I'm not sure why you're using a plugin to do anything you get for free with the native canvas API."
This got me thinking that I was making it more difficult than it needed to be so I stripped away some code. The script below does just what I need.
function exportAndSaveCanvas() {
html2canvas($("#containingDiv"), {
background:'#fff',
onrendered: function(canvas) {
var imgData = canvas.toDataURL('image/jpeg');
var url = 'upload/export.php';
$.ajax({
type: "POST",
url: url,
dataType: 'text',
data: {
base64data : imgData
}
});
}
}); //End html2canvas
} // End exportAndSaveCanvas()

Image Upload - Resize on Client Side piror to ajax call to php server

I have been doing research for quite a while already about this problem, and still haven't figure out the best way to resize the image prior to sending it to my Apache server via ajax.
I am trying to use the html5 canvas approach mentioned in this post
But I am having a hard time trying to work with the line:
var dataurl = canvas.toDataURL("image/png");
I would like to pass it to my server like a normal image file, so that in php i can call the follow code like $_FILES['file']['error']
to check the size, type, duplicate, etc... (just like how i would normally go about uploading the image)
Most importantly, I would like to use move_uploaded_file function in php to upload those image to server.
However, using the html5 canvas resize approach, I can no longer do so, since after decoding and trimming out the header part of the canvas.toDataURL, I am left with just a image itself to work with in my php code.
define('UPLOAD_DIR', 'uploads/');
$img = $_POST['image'];
$img = str_replace('data:image/jpeg;base64,', '', $img);
$img = str_replace(' ', '+', $img);
$data = base64_decode($img);
$file = UPLOAD_DIR . uniqid() . '.jpg';
$success = file_put_contents($file, $data);
print $success ? $file : 'Unable to save the file.';
Any other approach to achieve this action without the HTML5 canvas?
(Bottom line: I don't have any luck merging the traditional upload image with the new html5 canvas image resize technique)

Image corrupted when trying to push from fabric.js to php

I have a drawing app that I am building out using fabric.js and have a requirement to save the image server side. The code in place to do this is very simple, I have a form into which I push the canvas image using the following javascript:
jQuery(".send").click(function(){
canvas.deactivateAll();
if (!fabric.Canvas.supports('toDataURL')) {
alert('This browser doesn\'t provide means to serialize canvas to an image');
} else {
var imageUrl = canvas.toDataURL('image/png');
//Lets update our form and post
jQuery("#_image").val(imageUrl);
jQuery("#_imageForm").submit();
}
});
On the server side the code is then looking for the posted b64 data and pushing it to a file:
if (array_key_exists('_image', $_POST)) {
$source = $_POST['_image'];
$urlUploadImages = "/images/";
$nameImage = uniqid("image", true) . ".png";
$saveFile = $_SERVER['DOCUMENT_ROOT'] . $urlUploadImages . $nameImage;
$image = str_replace('data:image/png;base64,', '', $source);
$image = str_replace(' ', '+', $image);
file_put_contents($saveFile, base64_decode($image));
}
This mostly works. The png is created and has content but it is truncated about 2/3 of the way down. The image created is 512px x 512px but the lower 1/3 is just transparent.
Looking at the raw encoded data, I can see that the length appear different and that there is also what appear to be some binary in the content. Is there anything else I should do to protect the content when submitting in this way?

Image resizing client-side with JavaScript before upload to the server

I am looking for a way to resize an image client-side with JavaScript (really resize, not just change width and height).
I know it's possible to do it in Flash but I would like to avoid it if possible.
Is there any open source algorithm somewhere on the web?
Here's a gist which does this:
https://gist.github.com/dcollien/312bce1270a5f511bf4a
(an es6 version, and a .js version which can be included in a script tag)
You can use it as follows:
<input type="file" id="select">
<img id="preview">
<script>
document.getElementById('select').onchange = function(evt) {
ImageTools.resize(this.files[0], {
width: 320, // maximum width
height: 240 // maximum height
}, function(blob, didItResize) {
// didItResize will be true if it managed to resize it, otherwise false (and will return the original file as 'blob')
document.getElementById('preview').src = window.URL.createObjectURL(blob);
// you can also now upload this blob using an XHR.
});
};
</script>
It includes a bunch of support detection and polyfills to make sure it works on as many browsers as I could manage.
(it also ignores gif images - in case they're animated)
The answer to this is yes - in HTML 5 you can resize images client-side using the canvas element. You can also take the new data and send it to a server. See this tutorial:
http://hacks.mozilla.org/2011/01/how-to-develop-a-html5-image-uploader/
If you were resizing before uploading I just found out this http://www.plupload.com/
It does all the magic for you in any imaginable method.
Unfortunately HTML5 resize only is supported with Mozilla browser, but you can redirect other browsers to Flash and Silverlight.
I just tried it and it worked with my android!
I was using http://swfupload.org/ in flash, it does the job very well, but the resize size is very small. (cannot remember the limit) and does not go back to html4 when flash is not available.
http://nodeca.github.io/pica/demo/
In modern browser you can use canvas to load/save image data. But you should keep in mind several things if you resize image on the client:
You will have only 8bits per channel (jpeg can have better dynamic range, about 12 bits). If you don't upload professional photos, that should not be a problem.
Be careful about resize algorithm. The most of client side resizers use trivial math, and result is worse than it could be.
You may need to sharpen downscaled image.
If you wish do reuse metadata (exif and other) from original - don't forget to strip color profile info. Because it's applied when you load image to canvas.
Perhaps with the canvas tag (though it's not portable). There's a blog about how to rotate an image with canvas here, I suppose if you can rotate it, you can resize it. Maybe it can be a starting point.
See this library also.
You can use a javascript image processing framework for client-side image processing before uploading the image to the server.
Below I used MarvinJ to create a runnable code based on the example in the following page:
"Processing images in client-side before uploading it to a server"
Basically I use the method Marvin.scale(...) to resize the image. Then, I upload the image as a blob (using the method image.toBlob()). The server answers back providing a URL of the received image.
/***********************************************
* GLOBAL VARS
**********************************************/
var image = new MarvinImage();
/***********************************************
* FILE CHOOSER AND UPLOAD
**********************************************/
$('#fileUpload').change(function (event) {
form = new FormData();
form.append('name', event.target.files[0].name);
reader = new FileReader();
reader.readAsDataURL(event.target.files[0]);
reader.onload = function(){
image.load(reader.result, imageLoaded);
};
});
function resizeAndSendToServer(){
$("#divServerResponse").html("uploading...");
$.ajax({
method: 'POST',
url: 'https://www.marvinj.org/backoffice/imageUpload.php',
data: form,
enctype: 'multipart/form-data',
contentType: false,
processData: false,
success: function (resp) {
$("#divServerResponse").html("SERVER RESPONSE (NEW IMAGE):<br/><img src='"+resp+"' style='max-width:400px'></img>");
},
error: function (data) {
console.log("error:"+error);
console.log(data);
},
});
};
/***********************************************
* IMAGE MANIPULATION
**********************************************/
function imageLoaded(){
Marvin.scale(image.clone(), image, 120);
form.append("blob", image.toBlob());
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://www.marvinj.org/releases/marvinj-0.8.js"></script>
<form id="form" action='/backoffice/imageUpload.php' style='margin:auto;' method='post' enctype='multipart/form-data'>
<input type='file' id='fileUpload' class='upload' name='userfile'/>
</form><br/>
<button type="button" onclick="resizeAndSendToServer()">Resize and Send to Server</button><br/><br/>
<div id="divServerResponse">
</div>
In my experience, this example has been the best solution for uploading a resized picture: https://zocada.com/compress-resize-images-javascript-browser/
It uses the HTML5 Canvas feature.
The code is as 'simple' as this:
compress(e) {
const fileName = e.target.files[0].name;
const reader = new FileReader();
reader.readAsDataURL(e.target.files[0]);
reader.onload = event => {
const img = new Image();
img.src = event.target.result;
img.onload = () => {
const elem = document.createElement('canvas');
const width = Math.min(800, img.width);
const scaleFactor = width / img.width;
elem.width = width;
elem.height = img.height * scaleFactor;
const ctx = elem.getContext('2d');
// img.width and img.height will contain the original dimensions
ctx.drawImage(img, 0, 0, width, img.height * scaleFactor);
ctx.canvas.toBlob((blob) => {
const file = new File([blob], fileName, {
type: 'image/jpeg',
lastModified: Date.now()
});
}, 'image/jpeg', 1);
},
reader.onerror = error => console.log(error);
};
}
There are two downsides with this solution.
The first one is related with the image rotation, due to ignoring EXIF data. I couldn't tackle this issue, and wasn't so important in my use case, but will be glad to hear any feedback.
The second downside is the lack of support foe IE/Edge (not the Chrome based version though), and I won't put any time on that.
Yes, with modern browsers this is totally doable. Even doable to the point of uploading the file specifically as a binary file having done any number of canvas alterations.
http://jsfiddle.net/bo40drmv/
(this answer is a improvement of the accepted answer here)
Keeping in mind to catch process the result submission in the PHP with something akin to:
//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);
If one worries about Vitaly's point, you can try some of the cropping and resizing on the working jfiddle.

Categories