I'm using Plupload in order to download file. The configuration we have is the folowing :
$("#uploadData").pluploadQueue({
// General settings
runtimes: 'html5,flash,silverlight,html4',
url: serviceurl,
// Maximum file size
max_file_size: '50mb',
chunk_size: '1mb',
max_file_count: 50,
unique_names: true,
// Resize images on clientside if we can
resize: {
width: 200,
height: 200,
quality: 90,
crop: true // crop to exact dimensions
},
// Specify what files to browse for
filters: [
{ title: "Documents Excel", extensions: "xlsx" }
],
init: {
FilesAdded: function (up, files) {
up.start();
},
UploadComplete: function (up, files) {
if (up.total.uploaded == up.files.length) {
$(".plupload_buttons").css("display", "inline");
$(".plupload_upload_status").css("display", "inline");
up.init();
}
}
},
The problem i have is when i upload a file that is bigger than 1MB, i don't receive the right name, instead i receive Blob for name.
For exemple, the name of my file is "Test.xlsx" and the size is 2MB, i will receive, on the server side, "blob" for name and not Test.
Limitation, i'm not allowed to change the chuck size limitation on the client.
How can i get the right name.
Thank for your help.
code used to receive the data on the server side :
[System.Web.Mvc.HttpPost]
public ActionResult UploadData(int? chunk, string name)
{
var fileUpload = Request.Files[0];
if (Session["upDataFiles"] == null)
{
Session["upDataFiles"] = new List<FileUploadViewModel>();
}
Session["upDataFiles"] = UpdateTempDataUpload(fileUpload.FileName, name, (List<FileUploadViewModel>)Session["upDataFiles"]);
UploadFile(chunk, name);
return Content("chunk uploaded", "text/plain");
}
private void UploadFile(int? fileChunk, string fileName)
{
var fileUpload = Request.Files[0];
var uploadPath = Server.MapPath("~/App_Data");
var fullPath = Path.Combine(uploadPath, fileName);
fileChunk = fileChunk ?? 0;
using (var fs = new FileStream(Path.Combine(uploadPath, fileName), fileChunk == 0 ? FileMode.Create : FileMode.Append, FileAccess.Write, FileShare.ReadWrite))
{
var buffer = new byte[fileUpload.InputStream.Length];
fileUpload.InputStream.Read(buffer, 0, buffer.Length);
fs.Write(buffer, 0, buffer.Length);
fs.Close();
}
}
When i check the name in the request.File object, it's blob and not the actual name.
This issue was described in detail on GitHub. It might be a little confusing, but from what I understand:
$_FILES[ 'name' ] will obligatorily be 'blob' if you use chunks.
They seem to claim that $_REQUEST[ 'name' ] should have the real name, but the users seem to disagree.
As a workaround it is proposed to send the filename along in another form field or url parameter (using for example the BeforeUpload event to set that information). You can set multipart_params and store your information on the file object that you added before or look at a field in your html to get information at this point.
To extend the answer by nus a bit:
I used the BeforeUpload event in Javascript as described in the GitHub post and then had to make a change server-side.
Previously, to get the file name I'd used:
var file = Request.Files[f];
var fileName = file.FileName
However, this had been where 'blob' was being returned. Instead, I made a change so while I still used Request.Files[f] for the file details, I derived the file name like so:
var file = Request.Files[f];
var fileName = Request.Params["name"];
Use BeforeUpload event under init as below:
init : {
BeforeUpload: function(up, file) {
log('[BeforeUpload]', 'File: ', file);
}
}
Also add log function:
function log() {
var str = "";
plupload.each(arguments, function(arg) {
var row = "";
if (typeof(arg) != "string") {
plupload.each(arg, function(value, key) {
// Convert items in File objects to human readable form
if (arg instanceof plupload.File) {
// Convert status to human readable
switch (value) {
case plupload.QUEUED:
value = 'QUEUED';
break;
case plupload.UPLOADING:
value = 'UPLOADING';
break;
case plupload.FAILED:
value = 'FAILED';
break;
case plupload.DONE:
value = 'DONE';
break;
}
}
if (typeof(value) != "function") {
row += (row ? ', ' : '') + key + '=' + value;
}
});
str += row + " ";
} else {
str += arg + " ";
}
});
var log = $('#log');
log.append(str + "\n");
// log.scrollTop(log[0].scrollHeight);
}
And then you can get Filename in $_POST['name'] or $_REQUEST['name'].
Also you can set unique_names as false.
You can also find help here
Related
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.
When I use dropzone.js to upload many files, the problem is appearing.
I need add more parameter to POST request, I have read the documentation on dropzonejs.com and wiki on github.com, parameter is added to request.
The problem is that the default parameter of file is files[0],files[1] ...(I set the paramName option to files), but I can't receive files parameters with java spring mvc code.
This is my spring mvc controller code:
#RequestMapping("/upload")
public Map<String,Object> method(CaseInfo info,HttpServletRequest request,#RequestParam("files[]")MultipartFile[] files){
...
}
This is my js core code:
this.on("sending", function(file, xhr, formData){
console.log("formData ->", formData);
var frm = $('#form');
var data = frm.serializeArray();
console.log('data ->', data);
for (var obj in data) {
formData.append(obj.name, obj.value);
}
});
The controller just can't receive files parameter, and the name of others is undefined,
edited:
I changed the for-in to below, then the undefined problem solved.
But I don't know why... somebody know?
for (var i = data.length - 1; i >= 0; i--) {
var obj = data[i];
formData.append(obj.name,obj.value);
}
I solved this problem by overwriting the source js code.
Dropzone.prototype._getParamName = function(n) {
if (typeof this.options.paramName === "function") {
return this.options.paramName(n);
} else {
// return "" + this.options.paramName + (this.options.uploadMultiple ? "[" + n + "]" : "");
return "" + this.options.paramName;
}
};
Understood this is an old question but I've had some success changing the "sending" option to "sendingmultiple" then passing a function that simply returns "files" to match up with the spring controller signature:
js
sendingmultiple: function(files, xhr, formData) {
// additional request paramter
formData.append('media', JSON.stringify(media));
for (const [key, value] of formData) {
console.log('key: ' + key + ' value: ' + value);
}
},
acceptedFiles: "image/*",
uploadMultiple: true,
paramName: function() { return "files"; }
java
#PostMapping("/user/media/upload")
#ResponseStatus(HttpStatus.CREATED)
public User uploadMedia(#RequestParam String media, #RequestParam("files") MultipartFile[] files) {
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 am getting a very strange issue whereby when I try to extract the word document as a compressed file for processing in my MS Word Task Pane MVC app the third time, it will blow up.
Here is the code:
Office.context.document.getFileAsync(Office.FileType.Compressed, function (result) {
if (result.status == "succeeded") {
var file = result.value;
file.getSliceAsync(0, function (resultSlice) {
//DO SOMETHING
});
} else {
//TODO: Service fault handling?
}
});
The error code that comes up is 5001. I am not sure how to fix this.
Please let me know if you have any thoughts on this.
Additional Details:
From MSDN:
No more than two documents are allowed to be in memory; otherwise the
getFileAsync operation will fail. Use the File.closeAsync method to
close the file when you are finished working with it.
Make sure you call File.closeAsync before you read the file again - that could explain the issue you are seeing.
More at: https://msdn.microsoft.com/en-us/library/office/jj715284.aspx
I have an example about how to use this API correctly. Actually the current example in the MSDN is not very correct. This code is tested in Word.
// Usually we encode the data in base64 format before sending it to server.
function encodeBase64(docData) {
var s = "";
for (var i = 0; i < docData.length; i++)
s += String.fromCharCode(docData[i]);
return window.btoa(s);
}
// Call getFileAsync() to start the retrieving file process.
function getFileAsyncInternal() {
Office.context.document.getFileAsync("compressed", { sliceSize: 10240 }, function (asyncResult) {
if (asyncResult.status == Office.AsyncResultStatus.Failed) {
document.getElementById("log").textContent = JSON.stringify(asyncResult);
}
else {
getAllSlices(asyncResult.value);
}
});
}
// Get all the slices of file from the host after "getFileAsync" is done.
function getAllSlices(file) {
var sliceCount = file.sliceCount;
var sliceIndex = 0;
var docdata = [];
var getSlice = function () {
file.getSliceAsync(sliceIndex, function (asyncResult) {
if (asyncResult.status == "succeeded") {
docdata = docdata.concat(asyncResult.value.data);
sliceIndex++;
if (sliceIndex == sliceCount) {
file.closeAsync();
onGetAllSlicesSucceeded(docdata);
}
else {
getSlice();
}
}
else {
file.closeAsync();
document.getElementById("log").textContent = JSON.stringify(asyncResult);
}
});
};
getSlice();
}
// Upload the docx file to server after obtaining all the bits from host.
function onGetAllSlicesSucceeded(docxData) {
$.ajax({
type: "POST",
url: "Handler.ashx",
data: encodeBase64(docxData),
contentType: "application/json; charset=utf-8",
}).done(function (data) {
document.getElementById("documentXmlContent").textContent = data;
}).fail(function (jqXHR, textStatus) {
});
}
You may find more information from here:
https://github.com/pkkj/AppForOfficeSample/tree/master/GetFileAsync
Hope this could help.
Additional to Keyjing Peng's answer (which I found very helpful, thanks!) I thought I'd share a variation on the encodeBase64, which you don't want to do if you are uploading via REST to SharePoint. In that case you want to convert the byte array to a Uint8Array. Only then could I get it into a SharePoint library without file corruption.
var uArray = new Uint8Array(docdata);
Hope this helps someone, couldn't find this info anywhere else online...
See this link
http://msdn.microsoft.com/en-us/library/office/jj715284(v=office.1501401).aspx
it contains this example method:
var i = 0;
var slices = 0;
function getDocumentAsPDF() {
Office.context.document.getFileAsync("pdf",{sliceSize: 2097152}, function (result) {
if (result.status == "succeeded") {
// If the getFileAsync call succeeded, then
// result.value will return a valid File Object.
myFile = result.value;
slices = myFile.sliceCount;
document.getElementById("result").innerText = " File size:" + myFile.size + " #Slices: " + slices;
// Iterate over the file slices.
for ( i = 0; i < slices; i++) {
var slice = myFile.getSliceAsync(i, function (result) {
if (result.status == "succeeded") {
doSomethingWithChunk(result.value.data);
if (slices == i) // Means it's done traversing...
{
SendFileComplete();
}
}
else
document.getElementById("result").innerText = result.error.message;
});
}
myFile.closeAsync();
}
else
document.getElementById("result2").innerText = result.error.message;
});
}
change "pdf" to "compressed" and the method call doSomethingWithChunk() needs to be created and should probably do something like this:
function base64Encode(str) {
return btoa(encodeURIComponent(str).replace(/%([0-9A-F]{2})/g, function (match, p1) {
return String.fromCharCode('0x' + p1);
}));
}
I use this technique to successfully save to Azure blob storage.
Obviously you should rename the method as well.
I have an asp.net page.
Inside this page I have an img control/element.
I am calling an ashx page on my server.
This ashx page accepts a timestamp from the client and compares it to a timestamp stored on the server.
If the timestamps do not match then I return an image which has been converted to a byte array (in C#).
If the timestamps do not match then I return a string value of "-1".
So, this is a cut-down of my ashx page:
public void ProcessRequest (HttpContext context) {
context.Response.AddHeader("Access-Control-Allow-Origin", "*");
try
{
string clientTS = context.Request.QueryString["clientTS"];
if (clientTS == serverTS)
{
//new version available. refresh browser
context.Response.ContentType = "text/json";
string value = "-1";
context.Response.Write(value);
}
else
{
context.Response.ContentType = "image/jpg";
byte[] data = Shared.GetMobileNextFrame("par1", 0);
context.Response.BinaryWrite(data);
}
}
catch (Exception ex)
{
context.Response.ContentType = "text/json";
context.Response.Write("ERR");
}
}
And in my javascript code:
function GetImageStatus() {
finished = false;
var val = url + '/Mobile/isNewFrame.ashx?Alias=' + Alias + '&CamIndex=' + camIndex + '&Version=' + version + '&GuidLogOn=' + guidLogOn;
$.ajax({
url: val,
type: 'GET',
timeout: refreshWaitlimit,
data: lastTS,
success: function (response, status, xhr) {
var ct = xhr.getResponseHeader("content-type");
if (ct.indexOf('json') > -1) {
//no update
}
else {
try {
live1x4.src = 'data:image/bmp;base64,' + encode(response);
}
catch (err) {
alert(err);
}
}
},
error: function (jqXHR, textStatus, errorThrown) {
//handle error
}
});
}
function encode(data) {
var str = String.fromCharCode.apply(null, data);
return btoa(str).replace(/.{76}(?=.)/g, '$&\n');
}
But I get an error returned:
TypeError: Function.prototype.apply: Arguments list has wrong type
If I just apply:
live1x4.src = 'data:image/bmp;base64,' + btoa(response);
instead of:
live1x4.src = 'data:image/bmp;base64,' + encode(response);
I get this error:
InvalidCharacterError: btoa failed. the string to be encoded contains
characters outside of the Latin1 range.
I have tried using a canvas control with example code i have found on this site. I do not get an error but I also do not get an image.
I know the image is valid because my old code was point the image.src directly to the ashx handler (and i was not comparing timestamps).
I do not want to encode the byte array to base64 string on the server because that would inflate the download data.
I was wondering if I was using the wrong context.Response.ContentType but I could not see what else I could use.
What am i doing wrong?
When looking at the documentation at MDN you should pass 1 or more parameters to fromCharCode. You pass none in this line:
var str = String.fromCharCode.apply(null, data);
The syntax is:
String.fromCharCode(num1, ..., numN)
There is although the apply method as your said in comments, but you use it the wrong way. The first parameter shouldn't be null.
The syntax of that is (from Convert array of byte values to base64 encoded string and break long lines, Javascript (code golf)):
somefunction.apply(thisObj[, argsArray])
Just use
var str = String.fromCharCode.apply(data);
So use the thisObj parameter to pass the data.