I whant to write a Cordova App for BlackBerry10 that can write a PDF file (from a SharePointWebservice) and show it.
The PDF is transmitted from a ASP.NET Webservice as byte[] using
byte[] result = spFile.OpenBinary();
I'm able to access the file with JSON. This works fine.
To transform the data fromm JSON to usable format I use the following code:
var binary = '';
var bytes = new Uint8Array(data.d);
var len = bytes.byteLength;
for (var i = 0; i < len; i++) {
binary += String.fromCharCode(data.d[i]);
}
binary is now looking like that:
%PDF-1.5%ยตยตยตยต 1 0 obj ... startxref 103423 %%EOF
Here is the Code to write it to a file using cordova-plugin-file.
var blob = new Blob([binary], { type: 'application/pdf' });
fileWriter.write(blob);
It works fine for txt files, but when I try to write the PDF file I get an empty document.
I have also tryed window.btoa(binary) instead of just using binary.
Any ideas what ho to create the data blob, or which format to use?
I have solved the Problem by using the cordova fileOpener2 Plugin. I am using the var "bytes" from above filled into the new named variable data.
try {
window.resolveLocalFileSystemURL(cordova.file.externalApplicationStorageDirectory, function (directoryEntry) {
directoryEntry.getFile(fileName, { create: true }, function (fileEntry) {
fileEntry.createWriter(function (fileWriter) {
fileWriter.onwriteend = function (e) {
cordova.plugins.fileOpener2.open(cordova.file.externalApplicationStorageDirectory + fileName, 'application/pdf',
{
error: function (e) {
...
},
success: function () {
... //PDF has opened
}
}
);
};
fileWriter.onerror = function (e) {
...
};
//Blob erstellen - Blackberry File Plugin verwenden
var blob = new Blob([data], { type: 'application/pdf' });
fileWriter.write(blob);
}, function onerror(e) {
...
});
}, function onerror(e) {
...
});
}, function onerror(e) {
...
});
} catch (e) {
...
}
Used Plugins:
cordova-plugin-file &
cordova-plugin-file-opener2
For other file types like PNG I use (for jpg just replace png with jpg):
var blob = new Blob([data], { type: 'image/png' });
to write the file and
window.open(cordova.file.externalApplicationStorageDirectory + fileName);
to open and show it.
Showing txt files is quite easy, you can do it like that:
if (fileName.split('.')[1].indexOf("txt") > -1) {
var blob = new Blob([bytes], { type: 'text/plain' });
var objectUrl = URL.createObjectURL(blob);
window.open(objectUrl);
}
This worked for me, comment if you have any questions.
Related
I have used the below JS code provided by Microsoft in order to save a document in PDF:
Office.context.document.getFileAsync(Office.FileType.Pdf,
function(result) {
if (result.status == "succeeded") {
var myFile = result.value;
var sliceCount = myFile.sliceCount;
var slicesReceived = 0, gotAllSlices = true, docdataSlices = [];
console.log("File size:" + myFile.size + " #Slices: " + sliceCount);
// Now, you can call getSliceAsync to download the files,
// as described in the previous code segment (compressed format).
// Get the file slices.
getSliceAsync(myFile, 0, sliceCount, gotAllSlices, docdataSlices, slicesReceived);
myFile.closeAsync();
}
else {
console.log("Error:", result.error.message);
}
}
);
function getSliceAsync(file, nextSlice, sliceCount, gotAllSlices, docdataSlices, slicesReceived) {
file.getSliceAsync(nextSlice, function (sliceResult) {
if (sliceResult.status == "succeeded") {
if (!gotAllSlices) { // Failed to get all slices, no need to continue.
return;
}
// Got one slice, store it in a temporary array.
// (Or you can do something else, such as
// send it to a third-party server.)
docdataSlices[sliceResult.value.index] = sliceResult.value.data;
if (++slicesReceived == sliceCount) {
// All slices have been received.
file.closeAsync();
onGotAllSlices(docdataSlices);
}
else {
getSliceAsync(file, ++nextSlice, sliceCount, gotAllSlices, docdataSlices, slicesReceived);
}
}
else {
gotAllSlices = false;
file.closeAsync();
console.log("getSliceAsync Error:", sliceResult.error.message);
}
});
}
function onGotAllSlices(docdataSlices) {
var docdata = [];
for (var i = 0; i < docdataSlices.length; i++) {
docdata = docdata.concat(docdataSlices[i]);
}
var fileContent = new String();
for (var j = 0; j < docdata.length; j++) {
fileContent += String.fromCharCode(docdata[j]);
}
console.log('Final PDF content is received and stored in fileContent.');
send_file_content(fileContent);
}
function send_file_content(word_doc) {
var formData = new FormData();
var blob = new Blob([word_doc], { type: "application/pdf"});
formData.append("file", blob);
$.ajax({
type: 'POST',
url: 'My-upload-URL',
data: formData,
processData: false,
contentType: false
}).done(function(data) {
console.log('* Word Document successfully uploaded: ', data.filepath);
});
}
I'm pretty sure that the server side is OK as I have uploaded zillions of PDF documents and it works as expected, but when I upload Word PDF Document via the above JS code I get a blank page on server side. If the word document contains 3 pages then I will get 3 blank pages on server-side as a PDF file.
The Microsoft Documentation goes with charCodeAt function which ruins the data and makes a blank PDF document.
Instead of using that function, I used Uint8Array on the byte array directly:
var blob = new Blob([new Uint8Array(myFinalByteArray)], { type: 'application/pdf' });
And then uploaded the Blob using FormData into a remote server. The problem gone away with this approach.
I am using yeoman angular fullstack and im trying to do a simple file upload. I read the file from a form and i get it into the front end just fine
this.$scope.add = function() {
var f = document.getElementById('resume').files[0];
var reader = new FileReader();
reader.onload = (function(theFile) {
return function(e) {
console.log(e.target.result);
Auth.saveResume({
data: e.target.result,
name:theFile.name
});
};
})(f);
reader.readAsArrayBuffer(f);
}
in auth.services.ts i have
saveResume(resume, callback?: Function) {
console.log(User)
return User.saveResume({ id: currentUser._id }, {resume},
function() {
console.log('auth.service in function');
console.log('currentUser._id: ' + currentUser._id);
return safeCb(callback)(null);
},
function(err) {
return safeCb(callback)(err);
}).$promise;
},
it successfully makes it into my back end controller
router.put('/:id/resume', auth.isAuthenticated(), controller.saveResume);
where i have a saveResume function
export function saveResume(req, res){
console.log(typeof req.body.resume.data);
console.log(typeof req.body.resume.name);
}
In the save resume function when i access the "name" parameter it is correct and is of type string. However when i access "data" i just get an object. I would like data to be either a file or buffer so i can upload it to s3.
My only guess for why its an object instead of an ArrayBuffer is that i think node doesnt support javascript ArrayBuffers, blobs, or files. How do i get the file in the backend in some form that s3 will accept? ie file, blob, or buffer
As #bubblez suggest i encoded it to base 64 like so
var fileReader = new FileReader();
var base64;
// Onload of file read the file content
fileReader.onload = function(fileLoadedEvent) {
base64 = fileLoadedEvent.target.result;
// Print data in console
console.log(base64);
Auth.saveResume(f.name, base64);
};
// Convert data to base64
fileReader.readAsDataURL(f);
i also changed auth so that it takes two separate parameters
saveResume(name, data, callback?: Function) {
console.log(User)
return User.saveResume({ id: currentUser._id }, {name, data},
function() {
console.log('auth.service in function');
console.log('currentUser._id: ' + currentUser._id);
return safeCb(callback)(null);
},
function(err) {
return safeCb(callback)(err);
}).$promise;
},
i then decode from base 64
export function saveResume(req, res){
var base64String = req.body.data.split(';base64,').pop();
console.log(base64String);
var buf = Buffer.from(base64String, 'base64').toString('utf');
uploadParams.Body = buf;
}
and this works!
as title description.
I'm trying to take a file from js, send it to my web api, and save it as a file on the server.
in my js, i first take the files, an convert them to a object with the file prop, and a base64 string
for (var i = 0, f; f = files[i]; i++) {
var reader = new FileReader();
reader.onload = (function (theFile) {
return function (e) {
var newFile = { name : theFile.name,
type : theFile.type,
size : theFile.size,
lastModifiedDate : theFile.lastModifiedDate
}
console.log("e")
console.log(e)
console.log(theFile);
var binaryString = e.target.result;
updloadedFile(newFile, binaryString);
};
})(f);
reader.readAsDataURL(f)
Then i try to post it to my api, Sry there is a little angular mixed in here, but it should work like this anyway
function updloadedFile(file,data)
{
var dummyobj = {
Name: file.name,
Extension: file.type,
Path: "",
DataString: data,
}
$http.post('/api/FileBrowser/UploadedFiles/' + $rootScope.User.App_ID,
JSON.stringify(dummyobj),
{
headers: {
'Content-Type': 'application/json'
}
}
).success(function (data) {
}).error(function (data, status, headers, config) {
});
}
At last at my server, i try to take the DataString an convert it to a file
[HttpPost]
public void UploadedFiles(Int64 id, [FromBody]FileModel value)
{
try
{
var path = HttpContext.Current.Server.MapPath("~/gfx/Files/" + id + "/");
File.WriteAllBytes(path+"\\"+value.Name, Convert.FromBase64String(value.DataString));
}
catch (Exception ex)
{
throw;
}
}
But here it throw a exception with the messeage
The input is not a valid Base-64 string as it contains a non-base 64
character, more than two padding characters, or an illegal character
among the padding characters.
My base-64 string look like this in the web api
data:image/gif;base64,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
You need to remove data:image/gif;base64, before decoding, you can do this in javascript:
updloadedFile(newFile, binaryString.replace('data:image/gif;base64,', ''));
or in C#
File.WriteAllBytes(path+"\\"+value.Name, Convert.FromBase64String(value.DataString.Replace("data:image/gif;base64,", "")));
As jcubic mention, you need to remove the type tag.
A more dynamic way to remove the tag is to split on ;base64, and take last element. Should work for multiple types, instead of being hardcoded for gif files.
const GetBase64 = (file: any) => {
return new Promise((resolve, reject) => {
const reader = new FileReader();
reader.readAsDataURL(file);
reader.onload = () => {
var base64 = `${reader.result}`.split(';base64,').pop();
resolve({name: file.name, size: file.size,type: file.type, content: base64})
};
reader.onerror = error => reject(error);
});
};
I made an simple image manipulation experiment with html, css and javascript/jquery.
We can upload an image from local drive and displayed in browser.
After that we can also edit/tag the displayed image.
I use this jquery image tag plugin.
Then I think about, how can i save/print the edited image?
This is my code snippet :
$(function () {
$(":file").change(function () {
if (this.files && this.files[0]) {
var reader = new FileReader();
reader.onload = imageIsLoaded;
reader.readAsDataURL(this.files[0]);
}
});
});
function imageIsLoaded(e) {
$('#myImg').attr('src', e.target.result);
$('#myImg').imageTag();
};
Here's the real live app : http://nanonimos.com/upload-tag-image/
and this is the source code.
Any clue/advice would be greatly appreciated :)
You can convert the whole div to an canvas then convert the canvas into data uri(png,jpeg).
Check this Fiddlecanvastoimage for more.
Use this function(From Stackoverflow) to convert dataURI to blob:
function dataURItoBlob(dataURI) {
// convert base64/URLEncoded data component to raw binary data held in a string
var byteString;
if (dataURI.split(',')[0].indexOf('base64') >= 0)
byteString = atob(dataURI.split(',')[1]);
else
byteString = unescape(dataURI.split(',')[1]);
// separate out the mime component
var mimeString = dataURI.split(',')[0].split(':')[1].split(';')[0];
// write the bytes of the string to a typed array
var ia = new Uint8Array(byteString.length);
for (var i = 0; i < byteString.length; i++) {
ia[i] = byteString.charCodeAt(i);
}
return new Blob([ia], {type:mimeString});
}
and then whenever you want to save just post this file to server.
In HTML5 you can do like this:
var blob = dataURItoBlob(data);
var fd = new FormData();
fd.append("imageFile", blob);
Then send it with ajax like this:
$.ajax({
type: "POST",
url:"url to file",
data: fd,
success: function(result){
//check success
};
});
In a Google chrome extension I am working on, a file is downloaded from a server with an XMLHttpRequest. This file contains some binary data which are stored in an ArrayBuffer object. In order to provide the possibility to download this file I am using the createObjectURL API.
function publish(data) {
if (!window.BlobBuilder && window.WebKitBlobBuilder) {
window.BlobBuilder = window.WebKitBlobBuilder;
}
var builder = new BlobBuilder();
builder.append(data);
var blob = builder.getBlob();
var url = window.webkitURL.createObjectURL(blob);
$("#output").append($("<a/>").attr({href: url}).append("Download"));
}
It is working fine; except that the filename is an opaque UUID like 9a8f6a0f-dd0c-4715-85dc-7379db9ce142. Is there any way to force this filename to something more user-friendly?
you can force an arbitrary filename by setting the "download" attribute of your anchor
see: http://updates.html5rocks.com/2011/08/Downloading-resources-in-HTML5-a-download
I have never tried it before, but it should be possible to create a new File object (which allows you to specify a file name) and write your blob to it. Something along the lines of:
function publish(data, filename) {
if (!window.BlobBuilder && window.WebKitBlobBuilder) {
window.BlobBuilder = window.WebKitBlobBuilder;
}
fs.root.getFile(filename, {
create: true
}, function (fileEntry) {
// Create a FileWriter object for our FileEntry (log.txt).
fileEntry.createWriter(function (fileWriter) {
fileWriter.onwriteend = function (e) {
console.log('Write completed.');
};
fileWriter.onerror = function (e) {
console.log('Write failed: ' + e.toString());
};
var builder = new BlobBuilder();
builder.append(data);
var blob = builder.getBlob();
fileWriter.write(blob);
}, errorHandler);
}, errorHandler);
}
I think this could work for you.