1
0
Fork 0
mirror of https://github.com/mozilla/pdf.js.git synced 2025-04-19 14:48:08 +02:00

[api-minor] Attempt to support fetching the raw data of the PDF document from the PDFDocumentLoadingTask-instance (issue 15085)

The new API-functionality will allow a PDF document to be downloaded in the viewer e.g. while the PasswordPrompt is open, or in cases when document initialization failed.
Normally the raw data of the PDF document would be accessed via the `PDFDocumentProxy.prototype.getData` method, however in these cases the `PDFDocumentProxy`-instance isn't available.
This commit is contained in:
Jonas Jenwald 2025-03-09 14:50:43 +01:00
parent d1d88cc09e
commit 9e8d4e4d46
3 changed files with 92 additions and 30 deletions

View file

@ -629,39 +629,48 @@ const isValidExplicitDest = _isValidExplicitDest.bind(
class PDFDocumentLoadingTask {
static #docId = 0;
constructor() {
this._capability = Promise.withResolvers();
this._transport = null;
this._worker = null;
/**
* @private
*/
_capability = Promise.withResolvers();
/**
* Unique identifier for the document loading task.
* @type {string}
*/
this.docId = `d${PDFDocumentLoadingTask.#docId++}`;
/**
* @private
*/
_transport = null;
/**
* Whether the loading task is destroyed or not.
* @type {boolean}
*/
this.destroyed = false;
/**
* @private
*/
_worker = null;
/**
* Callback to request a password if a wrong or no password was provided.
* The callback receives two parameters: a function that should be called
* with the new password, and a reason (see {@link PasswordResponses}).
* @type {function}
*/
this.onPassword = null;
/**
* Unique identifier for the document loading task.
* @type {string}
*/
docId = `d${PDFDocumentLoadingTask.#docId++}`;
/**
* Callback to be able to monitor the loading progress of the PDF file
* (necessary to implement e.g. a loading bar).
* The callback receives an {@link OnProgressParameters} argument.
* @type {function}
*/
this.onProgress = null;
}
/**
* Whether the loading task is destroyed or not.
* @type {boolean}
*/
destroyed = false;
/**
* Callback to request a password if a wrong or no password was provided.
* The callback receives two parameters: a function that should be called
* with the new password, and a reason (see {@link PasswordResponses}).
* @type {function}
*/
onPassword = null;
/**
* Callback to be able to monitor the loading progress of the PDF file
* (necessary to implement e.g. a loading bar).
* The callback receives an {@link OnProgressParameters} argument.
* @type {function}
*/
onProgress = null;
/**
* Promise for document loading task completion.
@ -699,6 +708,16 @@ class PDFDocumentLoadingTask {
this._worker?.destroy();
this._worker = null;
}
/**
* Attempt to fetch the raw data of the PDF document, when e.g.
* - An exception was thrown during document initialization.
* - An `onPassword` callback is delaying initialization.
* @returns {Promise<Uint8Array>}
*/
async getData() {
return this._transport.getData();
}
}
/**

View file

@ -828,6 +828,47 @@ describe("api", function () {
await loadingTask.destroy();
});
it("gets data, on failure, from `PDFDocumentLoadingTask`-instance", async function () {
const typedArrayPdf = await DefaultFileReaderFactory.fetch({
path: TEST_PDFS_PATH + "issue6010_1.pdf",
});
// Sanity check to make sure that we fetched the entire PDF file.
expect(typedArrayPdf instanceof Uint8Array).toEqual(true);
expect(typedArrayPdf.length).toEqual(1116);
const loadingTask = getDocument(typedArrayPdf.slice());
expect(loadingTask instanceof PDFDocumentLoadingTask).toEqual(true);
let passwordData = null;
// Attach the callback that is used to request a password;
// similarly to how the default viewer handles passwords.
loadingTask.onPassword = async (updatePassword, reason) => {
passwordData = await loadingTask.getData();
updatePassword(new Error("Should reject the loadingTask."));
};
try {
await loadingTask.promise;
// Shouldn't get here.
expect(false).toEqual(true);
} catch (ex) {
expect(ex instanceof PasswordException).toEqual(true);
expect(ex.code).toEqual(PasswordResponses.NEED_PASSWORD);
}
// Ensure that the raw PDF document can be fetched while
// an `onPassword` callback is delaying initialization...
expect(passwordData).toEqual(typedArrayPdf);
// ... and once an exception has stopped initialization.
const data = await loadingTask.getData();
expect(data).toEqual(typedArrayPdf);
await loadingTask.destroy();
});
});
describe("PDFWorker", function () {

View file

@ -1153,7 +1153,9 @@ const PDFViewerApplication = {
async download() {
let data;
try {
data = await this.pdfDocument.getData();
data = await (this.pdfDocument
? this.pdfDocument.getData()
: this.pdfLoadingTask.getData());
} catch {
// When the PDF document isn't ready, simply download using the URL.
}