简体   繁体   中英

How to load a pdf received from an http call into the viewer?

I am getting a pdf from:

return this.http.get(path, { observe: 'response', responseType: 'arraybuffer' });

and processing it as a blob:

let blob: Blob = new Blob([response.body], { type: 'application/pdf' });

I am now looking to store that file locally and reference it through a local url. The reason I need to use a url is because the viewer.loadModel() requires it as a parameter. I have tried using let url = window.URL.createObjectURL(this.blobToFile(blob, 'viewer.pdf')); to get a url.

When i do that I get: https://localhost:3000/35ef3b8e-e59f-4fe9-a8cc-1e2e542ffb2a The viewer doesn't know the file type without the ' .pdf ' behind it though. If I put.pdf behind that url: https://localhost:3000/35ef3b8e-e59f-4fe9-a8cc-1e2e542ffb2a.pdf , it seems to load some data but I get the following error:

core.js:6241 ERROR Error: Uncaught (in promise): TypeError: Cannot read property 'getData' of undefined
TypeError: Cannot read property 'getData' of undefined
    at v (Viewer3D.js:1335)
    at PDFLoader.js:1358
    at ZoneDelegate.push../node_modules/zone.js/dist/zone.js.ZoneDelegate.invoke (zone.js:386)
    at Object.onInvoke (core.js:41697)
    at ZoneDelegate.push../node_modules/zone.js/dist/zone.js.ZoneDelegate.invoke (zone.js:385)
    at Zone.push../node_modules/zone.js/dist/zone.js.Zone.run (zone.js:143)
    at zone.js:891
    at ZoneDelegate.push../node_modules/zone.js/dist/zone.js.ZoneDelegate.invokeTask (zone.js:421)
    at Object.onInvokeTask (core.js:41675)
    at ZoneDelegate.push../node_modules/zone.js/dist/zone.js.ZoneDelegate.invokeTask (zone.js:420)
    at resolvePromise (zone.js:832)
    at zone.js:739
    at zone.js:755
    at ZoneDelegate.push../node_modules/zone.js/dist/zone.js.ZoneDelegate.invoke (zone.js:386)
    at Object.onInvoke (core.js:41697)
    at ZoneDelegate.push../node_modules/zone.js/dist/zone.js.ZoneDelegate.invoke (zone.js:385)
    at Zone.push../node_modules/zone.js/dist/zone.js.Zone.run (zone.js:143)
    at zone.js:891
    at ZoneDelegate.push../node_modules/zone.js/dist/zone.js.ZoneDelegate.invokeTask (zone.js:421)
    at Object.onInvokeTask (core.js:41675)

which is on the last line below: (Viewer3D.js:1335)

Viewer3D.prototype.loadModel = async function(url, options, onSuccessCallback, onErrorCallback, onWorkerStart) {
        var self = this;

        // Kind of sucks, but I couldn't think of a better way because loaders
        // are so
        var reservation = self.impl._reserveLoadingFile();     // Reserve a slot for a loading file
        options = options || {};

        if (typeof options.skipPropertyDb === "undefined") {
            var skipParam = getParameterByName("skipPropertyDb") || "";
            options.skipPropertyDb = skipParam === "true" ? true : (skipParam === "false" ? false : undefined);
        }

        var loaderInstance;
        function onDone( error, model ) {
            self.impl._removeLoadingFile(loaderInstance);
            if (error) {
                self.dispatchEvent({ type: et.LOADER_LOAD_ERROR_EVENT, error: error, loader: loaderInstance })
                onError( error.code, error.msg, error.args );
                return;
            }

            model.getData().underlayRaster = options.underlayRaster && model.getLeaflet();

Is there a way I can store the pdf locally from the blob and then get a local URL to it that will work with it? Or is there a way I can pass a bearer token so the loader can access storage? I'm not sure what else to do because the viewer.loadModel() only seems to work if I use a local absolute path to a file (Ex. https://localhost:3000/Content/Documents/qcad1.pdf"). I'd also like to mention I can't process it through the model-derivative api as it loses the pdf vectors if I do.

More context: This is where I'm loading the model...

Autodesk.Viewing.Initializer({ env: 'Local' }, () => {
            this.viewer = new Autodesk.Viewing.GuiViewer3D(document.getElementById('forgeViewer'));
            this.viewer.start();
            this.viewer.setTheme('dark-theme');
            this.viewer.loadExtension('Autodesk.Viewing.MarkupsCore');

            this.viewer.loadModel(this.pdfUrl, {}, this.initializeMeasureSettings.bind(this),
                () => {
                    console.log('File could not be loaded');

                    // On error was hoping to load a sample model but it loses context to the viewer somehow
                    //this.viewer.loadModel(this.samplePDF, {}, this.initializeMeasureSettings);
                });

            this.viewer.addEventListener('measurement-changed', this.onMeasurementChanged.bind(this));
            this.viewer.addEventListener('measurement-completed', this.onMeasurementCompleted.bind(this));
            this.viewer.addEventListener('finished-calibration', this.onCalibrationFinished.bind(this));
            this.viewer.addEventListener('delete-measurement', this.onObjectDeleted.bind(this));
            this.viewer.addEventListener('extensionLoaded', this.extensionLoaded.bind(this));

        });

So I ended up going deep into the pdfLoader and I found a way to pass a bearer token down which is used by PDFJS when loading the file from a url!

Just before calling viewer.loadModel I set:

Autodesk.Viewing.endpoint.HTTP_REQUEST_HEADERS = { Authorization: `Bearer ${this.authenticationService.getToken}` };

This is accessed PDFLoader.js:749 params.httpHeaders = av.endpoint.HTTP_REQUEST_HEADERS; .

This params object is what ends up being passed into PDFJS.getDocument(params) in the Promise.resolve (line 1370).

It's a standard feature in pdf.js but maybe Autodesk could make it easier by allowing it to be passed in the options object in viewer.loadModel().

Anyways, this allows me to download files securely from the backend and load them into the viewer.

I'm afraid that the loadModel method does not support any way to specify custom HTTP request headers so if the access to your PDF file is protected with an access token, that will be tricky.

What you could try is "hacking" the logic inside the loadModel function, not by appending .pdf directly to the data URI, but by faking the extension in a URL query or hash, eg:

https://localhost:3000/35ef3b8e-e59f-4fe9-a8cc-1e2e542ffb2a?name=foo.pdf

or

https://localhost:3000/35ef3b8e-e59f-4fe9-a8cc-1e2e542ffb2a#foo.pdf

This might be enough to convince the viewer to use the PDF loader, and at the same time it won't break the meaning of the URL.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM