Uploading Images via JQuery AJAX - javascript

I looked around and just couldn't find what I'm looking for without additional plugins/libraries. I want to upload an image and process it serverside via JQuery AJAX, but I can't figure out how to pass and process it. Any help is much appreciated!

Though Diodeus is correct, it isn't quite that difficult. Just maddening.
HTML5 does expose what is called the FileReader API, which is still relatively new and unsupported on legacy browsers, but which will make your job easier. I have a small app which accepts images on the client side and, using the FileReader API, converts them to base-64 for uploading to the server.
The following is the function I call upon a user's uploading an image. App.FileReader is an instantiation of the HTML5 FileReader, which is declared simply like:
App.FileReader = window.FileReader ? new FileReader : null;
Upon upload, I read the image as a dataURL using the FileReader, and push the data into an unused tag. The FileReader itself retains the read data, which is why it is a good idea to only instantiate one FileReader at a time.
if (input.files && input.files[0]) {
if (App.FileReader) {
App.FileReader.onload = function (e) {
$('#createMomentImagePreview').attr('src', e.target.result);
}
App.FileReader.readAsDataURL(input.files[0]);
$this.uploadedImage = true
}
else {
$('#createMomentImagePreview').attr('src', 'http://d33w6ffaa49e6z.cloudfront.net/media/ImageLoaded.png');
$this.uploadedImage = true
}
}
This is the AJAX call for uploading to the server, where data represents the read file, or "App.FileReader.result":
$.ajax({
url: '/image',
type: 'POST',
data: {
image: App.FileReader.result
}
}).done(function(data){
callback(data);
}).fail(function() {
console.log("Image upload failed!")
alert("Sorry, there was an error uploading your image to the database.")
})
Server-side (and I'm using Node with Express, so this might not apply), I can convert the base64 string to a Buffer (Blob) and send that up to S3 using Knox's putBuffer. This is waaaaaay simpler than actually authenticating with S3 AND trying to get it to play nice with your binary data.
if (req.body.image.match(/^data:image\/png;base64,/)) {
var image = new Buffer(req.body.image.replace(/^data:image\/png;base64,/,""), "base64");
}
else if (req.body.image.match(/^data:image\/jpeg;base64,/)) {
var image = new Buffer(req.body.image.replace(/^data:image\/jpeg;base64,/,""), "base64");
}
awsClient.putBuffer(image, '/' + imagePath + '.jpg', headers, function(err, stream) {
if (err) {
console.log(err);
return false
}
res.send(200, imagePath + '.jpg')
image = null;
});
In either case, once you have the base64 data on your server you've made significant progress. You could use ImageMagick to handle processing as well. For what it's worth, I hope this helps you out in some way!

Related

How to load an HTML5 Canvas with an image from an image-service?

My web app calls a Web API service, which returns an image. The service returns nothing but an image. Calling the service is little different because there is a function in the routing code that adds the required auth-code and such. Anyway, my point is, I don't have the full URL and even if I did, I wouldn't want to pass it into code in plain-text. So what I have is a response, and that response is an image.
getThumb(filename: string) {
return this.http.get('/Picture/' + filename).subscribe(response => {
return response;
});
}
What I need to do is draw that image on to a canvas. From what I've seen on the internet so far, it looks like I want to create an image element, then assign that element src a URL, then I can add it to the canvas. It's the src part that's perplexing me. All the samples I see are either loading the image from a local filesystem or predefined URL, or from a base64 string, etc. I can't figure out how to just load an image I have as a response from a service. I'm sure I'm overthinking it.
Does anyone have some sample code to illustrate this?
e.g Something like this:
var img = new Image(); // Create new img element
img.src = ... ; // Set source to image
You could convert the image to Base64. In my example, you request the image and convert it to a blob using response.blob(). Once it's a blob, use fileReader.readAsDataURL to get the Base64.
const fileReader = new FileReader();
fetch("image-resource").then((response) => {
if(response.ok) {
return response.blob();
}
}).then((blob) => {
fileReader.readAsDataURL(blob);
fileReader.onloadend = () => {
console.log(fileReader.result);
}
});
References:
readAsDataURL
Blob

Convert HEIC to JPG , using php or JS

Anyone tried to convert a heic to jpg?
I looked at the official repository, but I did'nt understand how it works.
All examples in the repository are working. But when I try to process my photo, made on the iphone, the script refuses to process it.
I've had some luck recently with the conversion using libheif. So I made this library which should greatly simplify the whole process
https://github.com/alexcorvi/heic2any
The only caveat is that the resulting PNG/JPG doesn't retain any of the meta-data that were in the original HEIC.
I managed to convert heic to jpg with the help of heic2any js library (https://github.com/alexcorvi/heic2any/blob/master/docs/getting-started.md)
I converted the picture on client side, then gave it to the input in client side.
Server is seeing it as it was originally uploaded as jpg.
function convertHeicToJpg(input)
{
var fileName = $(input).val();
var fileNameExt = fileName.substr(fileName.lastIndexOf('.') + 1);
if(fileNameExt == "heic") {
var blob = $(input)[0].files[0]; //ev.target.files[0];
heic2any({
blob: blob,
toType: "image/jpg",
})
.then(function (resultBlob) {
var url = URL.createObjectURL(resultBlob);
$(input).parent().find(".upload-file").css("background-image", "url("+url+")"); //previewing the uploaded picture
//adding converted picture to the original <input type="file">
let fileInputElement = $(input)[0];
let container = new DataTransfer();
let file = new File([resultBlob], "heic"+".jpg",{type:"image/jpeg", lastModified:new Date().getTime()});
container.items.add(file);
fileInputElement.files = container.files;
console.log("added");
})
.catch(function (x) {
console.log(x.code);
console.log(x.message);
});
}
}
$("#input").change(function() {
convertHeicToJpg(this);
});
What I am doing is converting the heic picture to jpg, then previewing it.
After that I add it to the original input. Server side will consider it as an uploaded jpg.
Some delay can appear while converting, therefore I placed a loader gif while uploading.

Append image file to form data - Cordova/Angular

I am using Anuglar, Ionic and Cordova in my current project, and I'm trying to POST FormData containing an image file to my server. Right now I'm using the cordova camera plugin to return a file path to the image on the device (ex: file://path/to/img). Once I have the file path I want to append the image file to a FormData object using the images file path. Here is my code right now.
var fd = new FormData();
fd.append('attachment', file);
fd.append('uuid', uuid);
fd.append('userRoleId', userRole);
The code above works when appending a file that is taken from an <input type='file'> but doesn't work when just given the file path on the device.
Basically the FormData is showing like this right now:
------WebKitFormBoundaryasdf
Content-Disposition: form-data; name="attachment";
file://path/to/img
and I want it to look like this
------WebKitFormBoundaryasdf
Content-Disposition: form-data; name="attachment"; filename="jesus-quintana.jpg"
Content-Type: image/jpeg
I found many different ways to upload the image using cordova FileTransfer and by converting the image to a base64 and then uploading it. But I couldn't find any simple ways of just grabbing the file by using the path and posting it within a form. I'm not very familiar with the File Api so any help would be appreciated
After some fiddling around I manage to figure out a pretty simple solution.
First I added the cordova file plugin then I use the code below
var fd = new FormData();
window.resolveLocalFileSystemURL(attachment.img, function(fileEntry) {
fileEntry.file(function(file) {
var reader = new FileReader();
reader.onloadend = function(e) {
var imgBlob = new Blob([ this.result ], { type: "image/jpeg" } );
fd.append('attachment', imgBlob);
fd.append('uuid', attachment.uuid);
fd.append('userRoleId', 12345);
console.log(fd);
//post form call here
};
reader.readAsArrayBuffer(file);
}, function(e){$scope.errorHandler(e)});
}, function(e){$scope.errorHandler(e)});
So I'm just creating a form and using FileReader to insert an ArrayBuffer to the Blob object and then append that to the form data. Hopefully this helps someone else looking for an easy way to do this.
You do need to send file content. With the HTML5 FileAPI you need to create a FileReader object.
Some time ago, I developed an application with cordova and I had to read some files, and I made a library called CoFS (first, by Cordova FileSystem, but it's working in some browsers).
It's on beta state, but I use it and works well. You can try to do some like this:
var errHandler = function (err) {
console.log("Error getting picture.", err);
};
var sendPicture = function (file) {
var fs = new CoFS();
fs.readFile(file, function (err, data) {
if (err) {
return errHandler(err);
}
var fd = new FormData();
fd.append('attachment', new Blob(data));
fd.append('uuid', uuid);
fd.append('userRoleId', userRole);
console.log("Data of file:" + data.toString('base64'));
// Send fd...
});
};
navigator.camera.getPicture(sendPicture, errHandler);
Sorry my poor english.
Your post was extremly helpful to fix my problem. I'm using Ionic 4 and trying to upload an image using standard http and file client. The key code for reference is here:
return this.file.readAsArrayBuffer(path, file).
then(blob => {
const imgBlob = new Blob([blob], { type: 'image/jpeg' } );
formData.append('image[file]', imgBlob);
return this.http.post(url, formData, headers).subscribe();
});
Hope it helps someone out there as it did for me.

Image not showing using chrome filesystem toURL

I have the following code to write an image into the filesystem, and read it back for display. Prior to trying out the filesystem API, I loaded the whole base64 image into the src attribute and the image displayed fine. Problem is the images can be large so if you add a few 5MB images, you run out of memory. So I thought I'd just write them to the tmp storage and only pass the URL into the src attribute.
Trouble is, nothing gets displayed.
Initially I thought it might be something wrong with the URL, but then I went into the filesystem directory, found the image it was referring to and physically replaced it with the real binary image and renamed it to the same as the replaced image. This worked fine and the image is displayed correctly, so the URL looks good.
The only conclusion I can come to is that the writing of the image is somehow wrong - particularly the point where the blob is created. I've looked through the blob API and can't see anything that I may have missed, however I'm obviously doing something wrong because it seems to be working for everyone else.
As an aside, I also tried to store the image in IndexedDB and use the createObjectURL to display the image - again, although the URL looks correct, nothing is displayed on the screen. Hence the attempt at the filesystem API. The blob creation is identical in both cases, with the same data.
The source data is a base64 encoded string as I mentioned. Yes, I did also try to store the raw base64 data in the blob (with and without the prefix) and that didn't work either.
Other info - chrome version 28, on linux Ubuntu
//strip the base64 `enter code here`stuff ...
var regex = /^data.+;base64,/;
if (regex.test(imgobj)) { //its base64
imgobj = imgobj.replace(regex,"");
//imgobj = B64.decode(imgobj);
imgobj = window.atob(imgobj);
} else {
console.log("it's already :", typeof imgobj);
}
// store the object into the tmp space
window.requestFileSystem(window.TEMPORARY, 10*1024*1024, function(fs) {
// check if the file already exists
fs.root.getFile(imagename, {create: false}, function(fileEntry) {
console.log("File exists: ", fileEntry);
callback(fileEntry.toURL(), fileEntry.name);
//
}, function (e) { //file doesn't exist
fs.root.getFile(imagename, {create: true}, function (fe) {
console.log("file is: ", fe);
fe.createWriter(function(fw){
fw.onwriteend = function(e) {
console.log("write complete: ", e);
console.log("size of file: ", e.total)
callback(fe.toURL(), fe.name);
};
fw.onerror = function(e) {
console.log("Write failed: ", e.toString());
};
var data = new Blob([imgobj], {type: "image/png"});
fw.write(data);
}, fsErrorHandler);
}, fsErrorHandler);
});
// now create a file
}, fsErrorHandler);
Output from the callback is:
<img class="imgx" src="filesystem:file:///temporary/closed-padlock.png" width="270px" height="270px" id="img1" data-imgname="closed-padlock.png">
I'm at a bit of a standstill unless someone can provide some guidance...
UPDATE
I ran a test to encode and decode the base64 image with both the B64encoder/decoder and atob/btoa -
console.log(imgobj); // this is the original base64 file from the canvas.toDataURL function
/* B64 is broken*/
B64imgobjdecode = B64.decode(imgobj);
B64imgobjencode = B64.encode(B64imgobjdecode);
console.log(B64imgobjencode);
/* atob and btoa decodes and encodes correctly*/
atobimgobj = window.atob(imgobj);
btoaimgobj = window.btoa(atobimgobj);
console.log(btoaimgobj);
The results show that the btoa/atob functions work correctly but the B64 does not - probably because the original encoding didn't use the B64.encode function...
The resulting file in filesystem TEMPORARY, I ran through an online base64 encoder for comparison and the results are totally different. So the question is - while in the filesystem temp storage, is the image supposed to be an exact image, or is it padded with 'something' which only the filesystem API understands? Remember I put the original PNG in the file system directory and the image displayed correctly, which tends to indicate that the meta-data about the image (eg. the filename) is held elsewhere...
Can someone who has a working implementation of this confirm if the images are stored as images in the filesystem, or are padded with additional meta-data?
So to answer my own question - the core problem was in the base64 encoding/decoding - I've since then changed this to use things like ajax and responseTypes like arraybuffer and blob and things have started working.
To answer the last part of the question, this is what I've found - in the filesystem tmp storage, yes the file is supposed to be an exact binary copy - verified this in chrome and phonegap.

FileReader, crash in Chrome

I am trying to implement a file upload with dnd and FileReader for image preview.
It works quite good and also if i upload multiple files at ones.
But when i upload a second time images > ~1,6MB it crashes in chrome (firefox runs fine).
probably a bug in chrome but maybe anyone knows how to solve this?
Here an example:
http://jsfiddle.net/PTssx/7/
Instead of MBs large Data URIs, you could also make use of requestFileSystem, to virtually store a copy of the file on the client's computer (in a location directly accessible by JavaScript). You then only have a file path which references to the actual contents (so this isn't a path to the original location; it starts with filesystem:).
Then again this is not supported by all browsers, but since you're already using FileReader I don't think this is much of an issue.
I altered a previous answer of mine to make it fit in your code: http://jsfiddle.net/PTssx/10/.
var img = document.createElement('img');
window.requestFileSystem(window.TEMPORARY, 1024*1024, function(fs) {
fs.root.getFile('test.png', {create: true}, function(fileEntry) { // create file
fileEntry.createWriter(function(fileWriter) {
var builder = new BlobBuilder();
builder.append(reader.result); // set file contents
var blob = builder.getBlob();
fileWriter.onwriteend = function() {
img.src = fileEntry.toURL(); // set img src to the file
};
fileWriter.write(blob);
}, function() {});
}, function() {});
}, function() {});
$('#items').append(img);
You then have to read the file as an ArrayBuffer instead of a Data URI:
reader.readAsArrayBuffer(f);
reader.result will then be an ArrayBuffer.
Note: For now, in Chrome this technology has been implemented as webkitRequestfileSystem and WebKitBlobBuilder.
I would avoid FileReader and FileSystem if i where you.
You can preview the image with just img.src = URL.createObjectURL(File)

Categories