zouyu
2025-11-27 eed98e551c817ead7965e08820d4b7adbc4a47f0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
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;
        }
    }