1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.mycore.iview2.frontend;
20
21 import java.awt.Graphics2D;
22 import java.awt.RenderingHints;
23 import java.awt.image.BufferedImage;
24 import java.io.IOException;
25 import java.io.InputStream;
26 import java.nio.file.Files;
27 import java.nio.file.Path;
28 import java.nio.file.attribute.BasicFileAttributes;
29
30 import org.apache.logging.log4j.LogManager;
31 import org.apache.logging.log4j.Logger;
32 import org.apache.pdfbox.pdmodel.PDDocument;
33 import org.apache.pdfbox.pdmodel.PDPage;
34 import org.apache.pdfbox.pdmodel.common.PDDestinationOrAction;
35 import org.apache.pdfbox.pdmodel.interactive.action.PDActionGoTo;
36 import org.apache.pdfbox.pdmodel.interactive.documentnavigation.destination.PDDestination;
37 import org.apache.pdfbox.pdmodel.interactive.documentnavigation.destination.PDPageDestination;
38 import org.apache.pdfbox.rendering.PDFRenderer;
39 import org.mycore.common.content.MCRContent;
40 import org.mycore.tools.MCRPNGTools;
41
42
43
44
45 public class MCRPDFTools implements AutoCloseable {
46
47 static final int PDF_DEFAULT_DPI = 72;
48
49 private static final Logger LOGGER = LogManager.getLogger(MCRPDFTools.class);
50
51 private final MCRPNGTools pngTools;
52
53 MCRPDFTools() {
54 this.pngTools = new MCRPNGTools();
55 }
56
57
58
59
60
61
62
63 @Deprecated
64 public static BufferedImage getThumbnail(Path pdfFile, int thumbnailSize, boolean centered) throws IOException {
65 return getThumbnail(-1, pdfFile, false);
66 }
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81 public static BufferedImage getThumbnail(int thumbnailSize, Path pdfFile, boolean centered) throws IOException {
82 InputStream fileIS = Files.newInputStream(pdfFile);
83 try (PDDocument pdf = PDDocument.load(fileIS)) {
84 PDFRenderer pdfRenderer = new PDFRenderer(pdf);
85 final PDPage page = resolveOpenActionPage(pdf);
86 BufferedImage level1Image = pdfRenderer.renderImage(pdf.getPages().indexOf(page));
87 if (thumbnailSize < 0) {
88 return level1Image;
89 }
90 return scalePage(thumbnailSize, centered, level1Image);
91 }
92 }
93
94 private static BufferedImage scalePage(int thumbnailSize, boolean centered, BufferedImage level1Image) {
95 int imageType = BufferedImage.TYPE_INT_ARGB;
96 final double width = level1Image.getWidth();
97 final double height = level1Image.getHeight();
98 LOGGER.info("new PDFBox: {}x{}", width, height);
99 LOGGER.info("temporary image dimensions: {}x{}", width, height);
100 final int newWidth = calculateNewWidth(thumbnailSize, width, height);
101 final int newHeight = calculateNewHeight(thumbnailSize, width, height);
102
103 final BufferedImage bicubicScaledPage = new BufferedImage(centered ? thumbnailSize : newWidth,
104 centered ? thumbnailSize : newHeight, imageType);
105 LOGGER.info("target image dimensions: {}x{}", bicubicScaledPage.getWidth(), bicubicScaledPage.getHeight());
106 final Graphics2D bg = bicubicScaledPage.createGraphics();
107 try {
108 bg.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC);
109 int x = centered ? (thumbnailSize - newWidth) / 2 : 0;
110 int y = centered ? (thumbnailSize - newHeight) / 2 : 0;
111 if (x != 0 && y != 0) {
112 LOGGER.warn("Writing at position {},{}", x, y);
113 }
114 bg.drawImage(level1Image, x, y, x + newWidth, y + newHeight, 0, 0, (int) Math.ceil(width),
115 (int) Math.ceil(height), null);
116 } finally {
117 bg.dispose();
118 }
119 return bicubicScaledPage;
120 }
121
122 private static int calculateNewHeight(int thumbnailSize, double width, double height) {
123 return width < height ? thumbnailSize : (int) Math.ceil(thumbnailSize * height / width);
124 }
125
126 private static int calculateNewWidth(int thumbnailSize, double width, double height) {
127 return width < height ? (int) Math.ceil(thumbnailSize * width / height) : thumbnailSize;
128 }
129
130
131
132
133
134
135
136
137
138 private static PDPage resolveOpenActionPage(PDDocument pdf) throws IOException {
139 PDDestinationOrAction openAction = pdf.getDocumentCatalog().getOpenAction();
140
141 if (openAction instanceof PDActionGoTo) {
142 final PDDestination destination = ((PDActionGoTo) openAction).getDestination();
143 if (destination instanceof PDPageDestination) {
144 openAction = destination;
145 }
146 }
147
148 if (openAction instanceof PDPageDestination) {
149 final PDPageDestination namedDestination = (PDPageDestination) openAction;
150 final PDPage pdPage = namedDestination.getPage();
151 if (pdPage != null) {
152 return pdPage;
153 } else {
154 int pageNumber = namedDestination.getPageNumber();
155 if (pageNumber != -1) {
156 return pdf.getPage(pageNumber);
157 }
158 }
159 }
160
161 return pdf.getPage(0);
162 }
163
164 MCRContent getThumnail(Path pdfFile, BasicFileAttributes attrs, int thumbnailSize, boolean centered)
165 throws IOException {
166 BufferedImage thumbnail = MCRPDFTools.getThumbnail(pdfFile, thumbnailSize, centered);
167 MCRContent pngContent = pngTools.toPNGContent(thumbnail);
168 BasicFileAttributes fattrs = attrs != null ? attrs : Files.readAttributes(pdfFile, BasicFileAttributes.class);
169 pngContent.setLastModified(fattrs.lastModifiedTime().toMillis());
170 return pngContent;
171 }
172
173 @Override
174 public void close() throws Exception {
175 this.pngTools.close();
176 }
177
178 }