How to read a MemoryStream of a PDF and open it


#1

Hi,

I am a newbie in working with electron. I have built an app which communicates with a .Net REST service to fetch some data and display it on the screen. One of the data includes a PDF file which resides on a remote server which is read by the REST service and sent to the app as a MemoryStream.

How can i read the PDF from this memory stream and open the same in the Adobe Acrobat Reader which is installed on my windows 7 machine ? Please find below a sample code -

var optionsGetPDF = {
        host: 'localhost',
        port: 8080,
        path: '/GetPDFdoc?docid=' + docid,
        method: 'GET'
};

http.request(optionsGetPDF, function (res) {
    res.pipe(memStream);
    res.on('end', function () {
         alert(memStream.toString().length)
    })
}).end();

Any help is very much appreciated !!

Regards
Shobhit


#2

Its been 8 days since i posted this question, could anyone please help on this ?


#3

Have you tried saving it in a file and then opening that file in Acrobat?


#4

Sorry, I am not too much familiar with working with electron. I have tried the opening part with the help of the shell, but that I have been able to do for a file on the client machine by giving the full path. I did not play around with the ‘fs’ that much.

But I did try the below -

var fs = require('fs');
var wstream = fs.createWriteStream('myfile.pdf');

var optionsGetPDF = {
        host: 'localhost',
        port: 8080,
        path: '/GetPDFdoc?docid=' + docid,
        method: 'GET'
};

http.request(optionsGetPDF, function (res) {
    res.pipe(memStream);
    wstream.write(memStream);
    res.on('end', function () {
         alert(memStream.toString().length)
    })
}).end();

On this I am getting error on wstream.write(memStream) -
Uncaught TypeError: Invalid non-string/buffer chunk.

Could you please provide me a code snippet how do i work around with it.

Thanks much.


#5

Given the code you are showing, I would suspect that this would work better:

var fs = require('fs');
var wstream = fs.createWriteStream('myfile.pdf');

var optionsGetPDF = {
        host: 'localhost',
        port: 8080,
        path: '/GetPDFdoc?docid=' + docid,
        method: 'GET'
};

http.request(optionsGetPDF, function (res) {
    res.pipe(wstream);
    res.on('end', function () {
         alert(wstream.toString().length)
    })
}).end();

#6

Nope. I tried doing it this way but it still didn’t work. Actually if you have looked at it close enough, what I am trying to do here is that I have a PDF file at a remote server. Through the .Net REST service I am converting that into a MemoryStream and sending it to the Client ( that happens when i do a http.request call with the options and capturing it with the response object ) , Now i have the PDF in form of a MemoryStream , I want to convert that PDF document back into its form and open it with the help of Electron Shell.

After doing what you had advised i had 2 issues

1.) The original PDF file which i am downloading is 4 MB but after fetching it at the client side it becomes ~13MB , not sure why.
2.) Also the pdf doesnt get opened up in the acrobat reader and throws up some error when we try to open it.

I am not sure whether my approach is correct or not, Please advise if i can make it work by some other way as well. May be with the help of just passing a byte[] array of the PDF doc or a FileStream may be.

I hope i am clear in explaining you the requirement.

Thank You. Appreciate your help !!


#7

So is your sample code that you’re posting here expected to run on the server side? Or on the client side in Electron? (Minor note, the name is just “Electron” … it used to be “Atom Shell” but we dropped the “Shell” when we changed the name :slight_smile: )


Sending pdf between WCF rest service and electron
#8

The sample code is of the client side. And sure i’ll remember to name electron as “Electron” :slight_smile:


#9

If the code you’re writing is on the client side then it doesn’t matter what form the data is stored in on the server side. Just because you’re using a .NET MemoryStream object on the server side doesn’t mean anything on the client. When you transfer the information from server to client, it isn’t a MemoryStream anymore … it’s just a bunch of bytes. So take those bunch of bytes and save them to a file.

Most likely this is happening because Node defaults to UTF-8 encoding but what you’re receiving is unencoded binary data. When calling fs.writeFile you want to set the encoding to binary.


#10

I still havent been able to find a solution to this.

As an alternative for the time being can anyone please help me with how can i remotely connect to a remote shared drive and loop through the folders and fetch a particular file whose name i already knew.

I need a complete sample code as i am very new to coding in javascript and come from a .net background.

Thanks !


#11

1.) The original PDF file which i am downloading is 4 MB but after fetching it at the client side it becomes ~13MB , not sure why.
Maybe PDF is send three times from whatever reason (bug in backend or client)
but @leedohm sugestion about UTF-8 seems more probable.


#12

I am able to debug in client and the server and quiet sure that its NOT doing it multiple times as it takes one trip to the server and i capture the result on the client side that very time. I tried to dig deeper into the UTF-8 option suggested by lee but couldnt get it working still.

There is also one issue when i try to call the getpdf service method directly from the browser(chrome, IE11, mozilla) then also i get an error. Below is the restful service code

Service method contract definition

[OperationContract]
[WebGet(ResponseFormat = WebMessageFormat.Json)]
MemoryStream GetPDF(string empid);

Service Side method Code

public MemoryStream GetPDF(string empid)
{
    string pdfName = "myfile.pdf";
    byte[] bytes = File.ReadAllBytes(@"C:\working\myfile.pdf");
    MemoryStream ms = new MemoryStream();
    ms.Write(bytes, 0, bytes.Length - 1);
    ms.Position = 0;
    WebOperationContext.Current.OutgoingResponse.ContentType = "application/pdf";
    WebOperationContext.Current.OutgoingResponse.Headers.Add("Content-disposition", "inline; filename=" + pdfName);
    return ms; //ms.Length = 4658228
}

When I am trying to call this method directly from the browser it throws an error like below :

Client Side Electron App Code

const shell = require('electron').shell

var optionsGetPDF = {
host: 'localhost',
port: 8080,
path: '/GetPDF?empid=' + empid.trim(),
method: 'GET'
};

var request = http.request(optionsGetPDF, function (response) {
var data = [];

response.on('data', function (chunk) {
    data.push(chunk);
})

response.on('end', function () {
    data = Buffer.concat(data);
    shell.openItem(data);
})

});

request.end();

I tried other alternative ways on the client side like using memorystream object , piping the response into the fs object , but couldnt get it working.

Please help. Thanks in advance.


#13

Never tried node so I could be off-topic but I’m deeply interested in the answer and in learning node
So ill guess an attempt
I guess leedohm 's solution would imply something like this at the end of your code

response.on('end', function () {
    var data = Buffer.concat(data);
    var tempFilePath = "path/to/some/temp/folder/temp.pdf"
    fs.writeFileSync(file = tempFilePath,
                         data = data,
                         encoding = "utf8");
   // yourShowPdfFonction(tempFilePath);
   // Example :
   fs.readFile( tempFilePath,  function (err,data){
     response.contentType("application/pdf");
     response.send(data);
  });//not tested - yours to see
})

yourShowPdfFonction reads the file and show it in the place you want.
If you master callbacks use fs.writeFile and the show function in the callnack
Hope I’m not too far
https://nodejs.org/api/fs.html#fs_fs_write_fd_data_position_encoding_callback