PDF-to-Image different page formats fix (#1460)
* Improve the PDF rendering process for pages of varying sizes This commit includes changes to handle the rendering of PDF documents with pages of different sizes. The updated code calculates the dimensions of each page upfront and assembles a final combined image that accommodates for the differing page dimensions. This approach avoids repetitive renderings of the same page sizes. * Refactor image preparation for Pdf to Image
This commit is contained in:
parent
3ede204918
commit
8cbb4367ab
1 changed files with 83 additions and 15 deletions
|
@ -1,27 +1,27 @@
|
||||||
package stirling.software.SPDF.utils;
|
package stirling.software.SPDF.utils;
|
||||||
|
|
||||||
import java.awt.Graphics;
|
import java.awt.*;
|
||||||
import java.awt.image.BufferedImage;
|
import java.awt.image.BufferedImage;
|
||||||
import java.awt.image.RenderedImage;
|
import java.awt.image.RenderedImage;
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Calendar;
|
import java.util.Calendar;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.zip.ZipEntry;
|
import java.util.zip.ZipEntry;
|
||||||
import java.util.zip.ZipOutputStream;
|
import java.util.zip.ZipOutputStream;
|
||||||
|
|
||||||
import javax.imageio.IIOImage;
|
import javax.imageio.*;
|
||||||
import javax.imageio.ImageIO;
|
|
||||||
import javax.imageio.ImageReader;
|
|
||||||
import javax.imageio.ImageWriteParam;
|
|
||||||
import javax.imageio.ImageWriter;
|
|
||||||
import javax.imageio.stream.ImageOutputStream;
|
import javax.imageio.stream.ImageOutputStream;
|
||||||
|
|
||||||
import org.apache.pdfbox.Loader;
|
import org.apache.pdfbox.Loader;
|
||||||
import org.apache.pdfbox.cos.COSName;
|
import org.apache.pdfbox.cos.COSName;
|
||||||
import org.apache.pdfbox.pdmodel.*;
|
import org.apache.pdfbox.pdmodel.PDDocument;
|
||||||
|
import org.apache.pdfbox.pdmodel.PDPage;
|
||||||
|
import org.apache.pdfbox.pdmodel.PDPageContentStream;
|
||||||
import org.apache.pdfbox.pdmodel.PDPageContentStream.AppendMode;
|
import org.apache.pdfbox.pdmodel.PDPageContentStream.AppendMode;
|
||||||
|
import org.apache.pdfbox.pdmodel.PDResources;
|
||||||
import org.apache.pdfbox.pdmodel.common.PDRectangle;
|
import org.apache.pdfbox.pdmodel.common.PDRectangle;
|
||||||
import org.apache.pdfbox.pdmodel.graphics.PDXObject;
|
import org.apache.pdfbox.pdmodel.graphics.PDXObject;
|
||||||
import org.apache.pdfbox.pdmodel.graphics.form.PDFormXObject;
|
import org.apache.pdfbox.pdmodel.graphics.form.PDFormXObject;
|
||||||
|
@ -245,19 +245,64 @@ public class PdfUtils {
|
||||||
writer.dispose();
|
writer.dispose();
|
||||||
} else {
|
} else {
|
||||||
// Combine all images into a single big image
|
// Combine all images into a single big image
|
||||||
BufferedImage image = pdfRenderer.renderImageWithDPI(0, DPI, colorType);
|
|
||||||
|
// Calculate the combined image dimensions
|
||||||
|
int maxWidth = 0;
|
||||||
|
int totalHeight = 0;
|
||||||
|
|
||||||
|
BufferedImage pdfSizeImage = null;
|
||||||
|
int pdfSizeImageIndex = -1;
|
||||||
|
|
||||||
|
// Using a map to store the rendered dimensions of each page size
|
||||||
|
// to avoid rendering the same page sizes multiple times
|
||||||
|
HashMap<PdfRenderSettingsKey, PdfImageDimensionValue> pageSizes =
|
||||||
|
new HashMap<>();
|
||||||
|
for (int i = 0; i < pageCount; ++i) {
|
||||||
|
PDPage page = document.getPage(i);
|
||||||
|
PDRectangle mediaBox = page.getMediaBox();
|
||||||
|
int rotation = page.getRotation();
|
||||||
|
PdfRenderSettingsKey settings =
|
||||||
|
new PdfRenderSettingsKey(
|
||||||
|
mediaBox.getWidth(), mediaBox.getHeight(), rotation);
|
||||||
|
PdfImageDimensionValue dimension = pageSizes.get(settings);
|
||||||
|
if (dimension == null) {
|
||||||
|
// Render the image to get the dimensions
|
||||||
|
pdfSizeImage = pdfRenderer.renderImageWithDPI(i, DPI, colorType);
|
||||||
|
pdfSizeImageIndex = i;
|
||||||
|
dimension =
|
||||||
|
new PdfImageDimensionValue(
|
||||||
|
pdfSizeImage.getWidth(), pdfSizeImage.getHeight());
|
||||||
|
pageSizes.put(settings, dimension);
|
||||||
|
if (pdfSizeImage.getWidth() > maxWidth) {
|
||||||
|
maxWidth = pdfSizeImage.getWidth();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
totalHeight += dimension.height();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a new BufferedImage to store the combined images
|
||||||
BufferedImage combined =
|
BufferedImage combined =
|
||||||
new BufferedImage(
|
prepareImageForPdfToImage(maxWidth, totalHeight, imageType);
|
||||||
image.getWidth(),
|
|
||||||
image.getHeight() * pageCount,
|
|
||||||
BufferedImage.TYPE_INT_RGB);
|
|
||||||
Graphics g = combined.getGraphics();
|
Graphics g = combined.getGraphics();
|
||||||
|
|
||||||
|
int currentHeight = 0;
|
||||||
|
BufferedImage pageImage;
|
||||||
|
|
||||||
|
// Check if the first image is the last rendered image
|
||||||
|
boolean firstImageAlreadyRendered = pdfSizeImageIndex == 0;
|
||||||
|
|
||||||
for (int i = 0; i < pageCount; ++i) {
|
for (int i = 0; i < pageCount; ++i) {
|
||||||
if (i != 0) {
|
if (firstImageAlreadyRendered && i == 0) {
|
||||||
image = pdfRenderer.renderImageWithDPI(i, DPI, colorType);
|
pageImage = pdfSizeImage;
|
||||||
|
} else {
|
||||||
|
pageImage = pdfRenderer.renderImageWithDPI(i, DPI, colorType);
|
||||||
}
|
}
|
||||||
g.drawImage(image, 0, i * image.getHeight(), null);
|
|
||||||
|
// Calculate the x-coordinate to center the image
|
||||||
|
int x = (maxWidth - pageImage.getWidth()) / 2;
|
||||||
|
|
||||||
|
g.drawImage(pageImage, x, currentHeight, null);
|
||||||
|
currentHeight += pageImage.getHeight();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Write the image to the output stream
|
// Write the image to the output stream
|
||||||
|
@ -296,6 +341,23 @@ public class PdfUtils {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static BufferedImage prepareImageForPdfToImage(
|
||||||
|
int maxWidth, int height, String imageType) {
|
||||||
|
BufferedImage combined;
|
||||||
|
if ("png".equalsIgnoreCase(imageType)) {
|
||||||
|
combined = new BufferedImage(maxWidth, height, BufferedImage.TYPE_INT_ARGB);
|
||||||
|
} else {
|
||||||
|
combined = new BufferedImage(maxWidth, height, BufferedImage.TYPE_INT_RGB);
|
||||||
|
}
|
||||||
|
if (!"png".equalsIgnoreCase(imageType)) {
|
||||||
|
Graphics g = combined.getGraphics();
|
||||||
|
g.setColor(Color.WHITE);
|
||||||
|
g.fillRect(0, 0, combined.getWidth(), combined.getHeight());
|
||||||
|
g.dispose();
|
||||||
|
}
|
||||||
|
return combined;
|
||||||
|
}
|
||||||
|
|
||||||
public static byte[] imageToPdf(
|
public static byte[] imageToPdf(
|
||||||
MultipartFile[] files, String fitOption, boolean autoRotate, String colorType)
|
MultipartFile[] files, String fitOption, boolean autoRotate, String colorType)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
|
@ -443,4 +505,10 @@ public class PdfUtils {
|
||||||
pdf.getDocumentInformation().setCreationDate(pdfMetadata.getCreationDate());
|
pdf.getDocumentInformation().setCreationDate(pdfMetadata.getCreationDate());
|
||||||
pdf.getDocumentInformation().setModificationDate(Calendar.getInstance());
|
pdf.getDocumentInformation().setModificationDate(Calendar.getInstance());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Key for storing the dimensions of a rendered image in a map. */
|
||||||
|
private record PdfRenderSettingsKey(float mediaBoxWidth, float mediaBoxHeight, int rotation) {}
|
||||||
|
|
||||||
|
/** Value for storing the dimensions of a rendered image in a map. */
|
||||||
|
private record PdfImageDimensionValue(int width, int height) {}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue