package com.xindao.ocr.swingui.swing.jpanel;
|
|
import org.apache.pdfbox.pdmodel.PDDocument;
|
import org.apache.pdfbox.rendering.PDFRenderer;
|
|
import javax.swing.*;
|
import java.awt.*;
|
import java.awt.event.MouseAdapter;
|
import java.awt.event.MouseEvent;
|
import java.awt.event.MouseMotionAdapter;
|
import java.awt.geom.AffineTransform;
|
import java.awt.geom.Rectangle2D;
|
import java.awt.image.BufferedImage;
|
import java.io.IOException;
|
|
public class PdfPreviewPanel extends JPanel {
|
private PDDocument document;
|
private int pageNumber;
|
private BufferedImage pageImage;
|
private Rectangle2D selection = null;
|
private Rectangle2D lastSelection = null; // 上次选择的区域
|
private Point startDrag = null;
|
private float scale = 1.0f;
|
private Point translation = new Point(0, 0); // 平移量
|
private Point lastDragPoint = null;
|
private float pdfWidth;
|
private float pdfHeight;
|
private boolean isDraggingPage = false; // 是否正在拖拽页面
|
|
private static final Color SELECTION_COLOR = new Color(255, 193, 7, 100); // 半透明黄色
|
private static final Color LAST_SELECTION_COLOR = new Color(76, 175, 80, 100); // 半透明绿色,用于标识上次选择的区域
|
|
public PdfPreviewPanel(PDDocument doc, int pageNum, Rectangle2D lastArea) throws IOException {
|
this.document = doc;
|
this.pageNumber = pageNum;
|
this.lastSelection = lastArea;
|
|
// 渲染PDF页面为图片
|
PDFRenderer renderer = new PDFRenderer(doc);
|
pageImage = renderer.renderImage(pageNumber);
|
|
// 获取PDF页面尺寸
|
pdfWidth = pageImage.getWidth();
|
pdfHeight = pageImage.getHeight();
|
|
// 如果有上次选择的区域,默认选中
|
if (lastSelection != null) {
|
this.selection = lastSelection;
|
}
|
|
// 添加鼠标监听器处理选择和拖拽
|
addMouseListener(new MouseAdapter() {
|
@Override
|
public void mousePressed(MouseEvent e) {
|
// 检查点击位置是否在PDF页面上
|
Rectangle2D pageBounds = getPageBounds();
|
if (pageBounds.contains(e.getPoint())) {
|
// 检查是否点击在选择区域内
|
if (selection != null && selection.contains(e.getPoint())) {
|
startDrag = e.getPoint();
|
isDraggingPage = false;
|
} else {
|
// 开始新的选择
|
startDrag = e.getPoint();
|
selection = null;
|
isDraggingPage = false;
|
}
|
} else {
|
// 点击在页面外,准备拖拽整个页面
|
lastDragPoint = e.getPoint();
|
isDraggingPage = true;
|
}
|
repaint();
|
}
|
|
@Override
|
public void mouseReleased(MouseEvent e) {
|
startDrag = null;
|
lastDragPoint = null;
|
isDraggingPage = false;
|
repaint();
|
}
|
});
|
|
addMouseMotionListener(new MouseMotionAdapter() {
|
@Override
|
public void mouseDragged(MouseEvent e) {
|
if (isDraggingPage && lastDragPoint != null) {
|
// 拖拽整个页面
|
int dx = e.getX() - lastDragPoint.x;
|
int dy = e.getY() - lastDragPoint.y;
|
translation.x += dx;
|
translation.y += dy;
|
lastDragPoint = e.getPoint();
|
repaint();
|
} else if (startDrag != null) {
|
// 拖拽选择区域
|
Point endDrag = e.getPoint();
|
selection = createRectangle(startDrag, endDrag);
|
repaint();
|
}
|
}
|
});
|
|
// 设置面板首选大小
|
setPreferredSize(new Dimension(pageImage.getWidth(), pageImage.getHeight()));
|
}
|
|
// 获取PDF页面在面板中的边界
|
private Rectangle2D getPageBounds() {
|
return new Rectangle2D.Double(
|
translation.getX(),
|
translation.getY(),
|
pageImage.getWidth() * scale,
|
pageImage.getHeight() * scale
|
);
|
}
|
|
private Rectangle2D createRectangle(Point p1, Point p2) {
|
int x = Math.min(p1.x, p2.x);
|
int y = Math.min(p1.y, p2.y);
|
int width = Math.abs(p1.x - p2.x);
|
int height = Math.abs(p1.y - p2.y);
|
return new Rectangle2D.Double(x, y, width, height);
|
}
|
|
@Override
|
protected void paintComponent(Graphics g) {
|
super.paintComponent(g);
|
Graphics2D g2 = (Graphics2D) g;
|
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
|
g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
|
|
// 绘制背景
|
g2.setColor(new Color(240, 240, 240));
|
g2.fillRect(0, 0, getWidth(), getHeight());
|
|
// 绘制PDF页面
|
if (pageImage != null) {
|
// 保存当前变换
|
AffineTransform originalTransform = g2.getTransform();
|
|
// 应用平移和缩放
|
g2.translate(translation.x, translation.y);
|
g2.scale(scale, scale);
|
|
// 绘制PDF图像
|
g2.drawImage(pageImage, 0, 0, null);
|
|
// 绘制上次选择的区域(如果有)
|
if (lastSelection != null && (selection == null || !selection.equals(lastSelection))) {
|
g2.setColor(LAST_SELECTION_COLOR);
|
g2.fill(lastSelection);
|
g2.setColor(new Color(76, 175, 80));
|
g2.setStroke(new BasicStroke(1));
|
g2.draw(lastSelection);
|
}
|
|
// 绘制当前选择区域
|
if (selection != null) {
|
// 转换选择区域坐标到PDF坐标系统
|
Rectangle2D pdfSelection = new Rectangle2D.Double(
|
selection.getX() - translation.x,
|
selection.getY() - translation.y,
|
selection.getWidth(),
|
selection.getHeight()
|
);
|
pdfSelection = new Rectangle2D.Double(
|
pdfSelection.getX() / scale,
|
pdfSelection.getY() / scale,
|
pdfSelection.getWidth() / scale,
|
pdfSelection.getHeight() / scale
|
);
|
|
g2.setColor(SELECTION_COLOR);
|
g2.fill(pdfSelection);
|
g2.setColor(Color.ORANGE);
|
g2.setStroke(new BasicStroke(2));
|
g2.draw(pdfSelection);
|
}
|
|
// 恢复变换
|
g2.setTransform(originalTransform);
|
}
|
}
|
|
public Rectangle2D getSelection() {
|
return selection;
|
}
|
|
public float getScale() {
|
return scale;
|
}
|
|
public Point getTranslation() {
|
return translation;
|
}
|
|
public float getPdfHeight() {
|
return pdfHeight;
|
}
|
}
|