Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How to use or create PDFDataRangeTransport? #10452

Closed
hojas opened this issue Jan 15, 2019 · 4 comments
Closed

How to use or create PDFDataRangeTransport? #10452

hojas opened this issue Jan 15, 2019 · 4 comments

Comments

@hojas
Copy link

hojas commented Jan 15, 2019

Attach (recommended) or Link to PDF file here:

Configuration:

  • Web browser and its version: Chrome v71
  • Operating system and its version: MacOS 10.14.2
  • PDF.js version: v2.0.943
  • Is a browser extension: no

Steps to reproduce the problem:

  1. I want to know how to use PDFDataRangeTransport, there is no document about it.

What is the expected behavior? (add screenshot)

What went wrong? (add screenshot)

Link to a viewer (if hosted on a site other than mozilla.github.io/pdf.js or as Firefox/Chrome extension):

@Snuffleupagus
Copy link
Collaborator

I want to know how to use PDFDataRangeTransport, there is no document about it.

The API unit-tests contain (basic) examples of using PDFDataRangeTransport, see

pdf.js/test/unit/api_spec.js

Lines 1451 to 1546 in 5cb00b7

describe('PDFDataRangeTransport', function () {
var loadPromise;
function getDocumentData() {
const pdfPath = new URL('../pdfs/tracemonkey.pdf', window.location).href;
if (loadPromise) {
return loadPromise;
}
loadPromise = new Promise(function (resolve, reject) {
var xhr = new XMLHttpRequest(pdfPath);
xhr.open('GET', pdfPath);
xhr.responseType = 'arraybuffer';
xhr.onload = function () {
resolve(new Uint8Array(xhr.response));
};
xhr.onerror = function () {
reject(new Error('PDF is not loaded'));
};
xhr.send();
});
return loadPromise;
}
it('should fetch document info and page using ranges', function (done) {
if (isNodeJS()) {
pending('XMLHttpRequest is not supported in Node.js.');
}
var transport;
var initialDataLength = 4000;
var fetches = 0;
var getDocumentPromise = getDocumentData().then(function (data) {
var initialData = data.subarray(0, initialDataLength);
transport = new PDFDataRangeTransport(data.length, initialData);
transport.requestDataRange = function (begin, end) {
fetches++;
waitSome(function () {
transport.onDataProgress(4000);
transport.onDataRange(begin, data.subarray(begin, end));
});
};
var loadingTask = getDocument(transport);
return loadingTask.promise;
});
var pdfDocument;
var getPagePromise = getDocumentPromise.then(function (pdfDocument_) {
pdfDocument = pdfDocument_;
var pagePromise = pdfDocument.getPage(10);
return pagePromise;
});
getPagePromise.then(function (page) {
expect(pdfDocument.numPages).toEqual(14);
expect(page.rotate).toEqual(0);
expect(fetches).toBeGreaterThan(2);
done();
}).catch(done.fail);
});
it('should fetch document info and page using range and streaming',
function (done) {
if (isNodeJS()) {
pending('XMLHttpRequest is not supported in Node.js.');
}
var transport;
var initialDataLength = 4000;
var fetches = 0;
var getDocumentPromise = getDocumentData().then(function (data) {
var initialData = data.subarray(0, initialDataLength);
transport = new PDFDataRangeTransport(data.length, initialData);
transport.requestDataRange = function (begin, end) {
fetches++;
if (fetches === 1) {
// send rest of the data on first range request.
transport.onDataProgressiveRead(data.subarray(initialDataLength));
}
waitSome(function () {
transport.onDataRange(begin, data.subarray(begin, end));
});
};
var loadingTask = getDocument(transport);
return loadingTask.promise;
});
var pdfDocument;
var getPagePromise = getDocumentPromise.then(function (pdfDocument_) {
pdfDocument = pdfDocument_;
var pagePromise = pdfDocument.getPage(10);
return pagePromise;
});
getPagePromise.then(function (page) {
expect(pdfDocument.numPages).toEqual(14);
expect(page.rotate).toEqual(0);
expect(fetches).toEqual(1);
done();
}).catch(done.fail);
});
});


The default viewer (when used in Firefox) also uses PDFDataRangeTransport, see

pdf.js/web/app.js

Lines 485 to 521 in 5cb00b7

initPassiveLoading() {
if (typeof PDFJSDev === 'undefined' ||
!PDFJSDev.test('FIREFOX || MOZCENTRAL || CHROME')) {
throw new Error('Not implemented: initPassiveLoading');
}
this.externalServices.initPassiveLoading({
onOpenWithTransport(url, length, transport) {
PDFViewerApplication.open(url, { range: transport, });
if (length) {
PDFViewerApplication.pdfDocumentProperties.setFileSize(length);
}
},
onOpenWithData(data) {
PDFViewerApplication.open(data);
},
onOpenWithURL(url, length, originalUrl) {
let file = url, args = null;
if (length !== undefined) {
args = { length, };
}
if (originalUrl !== undefined) {
file = { url, originalUrl, };
}
PDFViewerApplication.open(file, args);
},
onError(err) {
PDFViewerApplication.l10n.get('loading_error', null,
'An error occurred while loading the PDF.').then((msg) => {
PDFViewerApplication.error(msg, err);
});
},
onProgress(loaded, total) {
PDFViewerApplication.progress(loaded / total);
},
});
},
together with

pdf.js/web/firefoxcom.js

Lines 201 to 210 in 5cb00b7

class FirefoxComDataRangeTransport extends PDFDataRangeTransport {
requestDataRange(begin, end) {
FirefoxCom.request('requestDataRange', { begin, end, });
}
abort() {
// Sync call to ensure abort is really started.
FirefoxCom.requestSync('abortLoading', null);
}
}
and

pdf.js/web/firefoxcom.js

Lines 221 to 265 in 5cb00b7

initPassiveLoading(callbacks) {
let pdfDataRangeTransport;
window.addEventListener('message', function windowMessage(e) {
if (e.source !== null) {
// The message MUST originate from Chrome code.
console.warn('Rejected untrusted message from ' + e.origin);
return;
}
let args = e.data;
if (typeof args !== 'object' || !('pdfjsLoadAction' in args)) {
return;
}
switch (args.pdfjsLoadAction) {
case 'supportsRangedLoading':
pdfDataRangeTransport =
new FirefoxComDataRangeTransport(args.length, args.data);
callbacks.onOpenWithTransport(args.pdfUrl, args.length,
pdfDataRangeTransport);
break;
case 'range':
pdfDataRangeTransport.onDataRange(args.begin, args.chunk);
break;
case 'rangeProgress':
pdfDataRangeTransport.onDataProgress(args.loaded);
break;
case 'progressiveRead':
pdfDataRangeTransport.onDataProgressiveRead(args.chunk);
break;
case 'progress':
callbacks.onProgress(args.loaded, args.total);
break;
case 'complete':
if (!args.data) {
callbacks.onError(args.errorCode);
break;
}
callbacks.onOpenWithData(args.data);
break;
}
});
FirefoxCom.requestSync('initPassiveLoading', null);
},

@hojas
Copy link
Author

hojas commented Jan 15, 2019

@Snuffleupagus Thanks. But can not render the first page before downloaded the full file. How to render with ranges?

@Snuffleupagus
Copy link
Collaborator

But can not render the first page before downloaded the full file. How to render with ranges?

This issue asked how to use PDFDataRangeTransport, and examples were provided above. It's simply impossible, for anyone, to answer follow-up questions with zero context; please refer to https://github.com/mozilla/pdf.js/blob/master/.github/CONTRIBUTING.md and in particular (emphasis mine):

If you are developing a custom solution, first check the examples at https://github.com/mozilla/pdf.js#learning and search existing issues. If this does not help, please prepare a short well-documented example that demonstrates the problem and make it accessible online on your website, JS Bin, GitHub, etc. before opening a new issue or contacting us on the IRC channel -- keep in mind that just code snippets won't help us troubleshoot the problem.

@timvandermeij
Copy link
Contributor

timvandermeij commented Jan 15, 2019

Closing since the original question is answered. For range requests, refer to https://github.com/mozilla/pdf.js/wiki/Frequently-Asked-Questions#range.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants