How to show a PDF from TBytes?

I want to show a PDF file of which I have the binary data in a TBytes variable, like so:

Var Bytes : TBytes;
Bytes := MyFunc();

I can successfully do the following to conventionally show the PDF to the user:

Application.DownloadPDFFile(Bytes,'MyDoc',False);

This downloads the file MyDoc.pdf and the file shows OK in the browser or Acrobat, so I know the data in Bytes are OK.

Now I want to show the PDF directly without the download step. I found something similar to what follows in a TMS Blog (TMS Software | Blog):

Var  BlobURL : String;
ASM
 BlobURL = window.URL.createObjectURL(new Blob([Bytes], { type: 'application/pdf' }));
End;

Application.Navigate(BlobURL)

or alternatively:

WebBrowserControl1.URL := BlobURL

Unfortunately, the BlobURL creation seems to create garbage, as all I get to see is a popup saying the PDF is unreadable.

I think my problem is that this step is not correct:

new Blob([Bytes], { type: 'application/pdf' })

as I input TBytes into the Blob() function whereas in the Blog article the input came from a HTTP request (ARequest.req.response). So the question is:

How would I correctly create the BlobURL from my Bytes?

Thank you very much!

Maybe this helps you in the right direction

I read that post and it does basically what is already suggested in the Blog post.

I think my problem is the creation of the javascript Blob object from my TBytes. Here is what I tried:

Var Bytes : TBytes;
Bytes := MyFunc();

Length(Bytes) is around 600 KB.

Conversion A (with brackets around Bytes):

ASM
 var blob = new Blob([Bytes], {type: 'application/pdf'});
 var BlobSize = blob.size;

This gives a BlobSize of around 2.1 MB.

Conversion B (without brackets around Bytes)::

ASM
 var blob = new Blob(Bytes, {type: 'application/pdf'});
 var BlobSize = blob.size;

This gives a BlobSize of around 1.4 MB.

I would assume that BlobSize should also be in the area of 600 KB, so I think I'm doing the conversion wrong.

I also tried to convert the TBytes into a TJSArray first, like so:

Var JA : TJSArray;
JA := TJSArray(Bytes);
JA.flength := Length(Bytes);
ASM
 var blob = new Blob([JA], {type: 'application/pdf'});
resp.
 var blob = new Blob(JA, {type: 'application/pdf'});

But both versions also result in the same blob sizes as above.

So, now my question comes down to:

How would I correctly convert my Pascal TBytes into that JS Blob object?

Thanks for any input!

Did you try the TCustomMemoryStream class method:

Class Function BytesToMemory(aBytes : TBytes) : TJSArrayBuffer;

Thank you Bruno, that did it!

Here the full solution to the problem of showing a PDF that comes as TBytes in 3 variants, in case someone needs this.

Uses JS;

Var 
 Bytes  : TBytes;
 Buffer : TJSArrayBuffer;
 BlobURL: String;

// This gets a PDF as TBytes from somewhere
Bytes := MyFunc(); 

// Variant A: Just download the PDF
Application.DownloadPDFFile(Bytes,'MyPDFFileName',False);

{$IFNDEF WIN32}
 // Convert TBytes to TJSArrayBuffer
 Buffer := TCustomMemoryStream.BytesToMemory(Bytes);
 ASM
  // Convert TJSArrayBuffer to JS Blob object
  var blob = new Blob([Buffer], {type: 'application/pdf'});
  // Create URL for Blob object
  BlobURL = URL.createObjectURL(blob);
 END;
 // Keep compiler happy...
 If Buffer.byteLength=0 then;
{$ENDIF}

// Variant B: Show PDF in new browser tab/window
Application.Navigate(BlobURL);

// Variant C: Show PDF in a WebBrowserControl on the form
WebBrowserControl1.URL := BlobURL;
1 Like

This topic was automatically closed 24 hours after the last reply. New replies are no longer allowed.