There are a number of images that I'm displaying on our website. In addition, we allow users to upload images or preview images from an external source URL. All images on the site are available via standard <img> tags, where the src is set to the relevant image URL.
When an image is clicked, I'd like to take the image and post it to an API, which will then process the image and return a result:
Base64 Encode:
function getBase64Image(img) {
var canvas = document.createElement("canvas");
canvas.width = img.width;
canvas.height = img.height;
var ctx = canvas.getContext("2d");
ctx.drawImage(img, 0, 0);
var dataURL = canvas.toDataURL("image/png");
return dataURL.replace(/^data:image\/(png|jpg|jpeg);base64,/, "");
}
AJAX
$("#img").click(function () {
var base64 = getBase64Image(document.getElementById("img"));
$.ajax({
url: post_url,
type: 'POST',
data: { "img_data": base64 },
dataType: 'jsonp',
processData: false,
contentType: false,
success: function () {
...
},
});
});
There are a couple of issues that I'm aware of and probably more. I'm not technically "uploading" an image, because most of the images are already being displayed on the page. I'm also encoding in Base64 to send to the server, but I really need the data decoded in UTF-8. I suppose that I can do that server-side, but would be nice to have it done here.
I think in this scenario you should have two flows: one to the image the user upload, and one to the image from external resource.
In the flow to the images from external resource: your system knows the external URL to the images, so you can pass the URL in the post request, then in the server you download the image and manipulate it as you want.
And the flow to the image selected by the user, you post the file to the server and manipulate it as you want.
Related
I am trying to send an image to a server for my chrome extension. I am using code from a previous discussion --> how to send image to server with http.post in javascript and store base64 in mongodb.
My problem is that the image is never actually uploaded to the page. For instance, I am trying to upload the image to this input on server that is not mine: image upload section. After the code runs the image section is not uploaded with an image, which is ultimate goal of my program.
This is what the terminal looks like after all the console.log()'s run: enter image description here
Does anyone know the reason behind this and how I could fix this? Simply put, I want the desired image to be uploaded to "Add Photos" sections.
If anyone has a better solution to how approach the entirety of the problem, please let me know!
var convertToBase64 = function(url, imagetype, callback){
var img = document.createElement('IMG'),
canvas = document.createElement('CANVAS'),
ctx = canvas.getContext('2d'),
data = '';
// Set the crossOrigin property of the image element to 'Anonymous',
// allowing us to load images from other domains so long as that domain
// has cross-origin headers properly set
img.crossOrigin = 'Anonymous'
// Because image loading is asynchronous, we define an event listening function that will be called when the image has been loaded
img.onload = function(){
console.log('hoiii');
// When the image is loaded, this function is called with the image object as its context or 'this' value
canvas.height = this.height;
canvas.width = this.width;
ctx.drawImage(this, 0, 0);
console.log(canvas);
console.log(ctx);
data = canvas.toDataURL(imagetype);
console.log(data);
callback(data);
};
// We set the source of the image tag to start loading its data. We define
// the event listener first, so that if the image has already been loaded
// on the page or is cached the event listener will still fire
img.src = url;
console.log(img);
};
// Here we define the function that will send the request to the server.
// It will accept the image name, and the base64 data as arguments
var sendBase64ToServer = function(name, base64){
var httpPost = new XMLHttpRequest(),
path = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACgAAAAoCAYAAACM/rhtAAAFmklEQVRYR+1YWUiVaxRdx1nLOh7NynMpDbOOA4Z5pdvgQNFDb3VJIknqoVIQExyTNBHRCppoEkW0yVKQsMT7IBZGEZoiRaSlpSYOWM6m5HhZW4x75db5f4en24aDcv7z/Xt9a++99v4+zdTU1BTmaa9fv8a1a9fw9OlTTE5OwtvbGwEBAVi6dCl27NiBdevWzdmDZj4A29racPLkSTx48ABDQ0Pw9fXFnj174O/vj9HRUTx8+BAvXrzA3r17ERsbCxsbG9VA5wywtbUV8fHxKCwsxMTEBHbt2oXTp09j+/bt30F8/foVO3fuRGVlJY4cOYKUlBSsWbNGFcg5ARwfH0dCQgLOnz8vzjZt2oTs7GxhcLa9ffsWHh4e8vXhw4eRm5u7+ABLSkoQFhYGhpiWnp4uof6RkdX379/D3t4eOTk52Lp1q2KQc2IwNDQUt2/flpxiEWRmZsLZ2fmHTo8fP466ujp8+fIFBw4cQHJy8uIBZM6Rvd7eXlhaWuLWrVsIDg7+qcNLly4hPz9fcnXDhg3yv1JTzWBISIg40Ol00Gg0wooxe/78uRQQjarGql+2bJmxZfJcFcBPnz7Bx8cH3d3dsphs7t+/36ijd+/e4ejRo7C2tpZNJSUlYdu2bUbXqQZYUFCAY8eOYWBgAHZ2dqJxDJkxa2hoQHh4OExNTTE2NiY5GBgYaGyZegYPHTqEu3fvSpjo4MmTJ4qcEGBUVJSIN7WRerh7925Fa1WF2MvLC2/evJEXnzlzRoRaibGC4+LihHl2nIyMjMUB6OLigubmZixZsgQvX76EwWBQgg81NTUi7Kx8ivzVq1f/1XF+9hJVDFLrWlpapNdWVFQoAscfPX78WNgmwOXLl4uGuru7K1qvCiClpa+vD6dOnUJqaqoiB/wRZSU6OhqDg4My2bATrVixQtF6VQApERTnvLw86QhKjbp54sQJjIyMyChWXl4OKysrRcsVA7x48SJu3LghIaZksDsotaSkZFy+fFkY5GTj5/e70qXKhZoD6YULF/Dx40eZWmJiYsCqNpZLk5MAuw9FndrJoUGn0y48QDogC+wmXV1dMDc3l4k5Pj4BBw+GYOXK/86p4uJHspnGxkZs3rwZ1dVVisGp6iRpaWm4f/++dANWIwfWadMISIo4da6srAzV1dUiyNwAWbtz544MChwqCgruLTxA5g3Zo/bR+vv78fnz5+8AV61aLeMWi4AzIiudWunk5CRdh+wRaGJiIqKiIhce4Llz5+R8wSqmQ7LX2dkpYV6/3g39/QPo6emRyiQoMse2RtaampoEkJubmwyrBoPx3v3PHSiq4sjISBQXF8uASmbYrvjhhGxubgGeCwmIz8gkpYjFROY4HHBjLKaKCmW9WzXAs2fPCoOUCTMzM3z79k3CTIBk0MrKWkJOVrVaLfR6vQDu6OjAhw8fZJ2rqytevapVFV7FRcJmf+XKFZSWloqDGZAM5ZYtf2BwcOj7IEAhnjleEiDX8rN27Vr5a2KiDqOiEDOXsrKyRJwp1Gx5HD6Zj3r9b9Dp7KWF8dBuYmIiAy0ZJSB+x5zloFtTM11kakwRQL6QRcDTG4EyZDSCMRjcodXawdPTU6qYIaXEsGAoR5ymbW1tERERgfT0NDXYpkVMzc0Cc+z69evS/Nvb22V0IoOjo2NwcHAQUBzHmJ8sIj5nwfCQxQHDwUG3uABn3l5fXy/jflVVFfbt+xOlpX/h5s2bwtiMkV3mKK88eKug169WDU41g7M9PHv2TAbP1tbpOxqG1sLCAhs3bpTLIx6MLC3N5wRsZpGqEM/2NDw8jLq6ejg7u6C2thZBQUEwNdVgfHwSZmYqy/UH25gXQL7z0aMS+Pn5gXcwQUHKTmpqKJ03wKKiIjg6OsqtFbVuoe0XwPky+ovBXwwaY+B/X8V/A+fXNLaIW65OAAAAAElFTkSuQmCC",
data = JSON.stringify({image: base64});
httpPost.onreadystatechange = function(err) {
if (httpPost.readyState == 4 && httpPost.status == 200){
console.log(httpPost.responseText);
} else {
console.log(err);
}
};
// Set the content type of the request to json since that's what's being sent
httpPost.open("POST", path, true);
httpPost.setRequestHeader('Content-Type', 'image/jpeg');
httpPost.send(data);
};
// This wrapper function will accept the name of the image, the url, and the
// image type and perform the request
var uploadImage = function(src, name, type){
convertToBase64(src, type, function(data){
sendBase64ToServer(name, data);
});
};
// Call the function with the provided values. The mime type could also be png
// or webp
uploadImage(result.products[pointer][3], 'cool.jpeg', 'image/jpeg');
I have the following javascript produce images from a canvas and upload them to a server.
var can = document.createElement('canvas');
can.width = 600;
can.height = 600;
var ctx = can.getContext('2d');
ctx.fillRect(0, 0, can.width, can.height);
ctx.fillText("Julia", can.width/2, can.height/2);
can.toBlob(uploadImage, "image/jpg", 0.9);
function uploadImage(jpeg) {
var data = new FormData();
data.append('image', jpeg, 'image.jpg');
...
}
Every so often, the result looks like the above, only partially drawn. Multiple canvases are processed and uploaded serially, only moving on in the completion of the ajax (in the ... part), so only one at a time.
Have you seen this happen? If so, where in this process should I debug further? Maybe a setting or something in the context object?
Edit
The upload is an ajax post with a promise resolved only on the success branch. It actually uses angular's $http service:
$http({method: 'POST', url: '...', data: data}).then(function(response) {
// callback that processes and uploads the next image
});
We were facing with similar except part with canvas. You can debug it simply.
Print given blob to page as img src to make sure that file was created properly. Print also blob size.
Open browser's developer tools -> Network -> Filter XHR and start uploading
Assign finished(status 200) ajax request and look at Request Headers -> Content-Length. If this number is equal to blob size on page, it was uploaded properly and find issue on server side. Else check ajax call.
Make sure that server has set max client request size appropriate to your usecase. For example nginx has default value 1M.
TIP: set Content-Type by blob.type in $http headers. Default value for POST is application/json.
try to rearrange your logic a little,, you are getting racing condition with uploading process and when the image is created, they have to be callback in callback sorta ..
// ...
ctx.fillText("Julia", can.width / 2, can.height / 2);
can.toBlob(function(blob) {
var newImg = document.createElement('img'),
url = URL.createObjectURL(blob);
newImg.onload = function() {
// no longer need to read the blob so it's revoked
URL.revokeObjectURL(url);
newImg.src = url;
// we have image out of canvas and now do the upload of newImg
// $http || $.ajax call goes here
};
});
of if you want to submit image data URL try something like,,
// ...
ctx.fillText("Julia", can.width / 2, can.height / 2);
can.toBlob(function(blob) {
var reader = new window.FileReader();
reader.readAsDataURL(blob);
reader.onloadend = function() {
base64data = reader.result;
// we have image in base64 and now do the upload of base64data
// $http || $.ajax call goes here
}
});
hth, k
I am using HTML2Canvas to get image of complete HTML page .I am trying to save that image in PPT on a button click.
i am able to save image in PPT.
But the saved image content is getting overlapped and the alert which i have used here is taking around 1 min to show .
when i did debug i got to know that problem is with HTML2Canvas.
i have used many third party charts in my page like Google charts.
can you please suggest me any alternative for HTML2Canvas as i saw there are few limitations in HTML2Canvas when we use cross-origin content.
$('#PPTExport').click(function(e) {
var canvas = document.getElementById('canvas');
var target = $('#loadImageHeader');
html2canvas(target, {
onrendered: function(canvas) {
var data1 = canvas.toDataURL("image/jpeg").replace("image/jpeg", "image/octet-stream");
alert(data1);
$.ajax({
url: "savechart",
data:{
image1:data1
},
type: 'POST',
success: function (data) {
if(data=="success")
{
$("#formid1" ).attr('action','savechartDownload');
$( "#formid1" ).submit();
}
}
});
}
});
});
I Have solution for this problem.
You can try this out..
html2canvas([document.body], {
useCORS: true,
proxy: "Server",
onrendered : function(canvas) {
var myImage = canvas.toDataURL("image/png");
window.open(myImage);
}
});
Server is server url of node.js or any language you can write.
Example Node.js : https://github.com/niklasvh/html2canvas-proxy-nodejs
read more here: Can't capture google map with html2canvas
and Here: Cross-origin image load denied by Cross-Origin Resource Sharing policy
I am working on a FineUploader implementation. Special request is to create thumbnails on the fly client-side and then upload those with the original image-upload.
I have an implementation that works on FF, but does not seem to work on iOs. It looks like so:
var uploader = new qq.FineUploaderBasic({
button: document.getElementById(buttonID),
request: {
endpoint: '/up/load/a/' + $('section#ajax-viewport').data('albumid')
},
callbacks: {
onSubmit: function(id, fileName) {
// getFile obtains the file being uploaded
file = this.getFile(id);
// create a thumbnail & upload it:
ThumbDown(file, id, 200, fileName);
},
}
})
This code calls a function:
function ThumbDown(file, id, dimension, fileName) {
var reader = new FileReader();
reader.onload = function(e) {
var img = document.createElement("img");
img.onload = function (ev) {
var thumbnailDimensions; // object holding width & height of thumbnail
var c=document.getElementById("canvas-for-thumbnails"); // must be a <canvas> element
var ctx=c.getContext("2d");
// set thumbnail dimensions of canvas:
thumbnailDimensions = calcThumbnailDimension (img.width, img.height, dimension )
c.width = thumbnailDimensions.width;
c.height = thumbnailDimensions.height;
var ctx = c.getContext("2d");
ctx.drawImage(img, 0, 0, c.width, c.height);
uploadThumbnail(c.toDataURL('image/jpeg'), //a base64 encoded representation of the image
id,
fileName); // we need filename to combine with mother-image on the server
};
img.src = e.target.result;
}
reader.readAsDataURL(file);
} // end function
Finally the Thumbnail is uploaded with a dumb ajax-call:
function uploadThumbnail (base64encodedString, id, fileName) {
$.post('/up/thumb',
{
img : base64encodedString,
id: id,
fileName: fileName
},
function(data) {});
}
My questions:
1) Currently I have two uploads: one for mother-image and another for thumbnail. I would like to combine this in one FineUploader call. However, I do not see a way to do this, due to the asynchronous nature of my thumbnail creation.
Am I missing something? Is this possible to reduce this to one FineUploader call?
2) This code uploads the thumbnails as a base64 encoded string. I would like to upload the thumbnail as an image (or as a blob ?). Perhaps by following this recipe of Jeremy Banks. Would that work with FineUploader?
3) Are there other options/methods of FineUploader that I have missed but I should be using?
Any help is, as always, greatly appreciated.
So, it is already trivial to upload the original image. Fine Uploader takes care of that for you. If I understand correctly, you want to also upload a scaled version of the image (which you have already generated). I suggest you take the image you have drawn onto the canvas and convert it to a Blob. Then, you can submit this Blob directly to Fine Uploader, where it will upload it for you.
For example, change the value of uploadThumbnail to this:
function uploadThumbnail(thumbnailDataUri, id, filename) {
var imageBlob = getImageBlob(thumbnailDataUri, "image/jpeg"),
blobData = {
name: filename,
blob: imageBlob
};
// This will instruct Fine Uploader to upload the scaled image
uploader.addBlobs(blobData);
}
function getImageBlob(dataUri, type) {
var binary = atob(dataUri.split(',')[1]),
array = [];
for(var i = 0; i < binary.length; i++) {
array.push(binary.charCodeAt(i));
}
return new Blob([new Uint8Array(array)], {type: type});
}
Note: the getImageBlob function was adapted from this Stack Overflow answer. If this works for you, be sure to upvote the answer I've linked to.
Server-side note
A Blob is pretty much a File without a name property. Your server-side code will handle the upload of a Blob pretty much the same way as it does a File or form submit containing a <input type="file"> form field. The only noticeable difference to your server will be the filename parameter value in the Content-Disposition header of the multipart boundary containing the file. To put it another way, your server may think the image is named "blob" or perhaps some other generic name, due to the way most browsers generate multipart encoded requests that contain Blob objects. Fine Uploader should be able to get around that by explicitly specifying a file name for the browser to include in blob's Content-Disposition header, but this ability does not have wide browser support. Fine Uploader gets around this limitation, to some degree, by including a "qqfilename" parameter with the request containing the actual name of the Blob.
Future native support for thumbnail generation & scaling
The plan is to add native support for thumbnail previews to Fine Uploader. This is covered in feature requests #868 and #896. There are other related feature requests open, such as image rotation and validation related to images. These features and other image-related features will likely be added to Fine Uploader in the very near future. Be sure to comment on the existing feature requests or add additional requests if you'd like.
As of version 4.4 of FineUploader, as Ray Nicholus pointed out would eventually happen, this functionality has been baked into their framework.
Here is an example of setting the upload sizes when creating a FineUploader instance:
var uploader = new qq.FineUploader({
...
scaling: {
sizes: [
{name: "small", maxSize: 100},
{name: "medium", maxSize: 300}
]
}
});
See their page on uploading scaled images.
I need to send a image/media through json, for that conversion needs to be done into text format. How can I achieve that through jQuery/ Javascript?
You can find your answer in this post get image data in 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,/, "");
}
You need to pass the img tag to this function.
For further details see Convert an image into binary data in javascript
A few times already I read that jQuery doesn't provide functionality to download binary data and have it pass on to JavaScript as a string. Then I ran into this question. That got me thinking and I wrote a wrapper around $.ajax() looking like this (yes, it's simplified to show the main bits):
ajaxWrapper = function(url, dataType, callback, headers) {
return $.ajax({
url: url,
dataType: dataType == "binary" ? "text" : dataType,
mimeType: dataType == "binary" ? "text/plain; charset=x-user-defined" : undefined,
headers: headers || {}
}).done(function(data, status, jqXHR) {
callback(data, status, jqXHR);
});
}
And then in case you are dealing with Unicode the callback contains this line:
data = btoa(unescape(encodeURIComponent(data)));
or otherwise simply
data = btoa(data);
In other words if you read through the documentation of $.ajax() you simply add a dataType "binary".
Note that I use jQuery 1.7.1, but I don't see why it shouldn't work in later versions, too.