문제점
웹 프로젝트에서 PDF 문서를 표시해야 할 때가 있습니다. 하지만 브라우저에 PDF 플러그인을 직접 추가하는 경우, 호환성 문제가 발생하여 특정 브라우저에서 제대로 표시되지 않는 문제가 있습니다. 이럴 때 PDF를 이미지로 변환하여 표시하면 훨씬 더 안정적인 결과를 얻을 수 있습니다.
PDF를 이미지로 변환하는 방법은 주로 두 가지가 있습니다:
| 제품 | 특징 |
|---|---|
| Apache PDFBox | 무료; 속도는 다소 느리지만 사용 가능한 수준 |
| E-iceblue Spire.PDF for Java | 변환 품질 우수; 빠른 속도; 다양한 형식 지원; 유료 |
참고: Spire.PDF for Java는 변환 품질이 우수하지만, 라이선스를 구매하지 않으면 변환된 이미지에 워터마크가 추가됩니다.
PDFBox 사용 방법
의존성 추가
<dependency>
<groupId>org.apache.pdfbox</groupId>
<artifactId>pdfbox</artifactId>
<version>2.0.24</version>
</dependency>
<dependency>
<groupId>org.apache.pdfbox</groupId>
<artifactId>pdfbox-tools</artifactId>
<version>2.0.24</version>
</dependency>
다중 페이지 PDF를 여러 이미지로 변환
다음은 PdfUtil 도구 클래스를 생성하여 PDF를 이미지로 변환하는 예제입니다:
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.rendering.PDFRenderer;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
public class PdfConverter {
private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(PdfConverter.class);
/**
* PDF 파일을 PNG 이미지로 변환 (모든 페이지)
*
* @param pdfFilePath PDF 파일의 전체 경로
* @param dpi DPI가 높을수록 변환된 이미지가 더 선명하지만 변환 속도는 느려집니다
*/
public static void convertPdfToImages(String pdfFilePath, int dpi) {
File file = new File(pdfFilePath);
try {
String imgDirectory = file.getParent();
int dotIndex = file.getName().lastIndexOf('.');
// 이미지 파일명 생성
String baseImageName = file.getName().substring(0, dotIndex);
PDDocument document = PDDocument.load(file);
PDFRenderer renderer = new PDFRenderer(document);
// 총 페이지 수 확인
int totalPages = document.getNumberOfPages();
for (int i = 0; i < totalPages; i++) {
String imagePath = imgDirectory + File.separator + baseImageName +
"_" + (i + 1) + ".png";
File outputFile = new File(imagePath);
BufferedImage image = renderer.renderImageWithDPI(i, dpi);
ImageIO.write(image, "png", outputFile);
}
document.close();
log.info("PDF 문서가 PNG 이미지로 성공적으로 변환되었습니다!");
} catch (IOException e) {
log.error("PDF 변환 중 오류 발생", e);
}
}
}
다중 페이지 PDF를 단일 이미지로 결합
다음은 여러 페이지 PDF를 단일 이미지로 결합하는 방법입니다:
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.rendering.ImageType;
import org.apache.pdfbox.rendering.PDFRenderer;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
public class PdfConverter {
public static final int DEFAULT_DPI = 150;
/**
* PDF를 이미지로 변환
* 다중 페이지 PDF는 각 페이지를 별도 이미지로 변환 후 단일 이미지로 결합
*
* @param pdfFile PDF 파일 경로
* @param outputImagePath 이미지 출력 경로
* @param dpi 이미지 해상도에 해당하는 값, 값이 클수록 선명하지만 변환 시간이 증가
*/
public static void convertPdfToSingleImage(String pdfFile, String outputImagePath, Integer dpi) {
if (dpi == null) {
// DPI가 설정되지 않은 경우 기값으로 150 설정
dpi = DEFAULT_DPI;
}
try (PDDocument pdf = PDDocument.load(new FileInputStream(pdfFile))) {
int pageCount = pdf.getNumberOfPages();
List<BufferedImage> imageList = new ArrayList<>();
// 각 페이지를 이미지로 변환
for (int i = 0; i < pageCount; i++) {
BufferedImage image = new PDFRenderer(pdf)
.renderImageWithDPI(i, dpi, ImageType.RGB);
imageList.add(image);
}
// 이미지들을 하나로 결합
ImageCombiner.combineImagesVertically(imageList, outputImagePath);
} catch (IOException e) {
log.error("PDF 변환 중 오류 발생", e);
}
}
}
ImageCombiner 클래스
이미지들을 결합하는 ImageCombiner 클래스입니다:
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.List;
public class ImageCombiner {
private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(ImageCombiner.class);
/**
* 너비가 동일한 이미지들을 세로로 결합합니다
*
* @param images 이미지 리스트
* @param outputPath 출력 경로
*/
public static void combineImagesVertically(List<BufferedImage> images, String outputPath) {
if (images == null || images.isEmpty()) {
log.info("이미지 리스트가 비어있습니다!");
return;
}
try {
int totalHeight = 0;
int width = 0;
int[] heights = new int[images.size()];
// 총 너비와 높이 계산
for (int i = 0; i < images.size(); i++) {
BufferedImage img = images.get(i);
heights[i] = img.getHeight();
if (i == 0) {
width = img.getWidth();
}
totalHeight += heights[i];
}
// 새로운 이미지 생성
BufferedImage resultImage = new BufferedImage(width, totalHeight, BufferedImage.TYPE_INT_RGB);
int currentHeight = 0;
// 각 이미지를 결과 이미지에 병합
for (int i = 0; i < images.size(); i++) {
BufferedImage img = images.get(i);
int imgHeight = heights[i];
// 이미지 데이터를 결과 이미지에 설정
resultImage.setRGB(0, currentHeight, width, imgHeight,
img.getRGB(0, 0, width, imgHeight, null, 0, width), 0, width);
currentHeight += imgHeight;
}
// 결과 이미지 파일로 저장
File outputFile = new File(outputPath);
ImageIO.write(resultImage, "png", outputFile);
log.info("이미지가 성공적으로 결합되었습니다: " + outputPath);
} catch (IOException e) {
log.error("이미지 결합 중 오류 발생", e);
}
}
}