I am making a phonegap app, in which the user submits a photo from his camera, i get it in a Base64 encoding form.
var posData=extImage1;
$.ajax({
type: 'POST',
data: posData,
timeout:50000,
url: 'http://192.168.137.1/bee/services/add_photo.php',
success: function(data){
alert(data);
addToList();
},
error: function(){
alert('Please check your internet connection');
}
});
server side the code is saved to the database, but when selected and used as div background; it won't work no matter what!
BG='url(' + "data:image/jpeg;base64," + item.car_intImage3+ ')';
$('#item').css('background',BG);
why this is happening ? my guess is that during posting the data it got scrambled somehow.
I tried to save the image on server using the code from this question, but it just gives a corrupted image.
Update:
Using this decoder i submitted the posted 64 code and it also gives corrupted image. i think that means that there is something wrong with my post method. any suggestions?
It would be a lot cleaner and easier if you use Dropzone.js
Take a look at Dropzone.js Implementation. It is quite easy
This is how you can instantiate it
var myDropzone = new Dropzone("div#myId", { url: "/file/post"});
You can also listen to a lot of events like Adding a file, Removing a file
For Ex:
Dropzone.options.myAwesomeDropzone = {
init: function() {
this.on("addedfile", function(file) { alert("Added file."); });
}
};
EDIT: The Above solutions will work if you are storing the image in your disk and just the image location in your database. In fact it would be a lot better if you do this way.
Now coming to your method of working with images, You would want to go through this link how-can-i-store-and-retrieve-images-from-a-mysql-database-using-php which has a straight forward answer
Also, Check the datatype that you are using, may be its truncating he encoded data that you are storing in the database and hence you might be getting corrupted images. Also check with the above method of storing the images in the database mentioned in the link.
Hope this solves your problem
Related
Sorry for the long question, but I wanted to express it as well as I could, and ask it in a way that is understood easily. I have a program that allows a user to crop an image using croppie.js in JavaScript, and send the image to a Hunchentoot server on the backend running a Lisp program. I am having an issue saving the Base64 image to a .png file once the user uploads it. Once the post request is sent to the server I am getting the Base64 image as a string, removing invalid characters from the Base64 request by creating a subsequence of the string without the heading sent by the post request and also substituting the "%" character for the "+" character to make the Base64 valid. Next I remove the substring +3D+3D at the end of my string, because the s-base64 library that I am using in Common Lisp complains +3D+3D is invalid padding, and I replace it with "==" which is considered valid padding. Next I create a byte array by using the s-base64 library to translate the Base64 string to a byte array, and store it in a variable. Then I loop through the byte array and write each byte to the output file. When that is finished I decided to print the end of the byte array to the console so that I could see if the output and ending padding is valid, which it appears to be. Here is that part of the code, with comments to make it clearer:
(define-easy-handler (handle-image :uri "/handle-image.html") ()
(let ((data-source (hunchentoot:raw-post-data :force-text t))) ;get Base64 string
(let ((new-string (subseq data-source 36))) ;create a subsequence of Base64 string
(let ((final-string (substitute #\+ #\% new-string))) ;substitute % for +
(let ((end (search "+3D+3D" final-string))) ;find the invalid padding
(setf final-string (concatenate 'string (subseq final-string 0 end) "==")) ;add valid padding
(let ((byte-array (with-input-from-string (in final-string) ;create byte array (or simple-vector) out of Base64 string
(decode-base64-bytes in))))
(with-open-file (out "path/path/path/path/profile-image.png" ;create output stream to store file
:direction :output
:if-exists :supersede
:element-type 'unsigned-byte)
(dotimes (i (length byte-array)) ;write each byte from the byte array to output stream
(write-byte (aref byte-array i) out)))) ;close stream
(format t "!!!!!!!!: ~a" (subseq final-string (- (length final-string) 30))))))) ;print ending to console to ensure proper padding
"Upload Successful") ;send response to client
And here is some of my JavaScript code:
$(document).ready(function(){
$image_crop = $('#image_demo').croppie({
enableExif: true,
viewport: {
width:200,
height:200,
type:'square' //circle
},
boundary:{
width:300,
height:300
}
});
As you can see, I first create the cropper. I allow the user to have a 200 x 200 square to crop, and the total size of the cropping space is 300 x 300. There are no issues with that part of the code:
$('#upload_image').on('change', function(){
var reader = new FileReader();
reader.onload = function (event) {
$image_crop.croppie('bind', {
url: event.target.result
}).then(function(){
console.log('jQuery bind complete');
});
}
Above I bind the image they've uploaded to the cropper (like if you upload a Facebook image), when they select a file. Again, no issues:
reader.readAsDataURL(this.files[0]);
$('#uploadImageModal').modal('show');
Above I read the file that they've selected and then the modal "pops up" as if you're cropping a Facebook or Instagram photo:
$('.crop_image').click(function(event){
$image_crop.croppie('result', {
type: 'canvas',
size: 'viewport'
}).then(function(response){
$.ajax({
url:"handle-image.html",
type: "POST",
data:{"image": response},
success:function(data){
$('#uploadImageModal').modal('hide');
$('#uploaded_image').html(data);
}
});
})
});
Above I upload the ajax request, and if the upload was successful they will get a message from the server that it was success, and I hide the modal for image cropping as well.
Now the issue is that the image is simply blank. I know that the Base64 is valid because I used a Base64 conversion tool to see if the string was valid. I also went back and did my research in regards to Bits, Bytes, Pixels, and dimensions of images to see how the computer interacts with them, so i'm not sure why my image is simply displaying blank. Here is a look at what the cropper looks like on my website:
The bind is working, and then I get the message that the upload was successful. BUT after writing the image and viewing it in the file system it is either a blank image, or will sometimes say that the image type is not supported.
The reason why I am tagging PHP in this post is because I am sure some people have had similar issues in PHP with uploading a cropped image via ajax, and some of those solutions might be applicable in this case, but obviously will require me translating the solution to the lisp syntax. My assumption is that something is wrong with my code when I translate the string to a byte array and write it to a file, but I thought it'd be good to post other sections of my code if I am overlooking something.
As Brad commented, you should first try to use binary uploads directly.
That aside: if you encounter a % in a base64-encoded string, it most likely means that the entire thing is additionally URL-encoded. A quick apropos search gave do-urlencode as a library to decode that. Replacing % with + makes valid base64, but the result does not necessarily represent valid jpg.
Also: use let* instead of nested let forms. Maybe use write-sequence instead of byte-wise output.
Thanks to the answer from #Brad and #Svante I was able to solve the problem. I decided to put the image that I want to upload within a form element, add the blob image from the canvas as FormData for the form, and then send the FormData via an ajax post request:
$('.crop_image').on('click mousedown touchstart', function(event){ //When the crop image button is pressed event.
$image_crop.croppie('result', { //Get the result of the cropper
size: 'viewport', //Set the size to the viewport size (180 x 120)
format: 'png', //.png format
type: 'blob'
}).then(function (blob){
$form = $('#uploadForm');
var fd = new FormData($form);
fd.append('upload_image', blob);
$.ajax({
url: "handle-image.html",
type: "POST",
data: fd,
processData: false,
contentType: false,
success: function (data){
$('#uploadImageModal').modal('hide');
$('#uploaded_image').html(data);
}
});
})
});
Here I just decided to change the croppie result from the type "canvas"to the type "form", and specify that it will be a .png file. From there I added the form data from my newly created form to the .ajax request and went from there. Thanks to #Brad and #Svante for the help here.
I'm have trouble solving an issue with an AJAX request I'm making (I'm new to AJAX by the way). I have an API set-up and I'd like to retrieve a png image using an Authorization header which uses a token that I supply (which is stored in local storage). So for example, if i were to access the image with the Auth header then I would do this...
$.ajaxSetup({headers: {"Authorization" : localStorage.token}});
I'm able to retrieve the image. I can see it in the "Network" tab in Chrome, but when I append it to my div using this below...
$.ajax({
//Use commas for several parameters
type: 'GET',
url: *url of image*,
contentType: 'image/png',
success: function (data) {
binary = data;
$("#image").attr("src", 'data:image/png;base64,'+ data);
}
...it comes out in this weird character format (as seen below):
div id="image" src="data:image/png;base64, PNG
IHDRww^ÀþIDATxÚìÝ|ÔWº?þ½¿ÿ½Ý.ÅâÉd2îdâ®BB ÁÝÝ
)îÞbÅÝ¥TÐzi)Ô ÞRÙn»rï]»+w·{þçùÌ<Ãd]ùýV¾çõz¿H&I°Ï÷ç<çï}OÊø;æO1ªzhÔÀdÆþKȤ!......."
etc
I'd like it to come back as an image or a b64 string which I can simply put into the src param. I've searched online everywhere and cannot seem to find an answer.
Any ideas? I appreciate your time greatly.
This is the response I receive
Your code is downloading the image, which is in binary format.
You need to encode the binary to base64 in order to display the image in base64. Use btoa as explained in this answer: https://stackoverflow.com/a/247261/2223027
It seems like you are getting image file in binary data format and not the base64 format as you are expecting to put in the img tag src attribute.
If you do have image url you can put it in the img src directly no need of ajax call.
Here my jquery code:
var image = document.getElementById("canvas").toDataURL("image/png");
$.ajax({
type: "POST",
url: "imageup.php",
data: {image:image, title:getTitle, infos:informations},
success: function (response) {
alert(response);
}
});
For small images this work perfectly, but when i use a larg image, i odn't get the full base64 code of the image itself !
I tried this solution here:
https://stackoverflow.com/a/5061163/7232957
I devided the base64 image into many part and add them into array, and then send it to server side ! but all time same thing ! not get the full image.
Any one have a trick in order to solve this annoying problem ?
Is there a way to send html5 canvas image as file to server side ?
I already configured my apache server:
post_max_size = 500 Mo
upload_max_filesize = 500 Mo
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.
I have a feeling security concerns may not allow this but is it possible to generate a file with JavaScript and allow the user to drag it to the desktop (or file system)?
The following code drags out a file from a server
files[0].addEventListener("dragstart",function(evt){
evt.dataTransfer.setData("DownloadURL", "application/octet-stream:Eadui2.ttf:http://thecssninja.come/demo/gmail_dragout/Eadui.ttf");
},false);
And with the below code I can generate a file and have it download but I can't set the file name or let the user select the location.
var uriContent = "data:application/octet-stream," + encodeURIComponent(JSON.stringify(map));
location.href = uriContent;
Ideally I'd like a magical combination of both.
following code is currently working in Chrome only:
// generate downloadable URL, file name here will not affect stored file
var url = URL.createObjectURL(new File([JSON.stringify(map)], 'file_name.txt'));
// note that any draggable element may be used instead of files[0]
// since JSON.stringify returns a string, we use 'text' type in setData
files[0].addEventListener("dragstart", function(evt) {
evt.dataTransfer.setData("DownloadURL", "text:file_name.txt:" + url);
}, false);
now, dragging our files[0] element from the browser to desktop or file system, will store there a text file called, file_name.txt.
Feel free to choose another file name :)
This is only possible for Chrome, and even in Chrome you can't set the location. If using only Chrome is okay then you will have the following options:
Stick with Drag n' Drop like from the CSS Ninja's tutorial, then you should try Ben's answer. encodeURIComponent is one way, but if you have the file generated using BlobBuilder then you can use window.webkitURL.createObjectURL() to get the file's URL. You can also try using FileWriter() with requestFileSystem(TEMPORARY, ...).
Chrome supports download attribute for anchor tags so you can have regular link for the user to click (dragging also works):
Download
For cross browser support I suggest Downloadify.
You could try sending it to the server, saving the file, checking the return value and firing the download file function, followed by a server file that deletes the file from the server.
Something like this (with jQuery)
$.ajax({
url: 'saveFile.php',
method: 'post',
data: {
Filedata: data// file data variable
},
success: function(d) {
// save file function, where d is the filename
}
})
PHP:
$filename = ;//generate filename
file_put_contents($filename, $_POST['Filedata']);
echo $filename;
Obviously there is more to it but that should be the basics