Crop and upload image on client-side without server-side code involve - javascript

As title said. The requirement is to be able to crop an image before uploading the cropped image to the server. All the work should be done on the client-side.
I have heard of the method to crop the image on the server and save it altogether.
But as i use Parse.com service. There is no supported for image manipulation on the server-side so i need to process it locally and upload the finished image directly to Parse.com service.
Example code would be very helpful.
Thanks.

The solution i used:
First I use a 3rd party javascript library to select the crop area like jCrop.
Once i got the coordinates (x1,x2,y1,y2), i draw a copy of an image to a canvas.
var canvas = document.getElementById('drawcanvas');
var context = canvas.getContext('2d');
canvas.width = canvas.width; // clear canvas
var imageObj = new Image();
imageObj.onload = function() {
// draw cropped image
// ...
context.drawImage(imageObj, sourceX, sourceY, sourceWidth, sourceHeight, destX, destY, sourceWidth, sourceHeight);
var dataURL = canvas.toDataURL();
};
imageObj.src = // image url
After i drew the canvas, i converted the canvas to a DataURL which is in base64 format.
Once i've got the DataURL, i use this function i found from the internet where it converts the DataURL to raw binary data.
DataURLConverter: function(data) {
// convert base64 to raw binary data held in a string
// doesn't handle URLEncoded DataURIs
var byteString = atob(data.split(',')[1]);
// separate out the mime component
var mimeString = data.split(',')[0].split(':')[1].split(';')[0]
// write the bytes of the string to an ArrayBuffer
var ab = new ArrayBuffer(byteString.length);
var ia = new Uint8Array(ab);
for (var i = 0; i < byteString.length; i++) {
ia[i] = byteString.charCodeAt(i);
}
return ia;
}
When we got the binary data, we then upload this directly to Parse.com.
Upload to parse with 'ia' as a data
var serverUrl = 'https://api.parse.com/1/files/' + fileName;
$.ajax({
type: "POST",
beforeSend: function(request) {
request.setRequestHeader("X-Parse-Application-Id", "App id");
request.setRequestHeader("X-Parse-REST-API-Key", "API Key");
request.setRequestHeader("Content-Type", "File type");
},
url: serverUrl,
data: ia,
processData: false,
contentType: false,
success: function(data) {
},
error: function(data) {
}
});

OK, I finally made it!!! after searching for a whole day!! Even now parse propose server side cropping, it's still interesting to have client side resizing.
Check this:
HTML5 Pre-resize images before uploading
Justin Levene's correction works really good!
But to work with Parse.com, you need to use
new Parse.File(name, {base64: somebase64string});
These codes works for me (for exemple, I uploaded a 2M photo, the re-sized photo would be like 150k):
var dataurl = canvas.toDataURL("image/jpeg");
var name = "image.jpg";
var parseFile = new Parse.File(name, {base64: dataurl.substring(23)});
parseFile.save().then(function() { ....
the "23" is all the letters before the real base64 string.
the result of dataurl is "data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2......", we just need the part begin by "/9j/"
Good luck!

This might be an old post but if you found this answer (like me), you might want to know that Parse allows now to crop images server side.
For the latest code you should refer to their documentation: https://www.parse.com/docs/cloud_modules_guide#images
Parse Image Object (from Parse documentation):
var Image = require("parse-image");
Parse.Cloud.httpRequest({
url: object.get("profilePhoto").url(),
success: function(response) {
// The file contents are in response.buffer.
var image = new Image();
return image.setData(response.buffer, {
success: function() {
console.log("Image is " + image.width() + "x" + image.height() + ".");
},
error: function(error) {
// The image data was invalid.
}
})
},
error: function(error) {
// The networking request failed.
}
});
Crop Image (from Parse documentation):
// Crop the image to the rectangle from (10, 10) to (30, 20).
image.crop({
left: 10,
top: 10,
right: 30,
bottom: 20,
success: function(image) {
// The image was cropped.
},
error: function(error) {
// The image could not be cropped.
}
});
You can also scale, change image format, and create thumbnails.

Related

Get Malformed Image Data

When the browser realizes that an image is corrupt / not following .jpg, .png (etc..) format the browser displays this icon:
<img src="some_malformed_img.jpg" onerror="errorHandler()" id="Img1" />
In JavaScript how can I get the malformed image data? This is what I've tried:
function errorHandler() {
var c = document.createElement('canvas');
var img = document.getElementById('Img1');
c.height = someHeight //Let's assume I know the height
c.width = someWidth; //Let's assume I know the width
var ctx = c.getContext('2d');
ctx.drawImage(img, 0, 0, c.width, c.height);
var base64String = c.toDataURL(); //<---- This is empty :(
}
For this example, we are assuming the server actually sends the file and that it's just the browser that determines that the file is malformed.
If the browser determines the image is corrupt you will not be able to draw it to a canvas also the drawing and the saving step may not be lossless so you probably will not have the same data the server sent.
If you really want to get the image data just do an ajax request
function errorHandler() {
fetch(document.getElementById('Img1').src)
.then(function(response) {
if (!response.ok) {
throw new Error("HTTP error, status = " + response.status);
}
return response.arrayBuffer();
})
.then(function(image_data) {
// do something with the image data
});
}

Store image content not image path in mongodb

I have seen many questions and solutions for this now. I am new to Mongo DB and MEAN stack development. I want to know whether there is anyway to store image content itself rather than path of the image file in Mongo DB. All the solutions suggests to store image as buffer and then use it back in the source by converting buffer to base64. I did it but the resulting output get resolves to path to the image file rather than the image content. I am looking to save image itself in DB.
// saving image
var pic = {name : "profilePicture.png",
img : "images/default-profile-pic.png",
contentType : "image/png"
};
//schema
profilePic:{ name: String, img: Buffer, contentType: String }
//retrieving back
var base64 = "";
var bytes = new Uint8Array( profilePic.img.data );
var len = bytes.byteLength;
for (var i = 0; i < len; i++) {
base64 += String.fromCharCode( bytes[ i ] );
}
var proPic = "data:image/png;base64," + base64;
console.log(proPic);
//console output
data:image/png;base64,images/default-profile-pic.png
The output for proPic resolves to "data:image/png;base64,images/default-profile-pic.png"
few links that I referred before posting this
How to do Base64 encoding in node.js?
How to convert image into base64 string using javascript
The problem is simply, that you don't read and encode the picture. Instead you use the path as a string.
Serverside using Node
If you want to perform it on the serverside with an image on the filesystem you can use something along following:
var fs = require('fs');
// read and convert the file
var bitmap = fs.readFileSync("images/default-profile-pic.png");
var encImage = new Buffer(bitmap).toString('base64');
// saving image
var pic = {name : "profilePicture.png",
img : encImage,
contentType : "image/png"
};
....
Clientside
Again we need to load the image and encode it as base64. There is an answer about doing this on the client here.
using the first approach the result would be something like following:
function toDataUrl(url, callback, outputFormat){
var img = new Image();
img.crossOrigin = 'Anonymous';
img.onload = function(){
var canvas = document.createElement('CANVAS');
var ctx = canvas.getContext('2d');
var dataURL;
canvas.height = this.height;
canvas.width = this.width;
ctx.drawImage(this, 0, 0);
dataURL = canvas.toDataURL(outputFormat);
callback(dataURL);
canvas = null;
};
img.src = url;
}
toDataUrl("images/default-profile-pic.png", function(encImage){
// saving image
var pic = {name : "profilePicture.png",
img : encImage,
contentType : "image/png"
};
//Proceed in the callback or use a method to pull out the data
....
});
Below two links saved my time. If we use "ng-file-upload" our life becomes easy from there.
https://github.com/danialfarid/ng-file-upload#install
https://github.com/danialfarid/ng-file-upload
Below is what worked for me
//my html code
<div>
<button type="file" ngf-select="onFileSelect($file)" ng-model="file" name="file" ngf-pattern="'image/*'"
ngf-accept="'image/*'" ngf-max-size="15MB" class="btn btn-danger">
Edit Profile Picture</button>
</div>
//my js function
function onFileSelect(file){
//var image = document.getElementById('uploadPic').files;
image = file;
if (image.type !== 'image/png' && image.type !== 'image/jpeg') {
alert('Only PNG and JPEG are accepted.');
return;
}
$scope.uploadInProgress = true;
$scope.uploadProgress = 0;
var reader = new window.FileReader();
reader.readAsDataURL(image);
reader.onloadend = function() {
base64data = reader.result;
$scope.profile.profilePic = base64data;
ProfileService.updateProfile($scope.profile).then(function(response){
$rootScope.profile = response;
$scope.profilePicture = $rootScope.profile.profilePic;
});
}
}
// when reading from the server just put the profile.profilePic value to src
src="data:image/png;base64,{base64 string}"
// profile schema
var ProfileSchema = new mongoose.Schema({
userid:String,
//profilePic:{ name: String, img: Buffer, contentType: String },
profilePic:String
}
I wouldn't say this is the best solution but a good place to start.Also this limits you from uploading file size more than 16 MB in which case you can use"GridFs" in the above implementation initially the file is converted to "blob" and then I am converting it to "base64" format and adding that to my profile's string variable.
Hope this helps someone in saving their time.

Upload base64 image with Ajax

My client is offering the user to pick a picture, crop and resize it and then display it (in a <img> DOM element).
If the picture is fine, the user can upload it to the server so it can be saved.
I would like to do the upload thanks to an Ajax request.
I found tons of examples on the internet to upload the original image retrieved from the client PC. For instance:
$( '#my-form' )
.submit( function( e ) {
$.ajax( {
url: 'http://host.com/action/',
type: 'POST',
data: new FormData( this ),
processData: false,
contentType: false
} );
e.preventDefault();
} );
This works properly if I decide to upload the picture retrieved through the form input.
In my case I want to upload the modified picture (saved in a <img> element) instead of the original one.
This picture is stored as a base64 picture (For information: I used the croppie.js library to generate the image).
I don't know how to upload this picture with Ajax.
I tried to upload it as a regular parameter but on the server side the img is an empty string:
var url = 'http://host.com/action/';
var data = {};
data.img = $('img#generated-image').attr('src');
$.ajax({url: url, type: "POST", data: data})
.done(function(e){
// Do something
});
// RESULTS in a empty data.img on the server side.
My problem being the server having an empty string when retrieving the "img" parameter. I suspect the image is maybe too big to be passed to the server or some other issues that I don't understand... .
So I'm wondering what is the proper way to send a base64 image to the server using an Ajax request WITHOUT using a form.
Thanks for your help.
EDIT
Seems to be an xmlHTTP POST parameter size issue. I tried to reduce the number of characters of the string representation of the image and the server is now able to retrieve it.
EDIT2
post_max_size is set to 8M in the php.ini file wheras the picture size is only 24K. So the problem is not there.
I'm using PHP with the Symfony2 framework.
Maybe a limitation from Symfony2.
I finally decided to convert the base64 image to a Blob so it can be sent via an Ajax request with the formData object as follows.
It saves upload bandwidth (base64 takes 33% more bits than its binary equivalent) and I couldn't find the reason for no transmission of base64 parameter (due to size limitation somewhere for sure).
The base64ToBlob function is based on this answer to another question.
function base64ToBlob(base64, mime)
{
mime = mime || '';
var sliceSize = 1024;
var byteChars = window.atob(base64);
var byteArrays = [];
for (var offset = 0, len = byteChars.length; offset < len; offset += sliceSize) {
var slice = byteChars.slice(offset, offset + sliceSize);
var byteNumbers = new Array(slice.length);
for (var i = 0; i < slice.length; i++) {
byteNumbers[i] = slice.charCodeAt(i);
}
var byteArray = new Uint8Array(byteNumbers);
byteArrays.push(byteArray);
}
return new Blob(byteArrays, {type: mime});
}
My JS code:
var url = "url/action";
var image = $('#image-id').attr('src');
var base64ImageContent = image.replace(/^data:image\/(png|jpg);base64,/, "");
var blob = base64ToBlob(base64ImageContent, 'image/png');
var formData = new FormData();
formData.append('picture', blob);
$.ajax({
url: url,
type: "POST",
cache: false,
contentType: false,
processData: false,
data: formData})
.done(function(e){
alert('done!');
});
In Symfony2 I can retrieve the image thanks to:
$picture = $request->files->get('picture');
Nitseg's answer works nicely. Also, I wanted to add the following lines if you must use auth token in your ajax call. Again, take a look at Nitseg's answer for more details first.
var formData = new FormData();
var token = "<YOUR-TOKEN-HERE>";
formData.append("uploadfile", mediaBlob);
jQuery.ajax({
url: url,
type: "POST",
cache: false,
contentType: false,
processData: false,
data: formData,
beforeSend: function (xhr){
xhr.setRequestHeader("Authorization", "Bearer " + token);
}
})
.done((e) => {
// It is done.
})
.fail((e) => {
// Report that there is a problem!
});

Increase image DPI using Html2Canvas library

We are using Html2Canvas library to capture div element to an image. But captured image quality is not good. Please let us know how can we improve quality (DPI upto 300)
We have added below javascript code
$(‘#divId’).html2canvas({
onrendered: function (canvas) {
var imageData = { "imageData": canvas.toDataURL("image/png", 1.0) };
$('#ImageData').val(imageData);
var sourceUrl = configuration.baseURL + "/ScreenShot";
$.ajax({
type: "POST",
url: sourceUrl,
data: imageData,
success: function () {
},
error: function (a, errorStatus, errorThrown) {
alert(a, errorStatus, errorThrown);
}
});
}
});
C# code ::
public void ScreenShot(string imageData)
{
string trimmedData = imageData.Replace("data:image/png;base64,", string.Empty);
byte[] uploadedImage = Convert.FromBase64String(trimmedData);
byte[] tiffBytes;
using (MemoryStream inStream = new MemoryStream(uploadedImage))
using (MemoryStream outStream = new MemoryStream())
{
Bitmap.FromStream(inStream).Save(outStream, ImageFormat.Tiff);
tiffBytes = outStream.ToArray();
}
string fileName = Guid.NewGuid() + ".tiff";
string path = Server.MapPath(fileName);
System.IO.File.WriteAllBytes(path, tiffBytes);
}
Usually the screen resolution is near 100dpi, usualy a bit lower, so you cannot capture a higher resolution, because it's not available. The capture is a pixel by pixel capture of what's in the screen.
I don't know if yu can do so, but the only way to get a higher resolution is to cheat by zooming in in your browser, and capture the zoomed in div content. If you need 300 dpi you have to zoom at least x3.
The only other solution is to get the original capture, and use some library that can increase the resolution using interpolation, but you're not going to get a good quality.

Convert an img to file and back in Javascript

Imagine a web page has an img tag which needs to be uploaded. How do I convert this to a file object, so that I can send it over?
And on the other end, I have the hypothetical img, converted to file and sent to me. How do I convert this to a HTML tag?
I have an initial starting point for the latter part:
imageUrl = URL.createObjectURL(file);
image = document.createElement("img");
image.src = imageUrl;
If you alredy have your image loaded in html page, you can encode it to base64, then send it to your server by ajax call and save it
Javascript
function getBase64Image(img) {
// Create an empty canvas element
var canvas = document.createElement("canvas");
canvas.width = img.width;
canvas.height = img.height;
// Copy the image contents to the canvas
var ctx = canvas.getContext("2d");
ctx.drawImage(img, 0, 0);
// Get the data-URL formatted image
// Firefox supports PNG and JPEG. You could check img.src to
// guess the original format, but be aware the using "image/jpg"
// will re-encode the image.
var dataURL = canvas.toDataURL("image/png");
return dataURL.replace(/^data:image\/(png|jpg);base64,/, "");
}
$.ajax({
type: "POST",
url: "/yourPage.aspx/YourWebMethod",
data: "{yourParameterName:'" + JSON.stringify(getBase64Image(yourAlreadyLoadedImage)) + "'}",
contentType: "application/json; charset=utf-8",
dataType: "json",
async: false,
success: function (data) {
var result = data.d;
},
error: function () { alert('/yourPage.aspx/YourWebMethod'); }
});
Server side you can decode base64 image and save it, for example, in JPEG
C#
public void Base64ToImage(string coded)
{
System.Drawing.Image finalImage;
MemoryStream ms = new MemoryStream();
byte[] imageBytes = Convert.FromBase64String(coded);
using(var ms = new MemoryStream(imageBytes)) {
finalImage = System.Drawing.Image.FromStream(ms);
}
finalImage.Save(yourFilePath, ImageFormat.Jpeg);
}

Categories

Resources