Support for PDF (1st page)

This commit is contained in:
Knut Forkalsrud 2023-11-11 14:37:23 -08:00
parent c46cd2e3fe
commit 6f674599da
3 changed files with 124 additions and 36 deletions

11
pom.xml
View file

@ -237,6 +237,17 @@
<version>3.9.4</version>
</dependency>
<dependency>
<groupId>org.apache.pdfbox</groupId>
<artifactId>pdfbox</artifactId>
<version>3.0.0</version>
</dependency>
<dependency>
<groupId>org.apache.pdfbox</groupId>
<artifactId>pdfbox-io</artifactId>
<version>3.0.0</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-server</artifactId>

View file

@ -6,11 +6,7 @@ import java.io.IOException;
import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Properties;
import java.util.*;
import javax.imageio.ImageIO;
import javax.imageio.ImageReadParam;
@ -19,6 +15,11 @@ import javax.imageio.stream.ImageInputStream;
import com.drew.imaging.ImageMetadataReader;
import com.drew.imaging.ImageProcessingException;
import org.apache.pdfbox.Loader;
import org.apache.pdfbox.io.RandomAccessReadBufferedFile;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.pdmodel.common.PDRectangle;
import org.forkalsrud.album.db.DirectoryProps;
import org.forkalsrud.album.video.MovieMetadataGenerator;
import org.slf4j.Logger;
@ -91,6 +92,9 @@ public class DirectoryMetadataGenerator {
} else if (name.endsWith(".mov") || name.endsWith(".MOV") || name.endsWith(".mp4") || name.endsWith(".m4v") || name.endsWith(".avi")) {
Map<String, String> p = movieMetadataGenerator.generateVideoProperties(f);
addPropsForFile(props, f, p);
} else if (name.endsWith(".pdf")) {
Map<String, String> p = generatePdfProperties(f);
addPropsForFile(props, f, p);
}
}
}
@ -229,4 +233,34 @@ public class DirectoryMetadataGenerator {
iis.close();
return new Dimension(img.getWidth(), img.getHeight());
}
private Map<String, String> generatePdfProperties(File file) throws IOException {
HashMap<String, String> props = new HashMap<>();
String name = file.getName();
props.put("etag", Integer.toHexString(name.hashCode() + Long.valueOf(file.lastModified()).hashCode()));
try (PDDocument document = Loader.loadPDF(new RandomAccessReadBufferedFile(file))) {
PDPage page = document.getPage(0);
PDRectangle rect = page.getMediaBox();
int width = Math.round(rect.getWidth());
int height = Math.round(rect.getHeight());
props.put("dimensions", new Dimension(width, height).toString());
props.put("orientation", "1");
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd-HHmmss");
Calendar cal = document.getDocumentInformation().getCreationDate();
Date date = cal != null ? cal.getTime() : new Date(file.lastModified());
props.put("captureDate", sdf.format(date));
}
return props;
}
}

View file

@ -25,6 +25,15 @@ import javax.imageio.ImageWriteParam;
import javax.imageio.ImageWriter;
import javax.imageio.stream.ImageOutputStream;
import org.apache.pdfbox.Loader;
import org.apache.pdfbox.cos.COSDocument;
import org.apache.pdfbox.io.RandomAccessRead;
import org.apache.pdfbox.io.RandomAccessReadBufferedFile;
import org.apache.pdfbox.io.RandomAccessReadMemoryMappedFile;
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.forkalsrud.album.exif.Dimension;
import org.forkalsrud.album.exif.Thumbnail;
@ -85,7 +94,10 @@ public class PictureScaler {
@Override
public CachedImage call() throws Exception {
try {
try {
if (file.getName().endsWith(".pdf")) {
return renderPdf(file, thumbnail, size);
}
return scalePictureReally(file, thumbnail, size);
} catch (Exception e) {
log.error("sadness: " + file.getAbsolutePath(), e);
@ -151,7 +163,7 @@ public class PictureScaler {
* @param size
* @throws IOException
*/
CachedImage scalePictureReally(File file, Thumbnail thumbnail, String size) throws IOException {
CachedImage scalePictureReally(File file, Thumbnail thumbnail, String size) throws IOException {
Dimension orig = thumbnail.getSize();
Dimension outd = orig.scale(size);
@ -185,46 +197,50 @@ public class PictureScaler {
// The last four are obtained by rotating 90 degrees and then flipping X and/or Y.
//
double[] flipX = new double[] { +1, -1, -1, +1, -1, +1, +1, -1 };
double[] flipY = new double[] { +1, +1, -1, -1, +1, +1, -1, -1 };
double[] flipX = new double[]{ +1, -1, -1, +1, -1, +1, +1, -1 };
double[] flipY = new double[]{ +1, +1, -1, -1, +1, +1, -1, -1 };
int idx = thumbnail.getOrientation() - 1;
// Recalculate scale after sub-sampling was applied
double scale;
AffineTransform xform = new AffineTransform();
// Recalculate scale after sub-sampling was applied
double scale;
AffineTransform xform = new AffineTransform();
boolean rotate = idx >= 4;
xform.translate(intermediate.getWidth() / 2d, intermediate.getHeight() / 2d);
if (rotate) {
xform.rotate(Math.PI / 2);
scale = (double)intermediate.getHeight() / img.getWidth();
xform.rotate(Math.PI / 2);
scale = (double) intermediate.getHeight() / img.getWidth();
} else {
scale = (double)intermediate.getWidth() / img.getWidth();
scale = (double) intermediate.getWidth() / img.getWidth();
}
xform.scale(scale, scale);
xform.scale(flipX[idx], flipY[idx]);
xform.translate(-img.getWidth() / 2d, -img.getHeight() / 2d);
int imgType = img.getType() > 0 ? img.getType() : BufferedImage.TYPE_INT_RGB;
BufferedImage buf2 = new BufferedImage(intermediate.getWidth(), intermediate.getHeight(), imgType);
Graphics2D g2 = buf2.createGraphics();
g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
int imgType = img.getType() > 0 ? img.getType() : BufferedImage.TYPE_INT_RGB;
BufferedImage buf2 = new BufferedImage(intermediate.getWidth(), intermediate.getHeight(), imgType);
Graphics2D g2 = buf2.createGraphics();
g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
g2.transform(xform);
g2.drawImage(img, 0, 0, null);
img = null;
g2.transform(xform);
g2.drawImage(img, 0, 0, null);
img = null;
while (intermediate.getWidth() > outd.getWidth()) {
while (intermediate.getWidth() > outd.getWidth()) {
BufferedImage buf3 = buf2;
intermediate = intermediate.halved();
buf2 = new BufferedImage(intermediate.getWidth(), intermediate.getHeight(), imgType);
g2 = buf2.createGraphics();
g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
g2.drawImage(buf3, 0, 0, intermediate.getWidth(), intermediate.getHeight(), null);
}
BufferedImage buf3 = buf2;
intermediate = intermediate.halved();
buf2 = new BufferedImage(intermediate.getWidth(), intermediate.getHeight(), imgType);
g2 = buf2.createGraphics();
g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
g2.drawImage(buf3, 0, 0, intermediate.getWidth(), intermediate.getHeight(), null);
}
return encoded(buf2, file.lastModified());
}
Iterator<ImageWriter> writers = ImageIO.getImageWritersByFormatName("jpg");
private CachedImage encoded(BufferedImage buf2, long lastModifiedTs) throws IOException {
Iterator<ImageWriter> writers = ImageIO.getImageWritersByFormatName("jpg");
ImageWriter writer = writers.next();
ImageWriteParam writeParam = writer.getDefaultWriteParam();
writeParam.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
@ -241,10 +257,37 @@ public class PictureScaler {
ios.flush();
CachedImage cimg = new CachedImage();
cimg.lastModified = file.lastModified();
cimg.lastModified = lastModifiedTs;
cimg.mimeType = "image/jpeg";
cimg.bits = bits.toByteArray();
return cimg;
}
CachedImage renderPdf(File file, Thumbnail thumbnail, String size) throws IOException {
Dimension orig = thumbnail.getSize();
Dimension dim = orig.scale(size);
try (PDDocument document = Loader.loadPDF(new RandomAccessReadBufferedFile(file))) {
PDPage page = document.getPage(0);
PDRectangle rect = page.getMediaBox();
float width = rect.getWidth() / 72; // inches
float targetWidth = dim.getWidth(); // pixels
PDFRenderer renderer = new PDFRenderer(document);
BufferedImage image = renderer.renderImageWithDPI(0, targetWidth / width);
return encoded(image, file.lastModified());
}
}
}