I am getting image from the server in Base64 encoding.
My Base64 response is correct.
On the client side I am using following :
var blob = base64ToBlob(content, {type: 'image/jpeg'});
URL = window.URL || window.webkitURL;
var blobUrl = URL.createObjectURL(blob);
//Displaying image in div works.
var elImage = $("#dbimage");
elImage.append("<img src='data:image/jpeg;base64," + content+ " '/>");
///This doesn;t work.
return blobUrl;
var base64ToBlob = function(base64) {
var binary = atob(base64);
var len = binary.length;
var buffer = new ArrayBuffer(len);
var view = new Uint8Array(buffer);
for (var i = 0; i < len; i++) {
view[i] = binary.charCodeAt(i);
}
return new Blob([view], {type: 'image/jpeg'});
};
I am returning the blobURL to HandleBar template. It does not seem to recognize the blob.
This conversion is encapsulated in a promise. In the HandleBar template I am writing something like this :
<img {{bind-attr src=image.content}} />
This promise is present in the image attribute. The image displayed in the div works fine, but the one in the blob does not display.
Edit :
I am returning the promise, like this :
image : function() {
var promise = jQuery.ajax({
url: '/getattachments/?id=' + this.id + "&name=" + docname,
contentType: 'image/jpeg',
type: 'GET',
processData : false,
success: function(content) {
var blob = base64ToBlob(content, { type: 'image/jpeg'} );
URL = window.URL || window.webkitURL;
var blobUrl = URL.createObjectURL(blob);
return blobUrl;
},
error : function(content)
{
Em.Logger.info('Model:', this.id, 'has no image', err);
return '';
}
return DS.PromiseObject.create({ promise: promise });
}.property('_attachments'),
});
Pl help.
Thanks.
In the particular answer you provided there are a couple of little issues.
The property needs to be a computed property, not just a function
foo: function(){
}.property() // <-------this here
Additionally you were using part of Ember Data (the DS namespace) which isn't part of Ember, it is a separate product. This is fine, but you'll need to include the file if you're going to use it.
And since the promise is returning straight text, and not an object, you'll need to hook up to the content property of the promise object.
<img {{bind-attr src=img.content}}/>
http://emberjs.jsbin.com/qiyodojo/8/edit
Related
I know there are several threads about this topic, but I was not able to identify the problem in my case.
I have an application, where I upload an image to an endpoint-URL and after processing I'll receive a response. Works fine so far. The file is contained within a formdata object when using FileUploader-Control from SAPUI5.
When switching from file upload to "taking a picture with smartphone-camera", I dont have a file, I have an base64 dataurl (XString) image object.
var oImage = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAABQAA…8ryQAbwUjsV5VUaAX/y+YSPJii2Z9GAAAAABJRU5ErkJggg=="} // some lines are missing > 1 million lines
I thought converting it to blob and appending it to FormData might be the solution, but it does not work at all.
var blob = this.toBlob(oImage)
console.log("Blob", blob); // --> Blob(857809) {size: 857809, type: "image/png"} size: 857809 type: "image/png" __proto__: Blob
var formData = new window.FormData();
formData.append("files", blob, "test.png");
console.log("FormData", formData); // seems empty --> FormData {}__proto__: FormData
Functions (works fine from my perspective)
toBlob: function dataURItoBlob(dataURI) {
var byteString = atob(dataURI.split(',')[1]);
var mimeString = dataURI.split(',')[0].split(':')[1].split(';')[0]
var ab = new ArrayBuffer(byteString.length);
var ia = new Uint8Array(ab);
for (var i = 0; i < byteString.length; i++) {
ia[i] = byteString.charCodeAt(i);
}
var bb = new Blob([ab], {
"type": mimeString
});
return bb;
},
This is my problem, FormData is empty and my POST-request throws an undefined error (Loading of data failed: TypeError: Cannot read property 'status' of undefined at constructor.eval (...m/resources/sap/ui/core/library-preload.js?eval:2183:566))
//Create JSON Model with URL
var oModel = new sap.ui.model.json.JSONModel();
var sHeaders = {
"content-type": "multipart/form-data; boundary=---011000010111000001101001",
"APIKey": "<<myKey>>"
};
var oData = {
formData
};
oModel.loadData("/my-destination/service", oData, true, "POST", null, false, sHeaders);
oModel.attachRequestCompleted(function (oEvent) {
var oData = oEvent.getSource().oData;
console.log("Final Response XHR: ", oData);
});
Thanks for any hint
The upload collection is a complex standard control that can be used for attachment management. On desktop it opens a file dialog, on mobile it opens the ios or android photo options, which means picking a photo from the camera roll, or taking a new photo.
Fairly basic example, including the upload URL's and other handlers you'll need. More options are available, adjust to suit your needs. In your XML:
<UploadCollection
uploadUrl="{path:'Key',formatter:'.headerUrl'}/Attachments"
items="{Attachments}"
change="onAttachUploadChange"
fileDeleted="onAttachDelete"
uploadEnabled="true"
uploadComplete="onAttachUploadComplete">
<UploadCollectionItem
documentId="{DocID}"
contributor="{CreatedBy}"
fileName="{ComponentName}"
fileSize="{path:'ComponentSize',formatter:'.formatter.parseFloat'}"
mimeType="{MIMEType}"
thumbnailUrl="{parts:[{path:'MIMEType'},{path:'DocID'}],formatter:'.thumbnailURL'}"
uploadedDate="{path:'CreatedAt', formatter:'.formatter.Date'}" url="{path:'DocID',formatter:'.attachmentURL'}" visibleEdit="false"
visibleDelete="true" />
</UploadCollection>
Here's the handlers. Especially the onAttachUploadChange is important. I should mention there's no explicit post. If the uploadUrl is set correctly a post is triggered anyway.
onAttachUploadChange: function(oEvent) {
var csrf = this.getModel().getSecurityToken();
var oUploader = oEvent.getSource();
var fileName = oEvent.getParameter('files')[0].name;
oUploader.removeAllHeaderParameters();
oUploader.insertHeaderParameter(new UploadCollectionParameter({
name: 'x-csrf-token',
value: csrf
}));
oUploader.insertHeaderParameter(new UploadCollectionParameter({
name: 'Slug',
value: fileName
}));
},
onAttachDelete: function(oEvent) {
var id = oEvent.getParameter('documentId');
var oModel = this.getModel();
//set busy indicator maybe?
oModel.remove(`/Attachments('${encodeURIComponent(id)}')`, {
success: (odata, response) => {
//successful removal
//oModel.refresh();
},
error: err => console.log(err)
});
},
onAttachUploadComplete: function(oEvent) {
var mParams = oEvent.getParameter('mParameters');
//handle errors an success in here. Check `mParams`.
}
as for the formatters to determine URLs, that depends on your setup. In the case below, the stream is set up on the current binding contect, in which case this is one way to do it. You'll need the whole uri so including the /sap/opu/... etc bits.
headerUrl: function() {
return this.getModel().sServiceUrl + this.getView().getBindingContext().getPath()
},
URL for attachments is similar, but generally points to an entity of the attachment service itself.
attachmentURL: function(docid) {
return this.getModel().sServiceUrl + "/Attachments('" + docid + "')/$value";
},
You could fancy it up to check if it's an image, in which case you could include the mime type to show a thumbnail.
There might be better ways of doing this, but I've found this fairly flexible...
Before somebody says, "duplicate", I just want to make sure, that folks know, that I have already reviewed these questions:
1) Uses angular and php, not sure what is happening here (I don't know PHP): Download zip file and trigger "save file" dialog from angular method
2) Can't get this answer to do anything: how to download a zip file using angular
3) This person can already download, which is past the point I'm trying to figure out:
Download external zip file from angular triggered on a button action
4) No answer for this one:
download .zip file from server in nodejs
5) I don't know what language this even is:
https://stackoverflow.com/questions/35596764/zip-file-download-using-angularjs-directive
Given those questions, if this is still a duplicate, I apologize. Here is, yet, another version of this question.
My angular 1.5.X client gives me a list of titles, of which each have an associated file. My Node 4.X/Express 4.X server takes that list, gets the file locations, creates a zip file, using express-zip from npm, and then streams that file back in the response. I then want my client to initiate the browser's "download a file" option.
Here's my client code (Angular 1.5.X):
function bulkdownload(titles){
titles = titles || [];
if ( titles.length > 0 ) {
$http.get('/query/bulkdownload',{
params:{titles:titles},
responseType:'arraybuffer'
})
.then(successCb,errorCb)
.catch(exceptionCb);
}
function successCb(response){
// This is the part I believe I cannot get to work, my code snippet is below
};
function errorCb(error){
alert('Error: ' + JSON.stringify(error));
};
function exceptionCb(ex){
alert('Exception: ' + JSON.stringify(ex));
};
};
Node (4.X) code with express-zip, https://www.npmjs.com/package/express-zip:
router.get('/bulkdownload',function(req,resp){
var titles = req.query.titles || [];
if ( titles.length > 0 ){
utils.getFileLocations(titles).
then(function(files){
let filename = 'zipfile.zip';
// .zip sets Content-Type and Content-disposition
resp.zip(files,filename,console.log);
},
_errorCb)
}
});
Here's my successCb in my client code (Angular 1.5.X):
function successCb(response){
var URL = $window.URL || $window.webkitURL || $window.mozURL || $window.msURL;
if ( URL ) {
var blob = new Blob([response.data],{type:'application/zip'});
var url = URL.createObjectURL(blob);
$window.open(url);
}
};
The "blob" part seems to work fine. Checking it in IE's debugger, it does look like a file stream of octet information. Now, I believe I need to get that blob into the some HTML5 directive, to initiate the "Save File As" from the browser. Maybe? Maybe not?
Since 90%+ of our users are using IE11, I test all of my angular in PhantomJS (Karma) and IE. When I run the code, I get the old "Access is denied" error in an alert window:
Exception: {"description":"Access is denied...<stack trace>}
Suggestions, clarifications, answers, etc. are welcome!
Use this one:
var url="YOUR ZIP URL HERE";
window.open(url, '_blank');
var zip_file_path = "" //put inside "" your path with file.zip
var zip_file_name = "" //put inside "" file name or something
var a = document.createElement("a");
document.body.appendChild(a);
a.style = "display: none";
a.href = zip_file_path;
a.download = zip_file_name;
a.click();
document.body.removeChild(a);
As indicated in this answer, I have used the below Javascript function and now I am able to download the byte[] array content successfully.
Function to convert byte array stream (type of string) to blob object:
var b64toBlob = function(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;
};
An this is how I call this function and save the blob object with FileSaver.js (getting data via Angular.js $http.get):
$http.get("your/api/uri").success(function(data, status, headers, config) {
//Here, data is type of string
var blob = b64toBlob(data, 'application/zip');
var fileName = "download.zip";
saveAs(blob, fileName);
});
Note: I am sending the byte[] array (Java-Server-Side) like this:
byte[] myByteArray = /*generate your zip file and convert into byte array*/ new byte[]();
return new ResponseEntity<byte[]>(myByteArray , headers, HttpStatus.OK);
I updated my bulkdownload method to use $window.open(...) instead of $http.get(...):
function bulkdownload(titles){
titles = titles || [];
if ( titles.length > 0 ) {
var url = '/query/bulkdownload?';
var len = titles.length;
for ( var ii = 0; ii < len; ii++ ) {
url = url + 'titles=' + titles[ii];
if ( ii < len-1 ) {
url = url + '&';
}
}
$window.open(url);
}
};
I have only tested this in IE11.
I am getting byte array in service response and that image would be shown in an image field of my html page. Any idea how can i implement this. I tried to find out solution for this over stack overflow but not able to get valid solution. Please help. My code is:
this.getPrescription = function(pres_id) {
var deff = $q.defer();
$http({
method: "GET",
url: "www.abc.com/api/&prescriptionOnly=false&page=1",
headers: {
'Authorization': 'Bearer ' + localStorage.getItem("chemist_access_token"),
'Content-Type': 'application/json'
},
responseType: 'arraybuffer'
}).then(function(objS) {
console.log("getPrescription:\n" + JSON.stringify(objS))
deff.resolve(objS);
}, function(objE) {
errorHandler.serverErrorhandler(objE);
deff.reject(objE);
});
return deff.promise;
};
and in my controller I am calling like:
$scope.getPrescription = function(id) {
$ionicLoading.show({
template: '<ion-spinner icon="spiral"></ion-spinner>',
noBackdrop: false
});
serverRepo.prescriptionGet(id).then(function(objS) {
console.log("orderByCustomer:\n" + JSON.stringify(objS));
$scope.picdata=$window.URL.createObjectURL(new Blob([objS.data], {type: 'image/png'}));
$ionicLoading.hide();
console.log("getOrderByNew_success_loadMore:\n" +$scope.picdata);
}, function(objE) {
$ionicLoading.hide();
});
}
and when I check my console it showing:
getOrderByNew_success_loadMore:
blob:file:///0aa86d9f-61a1-4049-b18c-7bf81e05909f
Use this filter to convert byte array to base64
app.filter('bytetobase', function () {
return function (buffer) {
var binary = '';
var bytes = new Uint8Array(buffer);
var len = bytes.byteLength;
for (var i = 0; i < len; i++) {
binary += String.fromCharCode(bytes[i]);
}
return window.btoa(binary);
};
});
to bind it as image use
<img ng-src="data:image/JPEG;base64,{{picture | bytetobase}}" alt="..." width="100" height="100">
Or if you need to assign it a variable use
var image = $filter('bytetobase')($scope.picture );
If you need to display and image from byte array you can create an object using Blob and get it's URL to pass into the image tag source. The last parameter in Blob constructor contains information about blob type, so you should set correct type during blob creation.
$http.get(url, {responseType: 'arraybuffer'})
.then(function(response) {
return $window.URL.createObjectURL(new Blob([response.data], {type: 'image/png'}));
});
And when you don't plan to work with your object any longer (e.g. after image has been loaded in appropriate img tag)
Update
Alternative solution with base64
$scope.getPrescription = function(id) {
$ionicLoading.show({
template: '<ion-spinner icon="spiral"></ion-spinner>',
noBackdrop: false
});
serverRepo.prescriptionGet(id).then(function(objS) {
console.log("orderByCustomer:\n" + JSON.stringify(objS));
// Creating file reader
var reader = new window.FileReader();
// Creating blob from server's data
var data = new Blob([objS.data], {type: 'image/jpeg'});
// Starting reading data
reader.readAsDataURL(data);
// When all data was read
reader.onloadend = function() {
// Setting source of the image
$scope.picdata = reader.result;
// Forcing digest loop
$scope.$apply();
}
$ionicLoading.hide();
console.log("getOrderByNew_success_loadMore:\n" +$scope.picdata);
}, function(objE) {
$ionicLoading.hide();
});
}
Okay, I've read just about every Stack Overflow question on PDF downloading from a web service. None of them have helped me so far. I'm using this as a last ditch effort to try and get some answers. Basically, I'm making a GET request to the API, and need to get a dynamically generated PDF back. We've tried doing this with receiving a byte[] and now we're returning a stream with the content. The following is what we have in the web service controller:
var result = await resp.Content.ReadAsAsync<byte[]>();
var response = request.CreateResponse(HttpStatusCode.OK);
var dataStream = new MemoryStream(result);
response.Content = new StreamContent(dataStream);
response.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
response.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment");
response.Content.Headers.ContentDisposition.FileName = "idcard.pdf";
var fileStream = new FileStream(#"c:\temp\temp.pdf", FileMode.Create);
fileStream.Write(result, 0, result.Length);
fileStream.Close();
return response;
The FileStream part is a test we were doing to see if saving the data to a temporary file worked and that the PDF can be saved. That part does work. Going to c:\temp and opening the idcard.pdf file works perfectly. One of the problems with that is it does it silently and the user wouldn't know it's there. We can tell them, but we'd really prefer the PDF to open in the browser by default and/or have it save through the browser so they knew something happened.
My Angular code looks like this:
.factory('memberIdCard', ['$http', function($http) {
var get = function() {
return $http({
method: 'GET',
url: '/Member/IdCard',
headers: {
accept: 'application/octet-stream'
},
responseType: 'arraybuffer',
transformResponse: function(data) {
var pdf;
console.log('data: ', data);
if (data) {
pdf = new Blob([data], {
type: 'application/pdf'
});
console.log('pdf: ', pdf);
}
return pdf;
}
})
}
return {
get: get
}
}]);
I have tried this part with $http and $resource and neither works. Now, in my controller:
$scope.printIdCard = function() {
memberIdCard.get().then(function(data) {
var pdf = data.data;
FileSaver.saveAs(pdf, 'idcard.pdf');
var pdfUrl = window.URL.createObjectURL(pdf);
$scope.pdfView = $sce.trustAsResourceUrl(pdfUrl);
window.open($scope.pdfView);
});
As a note, FileSaver is from angular-file-saver.
After all that, the new window opens, but there's an error that says: Failed to load PDF Document, and if you try and open it in Adobe Acrobat it has an error that says: Adobe Acrobat Reader DC could not open 'idcard.pdf' because it is either not a supported file type or because the file has been damaged (for example, it was sent as an email attachment and wasn't correctly decoded).
Any help would be greatly appreciated. I feel like I've done everything that was suggested in many of the other SO questions, but maybe I'm missing something I just haven't been able to see.
Thanks!
I did something similar for .xlsx files, but the concept is the same. Hope this can help you, its working for me.
I got the javascript code to download the file from another SO answer, which I can't link because I don't remember where it was.
My web api controller looks like this:
[Route("all")]
[HttpGet]
public HttpResponseMessage GetAll(HttpRequestMessage request)
{
HttpResponseMessage response = null;
MemoryStream stream = _exportService.CreateDataStream();
response = request.CreateResponse(HttpStatusCode.OK);
response.Content = new ByteArrayContent(stream.GetBuffer());
response.Content.Headers.ContentDisposition = new System.Net.Http.Headers.ContentDispositionHeaderValue("attachment");
response.Content.Headers.Add("content-type", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
return response;
}
And the angular service:
(function (app) {
'use strict';
app.factory('exportService', exportService);
exportService.$inject = ['$q', '$http'];
function exportService($q, $http) {
var extension = '.xlsx';
var service = {
export: exportData
};
function exportData(event, fname){
var config = {
responseType: 'arraybuffer'
}
var path = 'api/export/'+event;
var deferred = $q.defer();
return $http.get(path, config).then(
function(response) {
var data = response.data;
var status = response.status;
var headers = response.headers();
var octetStreamMime = 'application/octet-stream';
var success = false;
var filename = fname + extension;
var contentType = headers['content-type'] || octetStreamMime;
try
{
// Try using msSaveBlob if supported
var blob = new Blob([data], { type: contentType });
if(navigator.msSaveBlob)
navigator.msSaveBlob(blob, filename);
else {
// Try using other saveBlob implementations, if available
var saveBlob = navigator.webkitSaveBlob || navigator.mozSaveBlob || navigator.saveBlob;
if(saveBlob === undefined) throw "Not supported";
saveBlob(blob, filename);
}
success = true;
deferred.resolve();
} catch(ex)
{
}
if(!success)
{
// Get the blob url creator
var urlCreator = window.URL || window.webkitURL || window.mozURL || window.msURL;
if(urlCreator)
{
// Try to use a download link
var link = document.createElement('a');
if('download' in link)
{
// Try to simulate a click
try
{
// Prepare a blob URL
var blob = new Blob([data], { type: contentType });
var url = urlCreator.createObjectURL(blob);
link.setAttribute('href', url);
// Set the download attribute (Supported in Chrome 14+ / Firefox 20+)
link.setAttribute("download", filename);
// Simulate clicking the download link
var event = document.createEvent('MouseEvents');
event.initMouseEvent('click', true, true, window, 1, 0, 0, 0, 0, false, false, false, false, 0, null);
link.dispatchEvent(event);
success = true;
deferred.resolve();
} catch(ex) {
}
}
if(!success)
{
// Fallback to window.location method
try
{
var blob = new Blob([data], { type: octetStreamMime });
var url = urlCreator.createObjectURL(blob);
window.location = url;
success = true;
deferred.resolve();
} catch(ex) {
deferred.reject();
}
}
}
}
return deferred.promise;
},
function(error) {
return $q.reject(error);
});
}
return service;
}
})(angular.module('core.module'));
I'm having troubles in finding a solution for this:
I retrieve a PDF blob from a SQL filestream field using Javascript in this way (it's a lightswitch project)
var blob = new Blob([screen.WebReportsPdfFilesStream.selectedItem.Pdf], { type: "application/pdf;base64" });
I have the blob and I can even convert it in a filestream or to base64("JVBERi0....." or "%PDF 1.6 ......", etc.)
No problem so far.
Now I need to display it in a viewer. I prefer the viewer to open in a new window but i'm open to embed it into my page somehow.
I'm wondering if I can directly pass the blob or the stream to the viewer and display the document. I've tried something like
PDFView.open(pdfAsArray, 0)
Nothing happens in the embedded viewer in this case.
The pdfAsArray is good since I can display it appending the stream to a canvas within the same page. I just want to display the viewer, not embed the PDF in a canvas, possibly in a new window.
Can anyone provide few lines of code on how to achieve that in Javascript?
I'm using PDFJS.version = '1.0.1040'; PDFJS.build = '997096f';
The code that worked for me to get base64 pdf data loaded was this:
function (base64Data) {
var pdfData = base64ToUint8Array(base64Data);
PDFJS.getDocument(pdfData).then(function (pdf) {
pdf.getPage(1).then(function (page) {
var scale = 1;
var viewport = page.getViewport(scale);
var canvas = document.getElementById('myCanvas');
var context = canvas.getContext('2d');
canvas.height = viewport.height;
canvas.width = viewport.width;
page.render({ canvasContext: context, viewport: viewport });
});
});
function base64ToUint8Array(base64) {
var raw = atob(base64);
var uint8Array = new Uint8Array(raw.length);
for (var i = 0; i < raw.length; i++) {
uint8Array[i] = raw.charCodeAt(i);
}
return uint8Array;
}
}
This function could be the success function of an api call promise. What I'm doing here is rendering the pdf onto a canvas element myCanvas.
<canvas id="myCanvas"></canvas>
This shows the first page of the pdf but has no functionality. I can see why the viewer is desirable. If I get this hooked up to the viewer (viewer.html / viewer.js) I will edit my answer.
EDIT: How to hook up the viewer
1 In bower.json, add "pdfjs-viewer": "1.0.1040"
2 Html:
<iframe id="pdfViewer" src="lib/pdfjs-viewer/web/viewer.html" style="width: 100%; height: 700px;" allowfullscreen="" webkitallowfullscreen=""></iframe>
3 Change the stupid default document in the viewer.js file:
var DEFAULT_URL = '';
4 Controller:
var pdfjsframe = document.getElementById('pdfViewer');
pdfjsframe.onload = function() {
LoadPdfDocument();
};
$scope.myApiCallThatReturnsBase64PdfData.then(
function(base64Data) {
$scope.base64Data = base64Data;
LoadPdfDocument();
},
function(failure) {
//NotificationService.error(failure.Message);
});
function LoadPdfDocument() {
if ($scope.PdfDocumentLoaded)
return;
if (!$scope.base64Data)
return;
var pdfData = base64ToUint8Array($scope.base64Data);
pdfjsframe.contentWindow.PDFViewerApplication.open(pdfData);
$scope.PdfDocumentLoaded = true;
}
function base64ToUint8Array(base64) {
var raw = atob(base64);
var uint8Array = new Uint8Array(raw.length);
for (var i = 0; i < raw.length; i++) {
uint8Array[i] = raw.charCodeAt(i);
}
return uint8Array;
}
If you've got an typed array (e.g. an Uint8Array), then the file can be opened using PDFView.open(typedarray, 0);.
If you've got a Blob or File object, then the data has to be converted to a typed array before you can view it:
var fr = new FileReader();
fr.onload = function() {
var arraybuffer = this.result;
var uint8array = new Uint8Array(arraybuffer);
PDFView.open(uint8array, 0);
};
fr.readAsArrayBuffer(blob);
Another method is to create a URL for the Blob/File object:
var url = URL.createObjectURL(blob);
PDFView.open(url, 0);
If the PDF Viewer is hosted at the same origin as your website that embeds the frame, then you can also view the PDF by passing the blob URL to the viewer:
var url = URL.createObjectURL(blob);
var viewerUrl = 'web/viewer.html?file=' + encodeURIComponent(url);
// TODO: Load the PDF.js viewer in a frame or new tab/window.
I finally made the PDFView.open method working. Now if I embed the viewer into my page and call the open function as Rob suggested in the first 2 examples it works.
For those who are looking for this kind of solution I provide some lines of code here:
This is the code in my Lightswitch mainPage.lsml.js. The js scripts (pdf.js, viewer and Others) are referenced in the main html page of the Lightswitch project (Default.html); I assume it should work with any other html page not Lightswitch based.
myapp.MainPage.ShowPdf_execute = function (screen) {
// Write code here.
// Getting the stream from sql
var blob = new Blob([screen.WebReportsPdfFilesStream.selectedItem.Pdf], { type: "application/pdf;base64" });
// Pass the stream to an aspx page that makes some manipulations and returns a response
var formData = new FormData();
formData.tagName = pdfName;
formData.append(pdfName, blob);
var xhr = new XMLHttpRequest();
var url = "../OpenPdf.aspx";
xhr.open('POST', url, false);
xhr.onload = function (e) {
var response = e.target.response;
var pdfAsArray = convertDataURIToBinary("data:application/pdf;base64, " + response);
var pdfDocument;
// Use PDFJS to render a pdfDocument from pdf array
PDFJS.getDocument(pdfAsArray).then(function (pdf) {
pdfDocument = pdf;
var url = URL.createObjectURL(blob);
PDFView.load(pdfDocument, 1.5)
})
};
xhr.send(formData); // multipart/form-data
};
This is the convertDataURIToBinary function
function convertDataURIToBinary(dataURI) {
var base64Index = dataURI.indexOf(BASE64_MARKER) + BASE64_MARKER.length;
var base64 = dataURI.substring(base64Index);
var raw = window.atob(base64);
var rawLength = raw.length;
var array = new Uint8Array(new ArrayBuffer(rawLength));
for (i = 0; i < rawLength; i++) {
array[i] = raw.charCodeAt(i);
}
return array;
}
What is still missed is the possibility to pass the stream directly to the viewer.html page in order to open it in a new window and have a separate ui where make the rendering.
This code is still not working since I got an empty viewer with no document inside:
var blob = new Blob([screen.WebReportsPdfFilesStream.selectedItem.Pdf], { type: "application/pdf;base64" });
var url = URL.createObjectURL(blob);
var viewerUrl = 'Scripts/pdfViewer/web/viewer.html?file=' + encodeURIComponent(url);
window.open(viewerUrl);
Looks like the encodeURIComponent(url) is not passing to the viewer a good object to load into the viewer.
Any idea or suggestion?
var url = URL.createObjectURL(blob);
var viewerUrl = 'web/viewer.html?file=' + encodeURIComponent(url);
// TODO: Load the PDF.js viewer in a frame or new tab/window.
//-- Abobe code opens a new window but with errors : 'Missing PDF
// blob://http://server-addr:port/converted-blob'
I am using viewer in an iframe;
<iframe
id="pdfIframe"
src="pdfjs/web/viewer.html"
style="width: 100%; height: 100%;"
>
</iframe>
And fetch API used as follows;
fetch(pdfSourceUrl).then((response: Response) => {
response.blob().then((blob) => {
var url = URL.createObjectURL(blob);
pdfIframe.src = `pdfjs/web/viewer.html?file=${url}`;
});
});
Eventually iframe src created as follows;
http://localhost:9000/pdfjs/web/viewer.html?file=blob:http://localhost:9000/14f6a2ec-ad25-40ab-9db8-560c15e90f6e