package jnpf.bizcommon.onlyoffice.service.impl;
|
|
import com.google.zxing.BinaryBitmap;
|
import com.google.zxing.MultiFormatReader;
|
import com.google.zxing.client.j2se.BufferedImageLuminanceSource;
|
import com.google.zxing.common.HybridBinarizer;
|
import jnpf.bizcommon.onlyoffice.entity.OnlyOfficeProperties;
|
import jnpf.dmsEntity.preview.model.DmsFilePreviewTicket;
|
import jnpf.dmsEntity.preview.model.DmsWatermarkPositionSnapshot;
|
import jnpf.dmsEntity.preview.model.DmsWatermarkSnapshot;
|
import jnpf.exception.DataException;
|
import org.apache.pdfbox.Loader;
|
import org.apache.pdfbox.pdmodel.PDDocument;
|
import org.apache.pdfbox.pdmodel.PDPage;
|
import org.apache.pdfbox.pdmodel.common.PDRectangle;
|
import org.apache.pdfbox.rendering.PDFRenderer;
|
import org.junit.Test;
|
|
import java.awt.image.BufferedImage;
|
import java.io.ByteArrayOutputStream;
|
import java.math.BigDecimal;
|
import java.util.List;
|
|
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertTrue;
|
|
public class DmsOnlyOfficePrintPdfComposerTest {
|
static {
|
System.setProperty("java.awt.headless", "true");
|
}
|
|
@Test
|
public void extractsOnlySelectedPagesAndStampsEachCopyBarcode() throws Exception {
|
DmsOnlyOfficePrintPdfComposer composer = new DmsOnlyOfficePrintPdfComposer(new OnlyOfficeProperties());
|
|
byte[] result = composer.compose(basePdf(3), List.of(
|
ticket("1,3", "COPY-1"), ticket("1,3", "COPY-2")));
|
|
try (PDDocument pdf = Loader.loadPDF(result)) {
|
assertEquals(4, pdf.getNumberOfPages());
|
PDFRenderer renderer = new PDFRenderer(pdf);
|
assertEquals("COPY-1", decode(renderer, 0));
|
assertEquals("COPY-1", decode(renderer, 1));
|
assertEquals("COPY-2", decode(renderer, 2));
|
assertEquals("COPY-2", decode(renderer, 3));
|
}
|
}
|
|
@Test
|
public void placesPrintBarcodeAtLandscapeCoordinatesOnRotatedPages() throws Exception {
|
DmsOnlyOfficePrintPdfComposer composer = new DmsOnlyOfficePrintPdfComposer(new OnlyOfficeProperties());
|
DmsFilePreviewTicket ticket = ticket("1", "ROTATED");
|
DmsWatermarkPositionSnapshot position = ticket.getWatermarks().get(0).getPositions().get(0);
|
position.setLandscapeXMm(new BigDecimal("180"));
|
position.setLandscapeYMm(new BigDecimal("40"));
|
DmsWatermarkPositionSnapshot a3 = new DmsWatermarkPositionSnapshot();
|
a3.setPaperType("A3");
|
a3.setPaperWidthMm(new BigDecimal("297"));
|
a3.setPaperHeightMm(new BigDecimal("420"));
|
a3.setPortraitXMm(new BigDecimal("10"));
|
a3.setPortraitYMm(new BigDecimal("20"));
|
a3.setLandscapeXMm(new BigDecimal("330"));
|
a3.setLandscapeYMm(new BigDecimal("60"));
|
ticket.getWatermarks().get(0).setPositions(List.of(position, a3));
|
|
for (int rotation : List.of(90, 180, 270)) {
|
boolean isA3 = rotation == 270;
|
byte[] source;
|
try (PDDocument document = new PDDocument();
|
ByteArrayOutputStream output = new ByteArrayOutputStream()) {
|
PDPage page = new PDPage(isA3 ? PDRectangle.A3 : PDRectangle.A4);
|
page.setRotation(rotation);
|
document.addPage(page);
|
document.save(output);
|
source = output.toByteArray();
|
}
|
try (PDDocument stamped = Loader.loadPDF(composer.composePreview(source, ticket))) {
|
PDFRenderer renderer = new PDFRenderer(stamped);
|
assertEquals("ROTATED", decode(renderer, 0));
|
BufferedImage image = renderer.renderImageWithDPI(0, 72);
|
int visible = 0;
|
int xMm = rotation == 180 ? 65 : isA3 ? 330 : 180;
|
int yMm = rotation == 180 ? 100 : isA3 ? 60 : 40;
|
for (int y = (int) (yMm * 72D / 25.4D); y < (int) ((yMm + 80) * 72D / 25.4D); y++) {
|
for (int x = (int) (xMm * 72D / 25.4D); x < (int) ((xMm + 80) * 72D / 25.4D); x++) {
|
if ((image.getRGB(x, y) & 0x00ffffff) < 0x00808080) visible++;
|
}
|
}
|
assertTrue("Expected barcode at landscape coordinates", visible > 0);
|
}
|
}
|
}
|
|
@Test
|
public void filtersPagesBeyondRenderedDocumentForPrintAndPreview() throws Exception {
|
DmsOnlyOfficePrintPdfComposer composer = new DmsOnlyOfficePrintPdfComposer(new OnlyOfficeProperties());
|
|
byte[] printed = composer.compose(basePdf(3), List.of(ticket("1-5", "PRINT")));
|
byte[] previewed = composer.composePreview(basePdf(3), ticket("2,4", "PREVIEW"));
|
|
try (PDDocument pdf = Loader.loadPDF(printed)) {
|
assertEquals(3, pdf.getNumberOfPages());
|
}
|
try (PDDocument pdf = Loader.loadPDF(previewed)) {
|
assertEquals(1, pdf.getNumberOfPages());
|
}
|
}
|
|
@Test(expected = DataException.class)
|
public void rejectsPrintWhenAllRequestedPagesAreBeyondRenderedDocument() throws Exception {
|
DmsOnlyOfficePrintPdfComposer composer = new DmsOnlyOfficePrintPdfComposer(new OnlyOfficeProperties());
|
|
composer.compose(basePdf(3), List.of(ticket("4-5", "PRINT")));
|
}
|
|
@Test(expected = DataException.class)
|
public void rejectsBatchOverConfiguredPageLimit() throws Exception {
|
OnlyOfficeProperties properties = new OnlyOfficeProperties();
|
properties.getDmsPrint().setMaxBatchPages(3);
|
DmsOnlyOfficePrintPdfComposer composer = new DmsOnlyOfficePrintPdfComposer(properties);
|
|
composer.compose(basePdf(3), List.of(ticket("1,3", "COPY-1"), ticket("1,3", "COPY-2")));
|
}
|
|
@Test(expected = DataException.class)
|
public void appliesBatchByteLimitToSingleCopy() throws Exception {
|
OnlyOfficeProperties properties = new OnlyOfficeProperties();
|
properties.getDmsPrint().setMaxBatchPdfBytes(1);
|
DmsOnlyOfficePrintPdfComposer composer = new DmsOnlyOfficePrintPdfComposer(properties);
|
|
composer.compose(basePdf(1), List.of(ticket("1", "COPY-1")));
|
}
|
|
private String decode(PDFRenderer renderer, int pageIndex) throws Exception {
|
BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(
|
new BufferedImageLuminanceSource(renderer.renderImageWithDPI(pageIndex, 144))));
|
return new MultiFormatReader().decode(bitmap).getText();
|
}
|
|
private byte[] basePdf(int pages) throws Exception {
|
try (PDDocument document = new PDDocument();
|
ByteArrayOutputStream output = new ByteArrayOutputStream()) {
|
for (int page = 0; page < pages; page++) document.addPage(new PDPage(PDRectangle.A4));
|
document.save(output);
|
return output.toByteArray();
|
}
|
}
|
|
private DmsFilePreviewTicket ticket(String pages, String content) {
|
DmsFilePreviewTicket ticket = new DmsFilePreviewTicket();
|
ticket.setPrintPages(pages);
|
ticket.setWatermarks(List.of(watermark(content)));
|
return ticket;
|
}
|
|
private DmsWatermarkSnapshot watermark(String content) {
|
DmsWatermarkPositionSnapshot position = new DmsWatermarkPositionSnapshot();
|
position.setPaperWidthMm(new BigDecimal("210"));
|
position.setPaperHeightMm(new BigDecimal("297"));
|
position.setPortraitXMm(new BigDecimal("65"));
|
position.setPortraitYMm(new BigDecimal("100"));
|
|
DmsWatermarkSnapshot watermark = new DmsWatermarkSnapshot();
|
watermark.setCustomBarcode(true);
|
watermark.setBarcodeFormat("QR_CODE");
|
watermark.setContent(content);
|
watermark.setShowBarcodeText(false);
|
watermark.setMarkWidthMm(new BigDecimal("80"));
|
watermark.setMarkHeightMm(new BigDecimal("80"));
|
watermark.setOpacity(100);
|
watermark.setPositions(List.of(position));
|
return watermark;
|
}
|
}
|