Skip to content

Commit

Permalink
XFA - Add support to print XFA forms
Browse files Browse the repository at this point in the history
  • Loading branch information
calixteman committed May 27, 2021
1 parent ac134ec commit e48e8d3
Show file tree
Hide file tree
Showing 7 changed files with 126 additions and 34 deletions.
2 changes: 2 additions & 0 deletions src/pdf.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import {
isValidFetchUrl,
LinkTarget,
loadScript,
PageViewport,
PDFDateString,
RenderingCancelledException,
} from "./display/display_utils.js";
Expand Down Expand Up @@ -135,6 +136,7 @@ export {
isPdfFile,
LinkTarget,
loadScript,
PageViewport,
PDFDateString,
RenderingCancelledException,
// From "./display/api.js":
Expand Down
7 changes: 7 additions & 0 deletions web/firefox_print_service.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
*/

import { RenderingCancelledException, shadow } from "pdfjs-lib";
import { getXfaHtmlForPrinting } from "./ui_utils.js";
import { PDFPrintServiceFactory } from "./app.js";

// Creates a placeholder with div and canvas with right size for the page.
Expand All @@ -33,6 +34,7 @@ function composePage(
canvas.height = Math.floor(size.height * PRINT_UNITS);

const canvasWrapper = document.createElement("div");
canvasWrapper.setAttribute("class", "printedPage");
canvasWrapper.appendChild(canvas);
printContainer.appendChild(canvasWrapper);

Expand Down Expand Up @@ -130,6 +132,11 @@ FirefoxPrintService.prototype = {
const body = document.querySelector("body");
body.setAttribute("data-pdfjsprinting", true);

if (pdfDocument.isPureXfa) {
getXfaHtmlForPrinting(printContainer, pdfDocument);
return;
}

for (let i = 0, ii = pagesOverview.length; i < ii; ++i) {
composePage(
pdfDocument,
Expand Down
15 changes: 13 additions & 2 deletions web/pdf_print_service.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
*/

import { PDFPrintServiceFactory, PDFViewerApplication } from "./app.js";
import { getXfaHtmlForPrinting } from "./ui_utils.js";
import { viewerCompatibilityParams } from "./viewer_compatibility.js";

let activeService = null;
Expand Down Expand Up @@ -139,6 +140,11 @@ PDFPrintService.prototype = {
},

renderPages() {
if (this.pdfDocument.isPureXfa) {
getXfaHtmlForPrinting(this.printContainer, this.pdfDocument);
return Promise.resolve();
}

const pageCount = this.pagesOverview.length;
const renderNextPage = (resolve, reject) => {
this.throwIfInactive();
Expand All @@ -157,8 +163,12 @@ PDFPrintService.prototype = {
this._printResolution,
this._optionalContentConfigPromise
)
.then(this.useRenderedPage.bind(this))
.then(function () {
.then(() => {
if (!this.pdfDocument.isPureXfa) {
this.useRenderedPage.bind(this);
}
})
.then(() => {
renderNextPage(resolve, reject);
}, reject);
};
Expand All @@ -181,6 +191,7 @@ PDFPrintService.prototype = {
}

const wrapper = document.createElement("div");
wrapper.setAttribute("class", "printedPage");
wrapper.appendChild(img);
this.printContainer.appendChild(wrapper);

Expand Down
27 changes: 27 additions & 0 deletions web/ui_utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@
* limitations under the License.
*/

import { DefaultXfaLayerFactory } from "./xfa_layer_builder.js";
import { PageViewport } from "pdfjs-lib";

const CSS_UNITS = 96.0 / 72.0;
const DEFAULT_SCALE_VALUE = "auto";
const DEFAULT_SCALE = 1.0;
Expand Down Expand Up @@ -994,6 +997,29 @@ function apiPageModeToSidebarView(mode) {
return SidebarView.NONE; // Default value.
}

function getXfaHtmlForPrinting(printContainer, pdfDocument) {
const xfaHtml = pdfDocument.allXfaHtml;
const factory = new DefaultXfaLayerFactory();
const scale = Math.round(CSS_UNITS * 100) / 100;
for (const xfaPage of xfaHtml.children) {
const page = document.createElement("div");
page.setAttribute("class", "xfaPrintedPage");
printContainer.appendChild(page);

const { width, height } = xfaPage.attributes.style;
const viewBox = [0, 0, parseInt(width), parseInt(height)];
const viewport = new PageViewport({ viewBox, scale, rotation: 0 });

const builder = factory.createXfaLayerBuilder(
page,
null,
pdfDocument.annotationStorage,
xfaPage
);
builder.render(viewport, "print");
}
}

export {
animationStarted,
apiPageLayoutToSpreadMode,
Expand All @@ -1010,6 +1036,7 @@ export {
getOutputScale,
getPageSizeInches,
getVisibleElements,
getXfaHtmlForPrinting,
isPortraitOrientation,
isValidRotation,
isValidScrollMode,
Expand Down
18 changes: 14 additions & 4 deletions web/viewer.css
Original file line number Diff line number Diff line change
Expand Up @@ -1772,7 +1772,8 @@ html[dir="rtl"] #documentPropertiesOverlay .row > * {
.toolbar,
#loadingBox,
#errorWrapper,
.textLayer {
.textLayer,
.canvasWrapper {
display: none;
}
#viewerContainer {
Expand Down Expand Up @@ -1816,7 +1817,7 @@ html[dir="rtl"] #documentPropertiesOverlay .row > * {
height: 100%;
}
/* wrapper around (scaled) print canvas elements */
#printContainer > div {
#printContainer > .printedPage {
page-break-after: always;
page-break-inside: avoid;

Expand All @@ -1829,8 +1830,17 @@ html[dir="rtl"] #documentPropertiesOverlay .row > * {
justify-content: center;
align-items: center;
}
#printContainer canvas,
#printContainer img {

#printContainer > .xfaPrintedPage {
page-break-after: always;
page-break-inside: avoid;
width: 100%;
height: 100%;
position: relative;
}

.printedPage canvas,
.printedPage img {
/* The intrinsic canvas / image size will make sure that we fit the page. */
max-width: 100%;
max-height: 100%;
Expand Down
7 changes: 7 additions & 0 deletions web/xfa_layer_builder.css
Original file line number Diff line number Diff line change
Expand Up @@ -262,3 +262,10 @@
.xfaTable .xfaRlRow > div {
flex: 1;
}

@media print {
.xfaTextfield,
.xfaSelect {
background-color: transparent;
}
}
84 changes: 56 additions & 28 deletions web/xfa_layer_builder.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,10 @@ class XfaLayerBuilder {
/**
* @param {XfaLayerBuilderOptions} options
*/
constructor({ pageDiv, pdfPage, annotationStorage }) {
constructor({ pageDiv, pdfPage, xfaHtml, annotationStorage }) {
this.pageDiv = pageDiv;
this.pdfPage = pdfPage;
this.xfaHtml = xfaHtml;
this.annotationStorage = annotationStorage;

this.div = null;
Expand All @@ -42,34 +43,54 @@ class XfaLayerBuilder {
* annotations is complete.
*/
render(viewport, intent = "display") {
return this.pdfPage
.getXfa()
.then(xfa => {
if (this._cancelled) {
return;
}
const parameters = {
viewport: viewport.clone({ dontFlip: true }),
div: this.div,
xfa,
page: this.pdfPage,
annotationStorage: this.annotationStorage,
};
if (intent === "display") {
return this.pdfPage
.getXfa()
.then(xfa => {
if (this._cancelled) {
return;
}
const parameters = {
viewport: viewport.clone({ dontFlip: true }),
div: this.div,
xfa,
page: this.pdfPage,
annotationStorage: this.annotationStorage,
};

if (this.div) {
XfaLayer.update(parameters);
} else {
// Create an xfa layer div and render the form
this.div = document.createElement("div");
this.pageDiv.appendChild(this.div);
parameters.div = this.div;
if (this.div) {
XfaLayer.update(parameters);
} else {
// Create an xfa layer div and render the form
this.div = document.createElement("div");
this.pageDiv.appendChild(this.div);
parameters.div = this.div;

XfaLayer.render(parameters);
}
})
.catch(error => {
console.error(error);
});
XfaLayer.render(parameters);
}
})
.catch(error => {
console.error(error);
});
}

// intent === "print".
const parameters = {
viewport: viewport.clone({ dontFlip: true }),
div: this.div,
xfa: this.xfaHtml,
page: null,
annotationStorage: this.annotationStorage,
};

// Create an xfa layer div and render the form
const div = document.createElement("div");
this.pageDiv.appendChild(div);
parameters.div = div;

XfaLayer.render(parameters);

return null;
}

cancel() {
Expand All @@ -92,12 +113,19 @@ class DefaultXfaLayerFactory {
* @param {HTMLDivElement} pageDiv
* @param {PDFPage} pdfPage
* @param {AnnotationStorage} [annotationStorage]
* @param {Object} [xfaHtml]
*/
createXfaLayerBuilder(pageDiv, pdfPage, annotationStorage = null) {
createXfaLayerBuilder(
pageDiv,
pdfPage,
annotationStorage = null,
xfaHtml = null
) {
return new XfaLayerBuilder({
pageDiv,
pdfPage,
annotationStorage,
xfaHtml,
});
}
}
Expand Down

0 comments on commit e48e8d3

Please sign in to comment.