I am trying to resize an image in Parse Cloud Code following the Cloud Modules Guide.
The basic idea is as follows: when afterSave is called on a User, check if the small profile pic is null and standard profile pic is not null. If true, get the standard profile pic from Parse, read into buffer, create file, save file, then add file to User and Save. Unfortunately, the file doesn't seem to be saving properly.
Here is the cloud afterSave function:
Parse.Cloud.afterSave(Parse.User, function(request) {
...
Parse.Cloud.httpRequest({
url: request.object.get("profilePicture").url(),
success: function(response) {
// The file contents are in response.buffer.
var image = new Image();
console.log("Buffer: " + response.buffer );
console.log("Length " + response.buffer.length);
image.setData(response.buffer);
var imgData = image.data();
// Save the image into a new file.
var base64 = imgData.toString("base64");
var scaled = new Parse.File("thumbnail.png", { base64: base64 });
scaled.save().then(function() {
request.object.set("profilePictureSmall", scaled);
request.object.save();
}, function(error) {
console.log( "The file either could not be read, or could not be saved to Parse.");
});
}
});
...
});
The User object seems to save fine, but the image file that is saved is a broken image.
The strange thing is that console.log("Length " + response.buffer.length); outputs the proper size to the console.
console.log("Buffer: " + response.buffer ); Gives output: �PNG
Any idea what's going on here?
The issue is that setData() is an async call, you need to wait for it to finish before you do the next bit.
http://parse.com/docs/js/symbols/Image.html#setData
Here's a snippet:
Parse.Cloud.httpRequest({
url: request.object.get("profilePicture").url()
}).then(function(response) {
var image = new Image();
return image.setData(response.buffer);
}).then(function(image) {
// make it fit in 100x100
var width = 100, height = 100;
if (image.width() > image.height()) {
// work out scaled height
height = image.height() * (100/image.width());
} else {
// work out scaled width
width = image.width() * (100/image.height());
}
console.log("..scale to " + width + "x" + height);
return image.scale({
width: width,
height: height
});
}).then(function(scaledImage) {
// get the image data in a Buffer
return scaledImage.data();
}).then(function(buffer) {
// save the image to a new file
console.log("..saving file");
var base64 = buffer.toString("base64");
var name = "Thumbnail.png";
var thumbnail = new Parse.File(name, { base64: base64 });
return thumbnail.save();
}).then(function(thumbnail) {
// attach the image file to the original object
console.log("..attaching file");
request.object.set("profilePictureSmall", thumbnail);
return request.object.save();
}) /* further chaining here for after-save */;
You basically have to chain your promises together to allow the previous step to finish.
Related
I'm using "nativescript-imagepicker" plugin to get an image from device library.
To do this, i'm calling this two modules:
var imagepicker = require("nativescript-imagepicker");
var imageSourceModule = require("tns-core-modules/image-source");
For now i have some function that shows the gallery, and i can select an image, that next is converted to base64 string and assigned as global variable for later use:
model.gallery = function () {
var img;
var context = imagepicker.create({mode: "single"});
context.authorize()
.then(function () {
return context.present();
})
.then(function (selection) {
selection.forEach(function (selected) {
img = selected;
model.set('avatar', img);
});
var source = new imageSourceModule.ImageSource();
source.fromAsset(img)
.then(function (imageSource) {
var convertedAvatar = imageSource.toBase64String("jpeg",1);
global.convertedAvatar = convertedAvatar;
});
}).catch(function (e) {
alert ('Error, please try again');
});
};
Everything seems to work fine, but please take a look at image quality (1).
I've tried quality of 90, but seems that string was so long that this http call was crashing an app:
model.test = function() {
var base64 = global.convertedAvatar;
var content = 'type=profile&file='+base64+'&extension=jpeg';
http.request({
url: global.host + 'profile/upload',
method: 'POST',
headers: {"Content-Type": global.cType},
content: content,
}).then(function (response) {
global.loaderHide();
result = response.content.toJSON();
if (response.statusCode == 200) {
success('Success','Data saved.')
} else {
global.alerts('Error',result.message);
}
}).catch(function (error) {
global.alerts('Error', error);
});
};
My question is : i think that my approach is wrong as i have issues. Base64 string is very long. Is there a way to do this right ?
Am i able to maybe resize image so string can be smaller ?
Or maybe this is API's issue (not accepting very long strings)?
Finally, maybe i need to use another method like background http module for uploading images, not base64 strings ?
Thank you for any ideas.
Below attached image, how long base64 string is even with quality set to 1.
I am trying to detect emotions in faces from an image uploaded. I can't seem to find any example code for emotion detection.
https://azure.microsoft.com/en-us/try/cognitive-services/my-apis/?apiSlug=face-api&country=Canada&allowContact=true
I found this
https://learn.microsoft.com/en-us/azure/cognitive-services/emotion/quickstarts/javascript
but the url endpoint doesn't work. I then tried regular face api, but even that I get resource not found.
Does anyone know what's going one?
Thanks
var FACE = new function () {
this.listen = function() {
var camera = document.getElementById('camera');
camera.addEventListener('change', function(e) {
var imageFile = e.target.files[0];
var reader = new FileReader();
var fileType;
//wire up the listener for the async 'loadend' event
reader.addEventListener('loadend', function () {
//get the result of the async readAsArrayBuffer call
var fileContentArrayBuffer = reader.result;
sendImage(fileContentArrayBuffer, fileType);
});
if (imageFile) {
//save the mime type of the file
fileType = imageFile.type;
//read the file asynchronously
reader.readAsArrayBuffer(imageFile);
}
});
function sendImage(fileContentArrayBuffer, fileType) {
$.ajax({
// NOTE: You must use the same location in your REST call as you used to obtain your subscription keys.
// For example, if you obtained your subscription keys from westcentralus, replace "westus" in the
// URL below with "westcentralus".
url: "https://westcentralus.api.cognitive.microsoft.com/face/v1.0/",
beforeSend: function(xhrObj){
// Request headers, also supports "application/octet-stream"
xhrObj.setRequestHeader("Content-Type","application/json");
// NOTE: Replace the "Ocp-Apim-Subscription-Key" value with a valid subscription key.
xhrObj.setRequestHeader("Ocp-Apim-Subscription-Key","my key");
},
//don't forget this!
processData: false,
type: "POST",
// Request body
data: new Blob([fileContentArrayBuffer], { type: fileType })
}).done(function(data) {
alert(data);
// Get face rectangle dimensions
var faceRectangle = data[0].faceRectangle;
var faceRectangleList = $('#faceRectangle');
// Append to DOM
for (var prop in faceRectangle) {
faceRectangleList.append("<li> " + prop + ": " + faceRectangle[prop] + "</li>");
}
// Get emotion confidence scores
var scores = data[0].scores;
var scoresList = $('#scores');
// Append to DOM
for(var prop in scores) {
scoresList.append("<li> " + prop + ": " + scores[prop] + "</li>")
}
}).fail(function(err) {
alert("Error: " + JSON.stringify(err));
});
}
};
};
Assuming you have your key, the request URL for Emotion API should be
https://westus.api.cognitive.microsoft.com/emotion/v1.0/recognize?
You may also want to take a look at this website. It got similar code.
Sorry I can't use comment function as I am new here and don't have enough reputation to do so.
Could you double check with your api region? Because this error occurs when there is no resource found for given api key in a region.
And for accessing emotions you will need to pass parameters to api which will give you attributes for faces in response which contains emotions.
I need to extract 1st page of an uploaded PDF file(in SharePoint Online) & save it as a separate PDF file using JavaScript.
After some searching I found this. But I'm not able to understand how it works.
Please help.
As requested in the comment in a previous answer I am posting sample code to just get the first page in its original format, so not as a bitmap.
This uses a third party REST service that can PDF Convert, Merge, Split, Watermark, Secure and OCR files. As it is REST based, it supports loads of languages, JavaScript being one of them.
What follows is a self-contained HTML page that does not require any additional server side logic on your part. It allows a PDF file to be uploaded, splits up the PDF into individual pages and discards them all except for the first one. There are other ways to achieve the same using this service, but this is the easiest one that came to mind.
You need to create an account to get the API key, which you then need to insert in the code.
Quite a bit of the code below deals with the UI and pushing the generated PDF to the browser. Naturally you can shorten it significantly by taking all that code out.
<!DOCTYPE html>
<html>
<head>
<title>Muhimbi API - Split action</title>
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
<script type="text/javascript">
// ** Specify the API key associated with your subscription.
var api_key = '';
// ** For IE compatibility*
// ** IE does not support 'readAsBinaryString' function for the FileReader object. Create a substitute function using 'readAsArrayBuffer' function.
if (FileReader.prototype.readAsBinaryString === undefined) {
FileReader.prototype.readAsBinaryString = function (file_content) {
var binary_string = "";
var thiswindow = this;
var reader = new FileReader();
reader.onload = function (e) {
var bytes = new Uint8Array(reader.result);
var length = bytes.byteLength;
for (var i = 0; i < length; i++) {
binary_string += String.fromCharCode(bytes[i]);
}
thiswindow.content = binary_string;
$(thiswindow).trigger('onload');
}
reader.readAsArrayBuffer(file_content);
}
}
// ** For IE compatibility*
// ** Create a Blob object from the base64 encoded string.
function CreateBlob(base64string)
{
var file_bytes = atob(base64string);
var byte_numbers = new Array(file_bytes.length);
for (var i = 0; i < file_bytes.length; i++) {
byte_numbers[i] = file_bytes.charCodeAt(i);
}
var byte_array = new Uint8Array(byte_numbers);
var file_blob = new Blob([byte_array], {type: "application/pdf"});
return file_blob;
}
// ** Execute code when DOM is loaded in the browser.
$(document).ready(function ()
{
//** Make sure an api key has been entered.
if(api_key=='')
{
alert('Please update the sample code and enter the API Key that came with your subscription.');
}
// ** Attach a click event to the Convert button.
$('#btnConvert').click(function ()
{
// ** Proceed only when API Key is provided.
if(api_key=='')
return;
try
{
// ** Get the file object from the File control.
var source_file = document.getElementById('file_to_split').files[0];
//** Was a file uploaded?
if (source_file)
{
// ** Get the file name from the uploaded file.
var source_file_name = source_file.name;
var reader = new FileReader();
//** Read the file into base64 encoded string using FileReader object.
reader.onload = function(reader_event)
{
var binary_string;
if (!reader_event) {
// ** For IE.
binary_string = reader.content;
}
else {
// ** For other browsers.
binary_string = reader_event.target.result;
}
// ** Convert binary to base64 encoded string.
var source_file_content = btoa(binary_string);
if(source_file_content)
{
// ** We need to fill out the data for the conversion operation
var input_data = "{";
input_data += '"use_async_pattern": false';
input_data += ', "fail_on_error": false';
input_data += ', "split_parameter": 1';
input_data += ', "file_split_type": "ByNumberOfPages"';
input_data += ', "source_file_name": "' + source_file_name + '"'; // ** Always pass the name of the input file with the correct file extension.
input_data += ', "source_file_content": "' + source_file_content + '"'; // ** Pass the content of the uploaded file, making sure it is base64 encoded.
input_data += '}',
// ** Allow cross domain request
jQuery.support.cors = true;
// ** Make API Call.
$.ajax(
{
type: 'POST',
// ** Set the request header with API key and content type
beforeSend: function(request)
{
request.setRequestHeader("Content-Type", 'application/json');
request.setRequestHeader("api_key", api_key);
},
url: 'https://api.muhimbi.com/api/v1/operations/split_pdf',
data: input_data,
dataType: 'json',
// ** Carry out the conversion
success: function (data)
{
var result_code = "";
var result_details = "";
var processed_file_contents = "";
var base_file_name = "";
// ** Read response values.
$.each(data, function (key, value)
{
if (key == 'result_code')
{
result_code = value;
}
else if (key == 'result_details')
{
result_details = value;
}
else if (key == 'processed_file_contents')
{
processed_file_contents = value;
}
else if (key == 'base_file_name')
{
base_file_name = value;
}
});
// ** Show result code and details.
$("#spnResultCode").text(result_code);
$("#spnResultDetails").text(result_details);
if(result_code=="Success")
{
// ** Get first item in the array. This is the first page in the PDF
var processed_file_content = processed_file_contents[0];
// ** Convert to Blob.
var file_blob = CreateBlob(processed_file_content)
// ** Prompt user to save or open the converted file
if (window.navigator.msSaveBlob) {
// ** For IE.
window.navigator.msSaveOrOpenBlob(file_blob, base_file_name + "." + output_format);
}
else {
// ** For other browsers.
// ** Create temporary hyperlink to download content.
var download_link = window.document.createElement("a");
download_link.href = window.URL.createObjectURL(file_blob, { type: "application/octet-stream" });
download_link.download = base_file_name + ".pdf";
document.body.appendChild(download_link);
download_link.click();
document.body.removeChild(download_link);
}
}
},
error: function (msg, url, line)
{
console.log('error msg = ' + msg + ', url = ' + url + ', line = ' + line);
// ** Show the error
$("#spnResultCode").text("API call error.");
$("#spnResultDetails").text('error msg = ' + msg + ', url = ' + url + ', line = ' + line);
}
});
}
else
{
// ** Show the error
$("#spnResultCode").text("File read error.");
$("#spnResultDetails").text('Could not read file.');
}
};
reader.readAsBinaryString(source_file);
}
else
{
alert('Select file to convert.');
}
}
catch(err)
{
console.log(err.message);
// ** Show exception
$("#spnResultCode").text("Exception occurred.");
$("#spnResultDetails").text(err.message);
}
});
});
</script>
</head>
<body>
<div>
<form id="convert_form">
Select file: <input type="file" id="file_to_split" />
<br /><br />
<button id="btnConvert" type="button">Split PDF</button>
<br /><br />
Result_Code: <span id="spnResultCode"></span>
<br />
Result_Details: <span id="spnResultDetails"></span>
</form>
</div>
</body>
</html>
Big fat disclaimer, I worked on this service, so consider me biased. Having said that, it works well and could potentially solve your problem.
Finally found a solution.
First converting the uploaded PDF to image using PDF.JS, done some customization in the sample code.
Then saved the 1st page image as PDF using jsPDF.
The customized download code,
$("#download-image").on('click', function() {
var imgData = __CANVAS.toDataURL();
var doc = new jsPDF();
doc.addImage(imgData, 0, 0, 210, 300);
doc.save('page1.pdf');
});
I'm trying to embed an image using the base64 data pattern, instead of a URL reference. I first download the data from Azure Blob storage, using the Azure Node.js SDK:
https://azure.microsoft.com/en-us/documentation/articles/storage-nodejs-how-to-use-blob-storage/#download-blobs
From what I can tell the data downloads as a string. But I'm not sure what to do with the string to get it into base64.
I need to encode the data as base64 and set the image source attribute. How do I do that?
Here is a snippet that shows what happens when I try to just embed the downloaded data directly:
cameraContainer.listBlobsSegmentedWithPrefix($routeParams.cameraId, path, null, options, function(error, result, response) {
result.entries.forEach(function(entry) {
$http.get(containerUrl + "/" + $routeParams.cameraId + "/" + entry.name + containerToken)
.then(function(successResponse) {
$scope.camera.imageUrl = "data:image/jpeg;base64," + successResponse.data;
}, function(errorResponse) {
});
});
});
I end up getting this error in the browser:
Also, if I try executing the following JS:
console.log(decodeURIComponent(successResponse.data));
I get this error:
Here is the raw data when logging to console
This is how I did it in our product. Please give it a try.
Essentially the data you're getting back is Uint8Array. First thing you would need to do is convert that array into string. You can use the following code to do so:
function Uint8ToString(array) {
var chunkSize = 0x8000;
var c = [];
for (var i = 0; i < array.length; i += chunkSize) {
c.push(String.fromCharCode.apply(null, array.subarray(i, i + chunkSize)));
}
return c.join('');
}
Next, you need to convert this string in base64 format. Here's how I'm doing it currently:
var blobContentsAsString = Uint8ToString(blobContents);
var blobContentsAsBase64String = btoa(blobContentsAsString);
$scope.camera.imageUrl = "data:image/jpeg;base64," + blobContentsAsBase64String;
Do give it a try.
i'm stuck with image upload to firebase database asynchronous mecanism in my project, here's my problematic:
i have a form where user put some info, the user also need to provide 4 photo to complete the upload process.
i use firebase database & firebase storage to handle this, here's the flow :
user fill form1 form2 & form3 with text based info
user select img1 img2 img3 img4 image from his computer
user clic submit all 4 image upload to firebase and give me 4 download url
i append all previously gathered information + 4 download url in a dictionary and ship it to firebase database
so the my deal is to create and ship the dictionary only when and if the 4 photo url are set, i heard about deferred/promise concept but i see a lot of Ajax request and no one with a similar issue, here is what i have for now
$("#submit-bag").click(function () {
var uploadDfdimg1 = function() {
var deferred = new $.Deferred();
var uploadTask = storageRef.child('images/' + $img1.name).put($img1);
uploadTask.on('state_changed', function(snapshot){
}, function(error) {
deferred.reject(error);
}, function() {
var downloadURL = uploadTask.snapshot.downloadURL;
console.log(downloadURL);
url1 = downloadURL;
deferred.resolve(downloadURL);
return deferred.promise();
});
}
var uploadDfdimg2 = function() {
var deferred = new $.Deferred();
var uploadTask = storageRef.child('images/' + $img2.name).put($img2);
uploadTask.on('state_changed', function(snapshot){
}, function(error) {
deferred.reject(error);
}, function() {
var downloadURL = uploadTask.snapshot.downloadURL;
console.log(downloadURL);
url2 = downloadURL;
deferred.resolve(downloadURL);
return deferred.promise();
});
}
$.when(uploadDfdimg1,uploadDfdimg2).then(
function(){console.log('double trouble success')},
function(){console.log(url1 + " deferred")},
function(){console.log(url2 + " deferred")});
var brand = $("#select1 option:selected").text()
var mail = document.getElementById('form1').value
var postal_code = document.getElementById('form2').value
var comment = document.getElementById('comment').value
//UPLOAD IMG
//uploadImg(img1,url1);
//uploadImg(img2,url2);
uploadImg(img3,url3);
uploadImg(img4,url4);
//console.log(url1);
//console.log(url2);
console.log(url3);
console.log(url4);
//PHOTO LINK VAR
var postData = {
marque: brand,
email: mail,
code_postal: postal_code,
commentaire: comment,
//PHOTO LINK
validation: 0
};
var newPostKey = firebase.database().ref().child('submission').push().key;
var updates = {};
updates['/submission/' + newPostKey] = postData;
firebase.database().ref().update(updates)
like you can see here, img3 & img4 upload themselves using the old non fonctionnal manner (downloadUrl come after the all dictionary PostData is send)
for img1 & img2 i tryed to use Deferred to see if i can get the 2 url at the same time when $.when.().then fired, normally after the success promise of the two uploadDfdimg function
the result is, i instantly get the "double trouble" log message with empty url variable, and normally after a second, the two url returned by firebase for img3 and img4
return log of the above code
how can i be able to asynchronously send 4 image to firebase, get the url, and at the end of this process, put the url in my dictionary to send it to my database ?
The question appears to ask for the following type of approach.
First a utility function, which promisifies the upload process and delivers a promise-wrapped downloadURL.
function uploadImg(img) {
return $.Deferred(function(dfrd) {
var uploadTask = storageRef.child('images/' + img.name).put(img);
uploadTask.on(
'state_changed',
function(snapshot) {},
function(error) { dfrd.reject(error); },
function() { dfrd.resolve(uploadTask.snapshot.downloadURL); }
);
}).promise();
}
Now, that utility can be used to create 4 x promises, which can then be aggregated with $.when() :
$("#submit-bag").click(function () {
var p1 = uploadImg(img1);
var p2 = uploadImg(img2);
var p3 = uploadImg(img3);
var p4 = uploadImg(img4);
$.when(p1, p2, p3, p4).then(function(downloadUrl1, downloadUrl2, downloadUrl3, downloadUrl4) {
// Whatever you want to do with downloadUrl1, downloadUrl3, downloadUrl3, downloadUrl4, ...
// ... do it somewhere in this function.
var updates = {};
updates['/submission/' + firebase.database().ref().child('submission').push().key] = {
marque: $("#select1 option:selected").text(),
email: $('#form1').val(),
code_postal: $('#form2').val(),
commentaire: $('#comment').val(),
validation: 0
};
firebase.database().ref().update(updates);
});
}
More concisely, you would probably write :
$("#submit-bag").click(function () {
var promises = [img1, img2, img3, img4].map(uploadImg);
$.when.apply(null, promises).then(function(downloadUrl1, downloadUrl3, downloadUrl3, downloadUrl4) {
// Whatever you want to do with downloadUrl1, downloadUrl3, downloadUrl3, downloadUrl4, ...
// ... do it somewhere in this function.
// etc, as above
});
}