base64 image post to php results in empty file - ajax

My question is very similar to one at this thread. I'm creating a canvas element on the fly, adding one or more img elements to it, and posting each img in turn to a php script on the server that then saves the resulting file. It's a basic drag-and-drop operation for images, much like Facebook's or the one on G+. I have everything working correctly except that the files resulting from the upload and save are all empty-- or rather, they're 2kb each and display nothing but blackness.
Here's the relevant portions of the code:
HTML:
<form method="post" action="upload.php" id="formUpload">
<div id="op">
<label class="lbl">Drop images here to add them,<br>or click an image to see it enlarged</label>
<span style='display:inline-block'>
<input type="file" name="files[]" id='file' class="fileUpload" onchange="startRead()" multiple><br>
<input type='submit' name='submit' value='+' class="fileUpload">
</span>
</div>
</form>
(not bothering with CSS as it's not germane to this)
javascript/jquery:
function addImg(imgSrc) {
var canvas = document.createElement('canvas');
var context = canvas.getContext('2d');
var imageObj = new Image();
imageObj.onload = function() {
context.drawImage(imageObj, 5, 5);
};
imageObj.className = "imgThumbnail";
imageObj.style.width = 140 + "px";
imageObj.style.height = 140 + "px";
imageObj.src = imgSrc.currentTarget.result;
var dataURL = canvas.toDataURL();
$.ajax({
type: "POST",
url: "upload.php",
data: {
imgBase64: dataURL
}
}).done(function(data) {
var fileName = data;
if (fileName.substring(1,1) !== "!") {
document.getElementById('op').insertBefore(imageObj);
$("#op").on('click', 'img', imgEnlarge);
$.get($("#path").val() + "/includes/addImage.php", {
imageType: $("#imageType").val(),
idParentObject: $("#idParentObject").val(),
url: fileName
});
} else {
alert("Error in upload processs. Could not save " + data.substring(2, data.length-1) + ".");
imageObj.attr("src", "../images/missing.png");
}
});
}
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 : '!$file';
Any help figuring out what I'm missing will be greatly appreciated. Correct answers will be even more appreciated.

Got it. It was an order of operations error. I was posting the canvas's base64 representation prior to drawing the image onto it. Here's what the javascript looks like corrected:
function addImg(imgSrc) {
var canvas = document.createElement('canvas');
var context = canvas.getContext('2d');
var imageObj = new Image();
imageObj.className = "imgThumbnail";
imageObj.style.width = 140 + "px";
imageObj.style.height = 140 + "px";
imageObj.src = imgSrc.currentTarget.result;
context.drawImage(imageObj, 0, 0, 140, 140);
var dataURL = canvas.toDataURL('image/png');
$.ajax({
type: "POST",
url: $("#path").val() + "/includes/upload.php",
data: {
img: dataURL
}
}).done(function(data) {
var fileName = data;
if (fileName.substring(1,1) !== "!") {
document.getElementById('op').insertBefore(imageObj);
$("#op").on('click', 'img', imgEnlarge);
$.get($("#path").val() + "/includes/addImage.php", {
imageType: $("#imageType").val(),
idParentObject: $("#idParentObject").val(),
url: fileName
});
$("#testOutput").val(data);
$("#testOutput").show();
} else {
alert("Error in upload processs. Could not save " + data.substring(2, data.length-1) + ".");
imageObj.attr("src", "../images/missing.png");
}
});
}

Related

How can I get the signature from Vue Signature Pad + Laravel

Hi I have read but I have not found the answer so I ask:
How can I get the signature picture?
My Vuejs code is this one:
<VueSignaturePad width="100%" height="500px" ref="signaturePad" />
<div>
<button #click="save">Guardar</button>
<button #click="undo">Borrar</button>
</div>
My methods are:
undo() {
this.$refs.signaturePad.undoSignature();
},
save() {
this.loading = true;
e.preventDefault();
let currentObj = this;
const config = {
headers: { 'content-type': 'multipart/form-data' }
}
let formData = new FormData();
formData.append('signature', this.$refs.signaturePad.saveSignature());
axios.post('/api/signature/store?api_token='+App.apiToken, formData, config)
.then(function (response) {
currentObj.success = response.data.success;
})
}
My Laravel code has this:
$fileName = time().'_'.'signature'.'_'.$this->user->rut.'_'.date('d_m_Y').'.'.$request->file->getClientOriginalExtension();
$signature = new Signature;
$signature->rut = $this->user->rut;
$signature->signature = $fileName;
$signature->save();
Storage::disk('dropbox')->putFileAs(
'signatures/',
$request->file,
$fileName
);
The problem is that it displays me an error:
Call to a member function getClientOriginalExtension() on null
So I wonder how can I get the image?
this option worked for me to convert the base64 file to image before sending it
Vue code
<div id="app">
<vueSignature ref="signature" :sigOption="option" :w="'800px'" :h="'400px'" :disabled="disabled"></vueSignature>
<vueSignature ref="signature1" :sigOption="option"></vueSignature>
<button #click="save">Save</button>
<button #click="clear">Clear</button>
<button #click="handleDisabled">disabled</button>
</div>
functions
save(){
var _this = this;
var png = _this.$refs.signature.save()
var block = png.split(";");
// Get the content type of the image
var contentType = block[0].split(":")[1];// In this case "image/gif"
// get the real base64 content of the file
var realData = block[1].split(",")[1];// In this case "R0lGODlhPQBEAPeoAJosM...."
// Convert it to a blob to upload
var blob = this.b64toBlob(realData, contentType);
let data = new FormData()
data.append('img', blob)
axios.post(this.url, data).then(res=>{
console.log(res.data)
}).catch(function (error) {
console.log(error.response)
})
},
b64toBlob(b64Data, contentType, sliceSize) {
contentType = contentType || '';
sliceSize = sliceSize || 512;
var byteCharacters = atob(b64Data);
var byteArrays = [];
for (var offset = 0; offset < byteCharacters.length; offset += sliceSize) {
var slice = byteCharacters.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);
}
var blob = new Blob(byteArrays, {type: contentType});
return blob;
},
I hope I've helped

convert .heic image to jpg image format in laravel

I have added intervention/image package to convert image format in laravel.
image converted successfully but after uploading image quality was so bad.
Original Image
Uploaded Image
$img =(string) Image::make($image['base64'])
->resize(500, 500)->encode('jpg',100);;
$img = base64_encode($img);
To convert Heic image you have to use imagick, can you use this instead
This is how to install https://ourcodeworld.com/articles/read/645/how-to-install-imagick-for-php-7-in-ubuntu-16-04
try {
$image = new \Imagick();
$image->readImageBlob($image['base64']));
$image->setImageFormat("jpeg");
$image->setImageCompressionQuality(100);
$image->writeImage($targetdir.$uid.".jpg");
}
catch (\ImagickException $ex) {
/**#var \Exception $ex */
return new JSONResponse(["error" => "Imagick failed to convert the images, check if you fulfill all requirements." , "details" => $ex->getMessage()], Http::STATUS_INTERNAL_SERVER_ERROR);
}
A bit late, but I had the same problem.
I managed to do it with the 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.
The heic2any js library helped me accomplish this (https://github.com/alexcorvi/heic2any/blob/master/docs/getting-started.md)
On the client side, I converted the picture, then gave it to the server input. The server sees it as it was originally uploaded as PNG.
$('#files').on('change' , function(){
var total_file=document.getElementById("files").files.length;
for(var i=0;i<total_file;i++)
{
files = event.target.files[i];
var fileName = files.name;
var fileNameExt = fileName.substr(fileName.lastIndexOf('.') + 1);
objURL = URL.createObjectURL(event.target.files[i]);
if(fileNameExt == "heic") {
objURL = await convertHeicToJpg(input , i);
}
})
async function convertHeicToJpg(input , i)
{
var blobfile = $(input)[0].files[i]; //ev.target.files[0];
let blobURL = URL.createObjectURL(blobfile);
// convert "fetch" the new blob url
let blobRes = await fetch(blobURL)
// convert response to blob
let blob = await blobRes.blob()
// convert to PNG - response is blob
let resultBlob = await heic2any({ blob })
console.log(resultBlob)
var url = URL.createObjectURL(resultBlob);
let fileInputElement = $(input)[0];
let container = new DataTransfer();
let file = new File([resultBlob], "heic"+".png",{type:"image/png", lastModified:new Date().getTime()});
container.items.add(file);
fileInputElement.files[0] = container.files;
uploadFile(container.files);
console.log("added");
console.log(url);
return url ;
}
function uploadFile(files)
{
console.log(files);
var error = '';
var form_data = new FormData();
for(var count = 0; count<files.length; count++)
{
var name = files[count].name;
var extension = name.split('.').pop().toLowerCase();
form_data.append("files[]", files[count]);
}
$.ajax({
url:"<?php echo base_url(); ?>Property/upload",
method:"POST",
data:form_data,
contentType:false,
cache:false,
processData:false,
dataType:'JSON',
beforeSend:function(){
//..processing
},
success:function(data)
{
alert('image uploade')
}
})
}

Binding Images to Image placeholder in repeater

I have a repeater that loads info from SQLite and works well. The user has options to take photos which are stored both in their photo library and in a temp folder. On reloading the page I need to reload the images to for a sliding gallery of thumbnails under the relevant section in the repeater.
The Image repeater is defined as
<Repeater items="{{ images }}" id="{{ repeaterphotoid }}">
<Repeater.itemTemplate>
<Image src="{{localurl}}" width="75" height="75" visibility="{{photoevidence === 'y' ? 'visible' : 'collapse'}}" />
</Repeater.itemTemplate>
</Repeater>
And my code is
exports.takePic = function(args){
var page = args.object;
camera.requestPermissions().then(
function success(){
var livesite = appSettings.getString("livesite");
var images=[];
var whichcamera = args.object;
var options = {saveToGallery: true, keepAspectRation: true, height: 1024 };
var gallery = args.object.page.getViewById("images-"+whichcamera.id);
var source = new imageSourceModule.ImageSource();
camera.takePicture(options).then(function(imageAsset){
var img = new imageModule.Image();
source.fromAsset(imageAsset).then((imageSource) => {
var auditDB = new sqlite("my.db", function(err, db){
if (err){
alert("Failed to open the database", err);
} else {
var tempfilename = livesite+"-"+whichcamera.qid+"-";
db.all("SELECT filename FROM images WHERE filename LIKE '"+tempfilename+"%'").then(rows =>{
//console.log("Images rows="+rows.length+1);
if (rows.length == 0){
imageCount = 1;
}
else
{
imageCount = rows.length+1;
}
var livesite = appSettings.getString("livesite");
// var path = filesystem.path.join(filesystem.knownFolders.documants().path,"photos")
var folder = filesystem.knownFolders.documents();
var filename = livesite+"-"+whichcamera.qid+"-"+imageCount+".jpg";
var imgPath = filesystem.path.join(folder.path,filename);
var saved = imageSource.saveToFile(imgPath,"jpg");
if (saved){
var livesite = appSettings.getString("livesite");
var liveaudit = appSettings.getString("liveaudit");
db.execSQL("INSERT INTO images (localurl,remoteurl,syncd,siteid,filename,question) VALUES(?,?,?,?,?,?)",[imgPath,'-','n',livesite,filename,whichcamera.qid])
var imageList = [];
var tempfilename = livesite+"-"+whichcamera.qid+"-";
var imageSQL = "SELECT localurl,remoteurl,filename FROM images WHERE filename LIKE '"+tempfilename+"%'";
db.all(imageSQL).then(rows =>{
for (var row in rows) {
imageList.push({
localurl: rows[row][0],
filename: rows[row][2]
});
}
const imagesource = fromObject({
images: imageList
});
imagesource.set = ("images", imageList);
var imageholder = args.object.page.getViewById("repeat_"+whichcamera.id);
imageholder.bindingContext = imagesource;
});
};
});
};
});
});
}).catch(function (err) {
alert("Camera Error "+err.message);
})
//alert("Taking Pic with camera "+whichcamera.id);
},
function failure(){
alert("You must allow this app access to the camera and your photos library.")
});
}
Binding to the questions works as expected but I cannot bind the images to the image repeater, nothing happens. Obviously missing something but going code blind.

Alloyui Ace editor read and write file

How read and write html or php file using ace editor ( alloyoui ), in the example i just get value to edit not from file and i have done to see the documentation but not get how read and write code from file.
example
YUI().use(
'aui-ace-editor',
function(Y) {
var editor = new Y.AceEditor(
{
boundingBox: '#myEditor',
height: '200',
mode: 'javascript',
value: 'alert("Write something here...");',
width: '700'
}
).render();
var mode = Y.one('#mode');
if (mode) {
var contents = {
javascript: 'alert("Write something here...");',
json: '{"value": "Write something here..."}',
php: '<?php echo "Write something here..."; ?>',
xml: '<value attr="something">Write something here...</value>'
};
var currentMode = 'javascript';
var updateValue = function() {
editor.set('value', contents[currentMode]);
};
mode.on(
'change',
function(event) {
currentMode = this.val();
editor.set('mode', currentMode);
updateValue();
}
);
}
}
);
how call the file code? or this can be done only change the value: 'alert("Write something here...");'whit file path/url?
thanks
You cannot write to or read system files with JavaScript. However, you can kind of write to files by reading the contents of uploaded files and loading them into the AceEditor. Use an <input type="file" /> to allow the user to upload the file. Once the file is uploaded, set the AceEditor's value to be the file's contents.
AUI().use('aui-ace-editor', function(A) {
var aceEditor;
var fileInput = A.one('#fileInput');
fileInput.on('change', function(event) {
var file = fileInput.getDOMNode().files[0];
if (file) {
// Other types may also be appropriate here:
if (file.type.startsWith('text/') || file.type.startsWith('application/')) {
var reader = new FileReader();
reader.onload = function (onloadEvent) {
if (!aceEditor) {
aceEditor = new A.AceEditor({
/* ...your AceEditor config... */
mode: 'text',
render: true
});
}
aceEditor.set('value', onloadEvent.target.result);
}
reader.onerror = function (onerrorEvent) {
alert('File could not be read. Aborting.')
}
reader.readAsText(file, "UTF-8");
}
else {
alert('File does not contain text. Aborting.');
}
}
});
});
You can also attempt to guess the mode that the editor should use from the file's mime type:
aceEditor.set('mode', file.type.replace(/^(text|application)\/(x-)?/, ''));
To download the edited file, you can use a data URI:
var downloadFileButton = Y.one('#downloadFileButton');
downloadFileButton.on('click', function(clickEvent) {
var downloadFileLink = Y.Node.create('<a href="data:' +
fileType + ';charset=utf-8,' +
encodeURIComponent(aceEditor.get('value')) +
'" download="' + fileName + '" style="display: none;" />');
var bodyElement = Y.one('body');
bodyElement.appendChild(downloadFileLink);
downloadFileLink.getDOMNode().click();
bodyElement.removeChild(downloadFileLink);
});
Here's a runnable example with all of the above features/code:
YUI().use('aui-ace-editor', function(Y) {
var aceEditor;
var fileName;
var fileType;
var fileInput = Y.one('#fileInput');
fileInput.on('change', function(event) {
var file = fileInput.getDOMNode().files[0];
if (file) {
fileType = file.type;
// Other types may also be appropriate here:
if (fileType.startsWith('text/') || fileType.startsWith('application/')) {
fileName = file.name;
var reader = new FileReader();
reader.onload = function (onloadEvent) {
if (!aceEditor) {
aceEditor = new Y.AceEditor({
boundingBox: '#aceEditor',
mode: 'text',
value: 'Upload a file to begin editing.',
height: '200',
width: '700',
render: true
});
var downloadFileButton = Y.one('#downloadFileButton');
downloadFileButton.setStyle('display', null);
downloadFileButton.on('click', function(clickEvent) {
var downloadFileLink = Y.Node.create('<a href="data:' +
fileType + ';charset=utf-8,' +
encodeURIComponent(aceEditor.get('value')) +
'" download="' + fileName + '" style="display: none;" />');
var bodyElement = Y.one('body');
bodyElement.appendChild(downloadFileLink);
downloadFileLink.getDOMNode().click();
bodyElement.removeChild(downloadFileLink);
});
}
aceEditor.set('value', onloadEvent.target.result);
aceEditor.set('mode', fileType.replace(/^(text|application)\/(x-)?/, ''));
}
reader.onerror = function (onerrorEvent) {
alert('File could not be read. Aborting.')
}
reader.readAsText(file, "UTF-8");
}
else {
alert('File does not contain text. Aborting.');
}
}
});
});
<script src="https://cdn.rawgit.com/stiemannkj1/701826667a70997013605edcd37e92a6/raw/469fe1ae297e72a5a80eb9015003b7b04eac735e/alloy-ui-3.0.1_aui_aui-min.js"></script>
<link href="https://cdn.rawgit.com/stiemannkj1/90be22de7f48c729b443af14796d91d3/raw/a9f35ceedfac7fc0559b121bed105eaf80f10bf2/aui-css_css_bootstrap.min.css" rel="stylesheet"></link>
<div class="yui3-skin-sam">
<input type="file" id="fileInput">
<div id="aceEditor"></div>
<button id="downloadFileButton" style="display: none;">Download File</button>
</div>

Phonegap camera.getPicture() missing file extension and header data

I've been struggling on this for a while.
When I upload an image in a phonegap application with camera.getPicture() and ft.upload() the image is uploaded without file extension. I read it was because of a cache thing, providing a link to the actual file entry or something.
It was annoying me but I moved on since the image was uploaded fine on my server and displayed fine too even without file extension.
But today, we figured images were sometime rotated by 90°.
I instantly made the connection between the missing part of the image data and this issue, and I guess (not sure) I am right on this point.
I read image rotated by 90° could be caused by missing header meta data, so I guess not only the file extension were missing after all..
Could someone explain me what am I missing in the code and what to do or in which direction to look ? That would be awesome.
Here is part of my code (I can give you more if needed)
navigator.camera.getPicture(function(uri) {
try {
var imageURI = uri;
...
var ft = new FileTransfer();
ft.upload(imageURI, "some_script.php", function(r) {
...
Note:The image stored in database seems fine, the issue happens when the image is displayed in an tag.
Here an example of file getting rotate once uploaded (I added manually the .jpg extension so I could upload it on noelshack otherwise not able to). As you can see, the link to image is OK but once in tag it gets rotated
http://image.noelshack.com/fichiers/2015/41/1444168922-35-1444166605.jpg
http://jsfiddle.net/c3ybkqt8/
tl;dr
How to upload an image file entirely with phonegap including file extension & metadata header and not only a sort of cached file entry.
iOS Code
function capturePhoto() {
navigator.camera.getPicture(uploadPhoto, onFail, {
quality: 50,
// allowEdit: true,
correctOrientation: true,
destinationType: Camera.DestinationType.FILE_URL,
// destinationType: Camera.DestinationType.DATA_URL
sourceType: Camera.PictureSourceType.CAMERA
}
);
}
// function onPhotoDataSuccess(imageData) {
// localStorage.setItem("ImageData",imageData);
// localStorage.setItem("captureImgFlag",captureImgFlag);
// window.location = 'profileUserImgUploadInGallary.html';
// }
function onFail(message) {
// alert('Failed because: ' + message);
}
function uploadPhoto(imageURI){
console.log(imageURI);
spinnerplugin.show();
var UserId = localStorage.getItem('UserId');
// imgPostGallary
// var img = document.getElementById('imgPostGallary');
// var imageURI = img.src;
// var imageURI = imageData;
// img.src = imageURI;
// var ImageDataUp = localStorage.getItem('ImageDataUp');
// var imageURI = ImageDataUp;
var options = new FileUploadOptions();
options.fileKey="file";
options.fileName=imageURI.substr(imageURI.lastIndexOf('/')+1);
options.mimeType="image/jpeg";
var ft = new FileTransfer();
ft.upload(imageURI, encodeURI("http://XYZ/uploadimg?user_id="+UserId+""), winGallary, fail, options);
console.log(ft.upload);
}
function winGallary(rGallary) {
console.log("Code = " + rGallary.responseCode);
console.log("Response = " + rGallary.response);
console.log("Sent = " + rGallary.bytesSent);
spinnerplugin.hide();
window.location = 'profileUserImgUploadInGallary.html';
}
function fail(error) {
console.log("upload error source " + error.source);
console.log("upload error target " + error.target);
}
Hello, here is full example it's working for me capturing photos and set in image tag and upload that photos on server. and still you have facing any problem message me.
<img id="profileImageId">
<script type="text/javascript">
var profileImage = '';
function profileCapturePhotoEdit() {
navigator.camera.getPicture(profileonPhotoDataSuccess, onFail, {
quality: 50,
// allowEdit: true,
correctOrientation: true, // using this your image not roted 90 degree
destinationType: Camera.DestinationType.DATA_URL,
sourceType: Camera.PictureSourceType.CAMERA }
);
}
function profileonPhotoDataSuccess(imageData) {
localStorage.setItem("imageDataProfile","data:image/jpeg;base64," + imageData);
var imageDataProfile = localStorage.getItem("imageDataProfile");
document.getElementById('profileImageId').src = imageDataProfile;
}
function onFail(message) {
// alert('Failed because: ' + message);
}
</script>
<!-- uploadProfileImage -->
<button onclick="uploadProfileImage();">
Upload Profile Image
</button>
<script type="text/javascript">
function uploadProfileImage() {
var UserId = localStorage.getItem('UserId');
var img = document.getElementById('profileImageId');
var imageURI = img.src;
var options = new FileUploadOptions();
options.fileKey="file"; // your file key in your .php file change here
options.fileName=imageURI.substr(imageURI.lastIndexOf('/')+1);
options.mimeType="image/jpeg"; // your extension
var ft = new FileTransfer();
ft.upload(imageURI, encodeURI("http://XYZ?user_id="+UserId+""), winProfile, failProfile, options);
}
function winProfile(r) {
console.log("Code = " + r.responseCode);
console.log("Response = " + r.response);
console.log("Sent = " + r.bytesSent);
// alert('Send success');
}
function failProfile(error) {
console.log("upload error source " + error.source);
console.log("upload error target " + error.target);
}
</script>

Resources