package com.xindao.ocr.swingui.swing.jpanel;
|
|
import com.alibaba.excel.EasyExcel;
|
import com.alibaba.excel.support.ExcelTypeEnum;
|
import com.xindao.ocr.swingui.constant.OcrSwingConstants;
|
import com.xindao.ocr.swingui.excel.ContractNumberExcelData;
|
import com.xindao.ocr.swingui.service.OcrService;
|
import com.xindao.ocr.swingui.swing.FileProcessorApp;
|
import com.xindao.ocr.swingui.swing.utils.FileNameValidator;
|
import com.xindao.ocr.swingui.swing.utils.GenerateCustomizeComponent;
|
import com.xindao.ocr.swingui.swing.utils.ToFile;
|
import org.apache.commons.lang3.StringUtils;
|
import org.apache.pdfbox.pdmodel.PDDocument;
|
import org.apache.pdfbox.rendering.PDFRenderer;
|
import org.apache.pdfbox.util.filetypedetector.FileType;
|
import org.apache.poi.util.IOUtils;
|
|
import javax.swing.*;
|
import javax.swing.border.CompoundBorder;
|
import javax.swing.border.EmptyBorder;
|
import javax.swing.border.LineBorder;
|
import javax.swing.filechooser.FileFilter;
|
import java.awt.*;
|
import java.awt.geom.Rectangle2D;
|
import java.awt.image.BufferedImage;
|
import java.io.File;
|
import java.io.IOException;
|
import java.nio.file.Files;
|
import java.time.LocalDate;
|
import java.time.format.DateTimeFormatter;
|
import java.util.*;
|
import java.util.List;
|
import java.util.concurrent.CopyOnWriteArrayList;
|
import java.util.concurrent.atomic.AtomicInteger;
|
import java.util.prefs.Preferences;
|
|
/**
|
* 合同编号处理面板
|
*/
|
public class ContractNumberProcessPanel {
|
|
private final OcrService ocrService;
|
private final List<File> selectedFiles = new ArrayList<>();
|
private final Preferences prefs;
|
private final Font DEFAULT_FONT;
|
|
private JTextArea logArea;
|
private JLabel filesLabel;
|
private JLabel outputDirLabel;
|
private JLabel lastSelectionLabel; // 新增:用于显示上次选择信息的标签
|
private File outputDirectory;
|
|
private final Color BACKGROUND_COLOR;
|
private final Color PRIMARY_COLOR;
|
private final Color TEXT_COLOR;
|
private final Color TEXT_LIGHT;
|
|
|
// PDF区域选择相关的偏好设置键
|
private static final String PREF_PDF_PAGE = "lastPdfPage";
|
private static final String PREF_PDF_X = "lastPdfX";
|
private static final String PREF_PDF_Y = "lastPdfY";
|
private static final String PREF_PDF_WIDTH = "lastPdfWidth";
|
private static final String PREF_PDF_HEIGHT = "lastPdfHeight";
|
|
private final FileProcessorApp supper;
|
|
AtomicInteger fileIndex = new AtomicInteger(1);
|
|
public ContractNumberProcessPanel(
|
Color BACKGROUND_COLOR,
|
Color PRIMARY_COLOR,
|
Color TEXT_COLOR,
|
Color TEXT_LIGHT,
|
Font font,
|
FileProcessorApp supper,
|
OcrService ocrService){
|
this.BACKGROUND_COLOR = BACKGROUND_COLOR;
|
this.PRIMARY_COLOR = PRIMARY_COLOR;
|
this.TEXT_COLOR = TEXT_COLOR;
|
this.TEXT_LIGHT = TEXT_LIGHT;
|
|
this.DEFAULT_FONT = font;
|
this.supper = supper;
|
this.ocrService = ocrService;
|
this.prefs = Preferences.userNodeForPackage(ContractNumberProcessPanel.class);
|
|
}
|
|
public JPanel initPanel() {
|
// 初始化面板
|
// 第一个标签页:文件处理和日志(合并到一个标签页)
|
JPanel mainTab = new JPanel(new BorderLayout(15, 15));
|
mainTab.setBorder(new EmptyBorder(15, 15, 15, 15));
|
mainTab.setBackground(BACKGROUND_COLOR);
|
|
// 顶部卡片:文件选择区域
|
JPanel topCard = GenerateCustomizeComponent.createCardPanel();
|
topCard.setLayout(new BoxLayout(topCard, BoxLayout.Y_AXIS));
|
topCard.setBorder(new EmptyBorder(20, 20, 20, 20));
|
|
// 添加标题 - 修改为居中显示
|
JPanel titlePanel = new JPanel(new GridBagLayout());
|
titlePanel.setOpaque(false);
|
JLabel titleLabel = new JLabel("合同编号识别");
|
titleLabel.setFont(new Font(DEFAULT_FONT.getName(), Font.BOLD, 18));
|
titleLabel.setForeground(PRIMARY_COLOR);
|
titleLabel.setBorder(new EmptyBorder(0, 0, 15, 0));
|
titlePanel.add(titleLabel);
|
|
topCard.add(titlePanel);
|
topCard.add(Box.createVerticalStrut(10));
|
|
// 文件选择区域
|
JPanel fileSelectionPanel = GenerateCustomizeComponent.createStyledPanel(new FlowLayout(FlowLayout.LEFT, 10, 10));
|
JButton selectFilesBtn = GenerateCustomizeComponent.createStyledButton("选择文件...",DEFAULT_FONT);
|
filesLabel = new JLabel("未选择文件");
|
filesLabel.setFont(DEFAULT_FONT);
|
filesLabel.setForeground(TEXT_COLOR);
|
fileSelectionPanel.add(selectFilesBtn);
|
fileSelectionPanel.add(filesLabel);
|
|
// 输出目录选择区域
|
JPanel outputDirPanel = GenerateCustomizeComponent.createStyledPanel(new FlowLayout(FlowLayout.LEFT, 10, 10));
|
JButton selectOutputDirBtn = GenerateCustomizeComponent.createStyledButton("选择输出目录...",DEFAULT_FONT);
|
outputDirLabel = new JLabel("未选择输出目录");
|
outputDirLabel.setFont(DEFAULT_FONT);
|
outputDirLabel.setForeground(TEXT_COLOR);
|
outputDirPanel.add(selectOutputDirBtn);
|
outputDirPanel.add(outputDirLabel);
|
|
// PDF区域选择按钮和上次选择信息 - 修改为一行显示
|
JPanel pdfSelectionPanel = GenerateCustomizeComponent.createStyledPanel(new FlowLayout(FlowLayout.LEFT, 10, 10));
|
JButton selectPdfAreaBtn = GenerateCustomizeComponent.createStyledButton("选择PDF区域...",DEFAULT_FONT);
|
pdfSelectionPanel.add(selectPdfAreaBtn);
|
|
// 上次选择的PDF区域信息 - 使用成员变量引用
|
lastSelectionLabel = new JLabel("上次选择: 无");
|
lastSelectionLabel.setFont(DEFAULT_FONT);
|
lastSelectionLabel.setForeground(TEXT_LIGHT);
|
pdfSelectionPanel.add(lastSelectionLabel);
|
|
// 处理按钮
|
JPanel processBtnPanel = GenerateCustomizeComponent.createStyledPanel(new FlowLayout(FlowLayout.CENTER, 0, 15));
|
JButton processBtn = GenerateCustomizeComponent.createPrimaryButton("处理文件",DEFAULT_FONT);
|
processBtnPanel.add(processBtn);
|
|
// 添加到顶部卡片
|
topCard.add(fileSelectionPanel);
|
topCard.add(Box.createVerticalStrut(10));
|
topCard.add(outputDirPanel);
|
topCard.add(Box.createVerticalStrut(10));
|
topCard.add(pdfSelectionPanel);
|
topCard.add(Box.createVerticalStrut(15));
|
topCard.add(processBtnPanel);
|
|
// 底部卡片:日志区域
|
JPanel bottomCard = GenerateCustomizeComponent.createCardPanel();
|
bottomCard.setLayout(new BorderLayout());
|
bottomCard.setBorder(new EmptyBorder(15, 15, 15, 15));
|
|
|
JLabel logTitleLabel = new JLabel("处理日志");
|
logTitleLabel.setFont(new Font(DEFAULT_FONT.getName(), Font.BOLD, 14));
|
logTitleLabel.setForeground(TEXT_COLOR);
|
logTitleLabel.setBorder(new EmptyBorder(0, 0, 10, 0));
|
|
logArea = new JTextArea();
|
logArea.setEditable(false);
|
logArea.setLineWrap(true);
|
logArea.setSize(-1,100);
|
logArea.setFont(DEFAULT_FONT);
|
logArea.setBackground(new Color(250, 250, 250));
|
logArea.setBorder(new CompoundBorder(
|
new LineBorder(new Color(220, 220, 220)),
|
new EmptyBorder(5, 5, 5, 5)
|
));
|
|
JScrollPane scrollPane = new JScrollPane(logArea);
|
scrollPane.setBorder(null);
|
scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
|
|
bottomCard.add(logTitleLabel, BorderLayout.NORTH);
|
bottomCard.add(scrollPane, BorderLayout.CENTER);
|
|
// 添加顶部卡片和底部卡片到主标签页
|
mainTab.add(topCard, BorderLayout.NORTH);
|
mainTab.add(bottomCard, BorderLayout.CENTER);
|
|
// 添加事件监听器
|
selectFilesBtn.addActionListener(e -> selectFiles());
|
selectOutputDirBtn.addActionListener(e -> selectOutputDirectory());
|
processBtn.addActionListener(e -> processFiles());
|
selectPdfAreaBtn.addActionListener(e -> selectPdfArea());
|
|
|
loadLastPaths();
|
showLastPdfSelectionInfo();
|
|
return mainTab;
|
}
|
|
private void selectFiles() {
|
JFileChooser fileChooser = new JFileChooser();
|
setComponentFont(fileChooser, DEFAULT_FONT);
|
|
String lastFilePath = prefs.get("lastFilepath", "");
|
if (!lastFilePath.isEmpty()) {
|
File lastFile = new File(lastFilePath);
|
if (lastFile.exists()) {
|
fileChooser.setCurrentDirectory(lastFile.getParentFile());
|
}
|
}
|
|
fileChooser.setMultiSelectionEnabled(true);
|
fileChooser.setDialogTitle("选择要处理的文件");
|
styleFileChooser(fileChooser);
|
|
int result = fileChooser.showOpenDialog(supper);
|
if (result == JFileChooser.APPROVE_OPTION) {
|
selectedFiles.clear();
|
File[] files = fileChooser.getSelectedFiles();
|
selectedFiles.addAll(Arrays.asList(files));
|
filesLabel.setText("已选择 " + selectedFiles.size() + " 个文件");
|
log("已选择 " + selectedFiles.size() + " 个文件");
|
|
if (files.length > 0) {
|
prefs.put("lastFilepath", files[0].getAbsolutePath());
|
}
|
}
|
}
|
|
private void setComponentFont(Component component, Font font) {
|
component.setFont(font);
|
if (component instanceof Container) {
|
for (Component child : ((Container) component).getComponents()) {
|
setComponentFont(child, font);
|
}
|
}
|
}
|
|
// 美化文件选择器
|
private void styleFileChooser(JFileChooser chooser) {
|
chooser.setBackground(BACKGROUND_COLOR);
|
chooser.setForeground(TEXT_COLOR);
|
|
// 设置按钮样式
|
for (Component comp : chooser.getComponents()) {
|
if (comp instanceof JButton) {
|
JButton btn = (JButton) comp;
|
btn.setFont(DEFAULT_FONT);
|
btn.setBorder(new EmptyBorder(5, 10, 5, 10));
|
btn.setFocusPainted(false);
|
}
|
setComponentFont(comp, DEFAULT_FONT);
|
}
|
}
|
|
private void selectOutputDirectory() {
|
JFileChooser dirChooser = new JFileChooser();
|
setComponentFont(dirChooser, DEFAULT_FONT);
|
|
String lastDirPath = prefs.get("lastOutputDir", "");
|
if (!lastDirPath.isEmpty()) {
|
File lastDir = new File(lastDirPath);
|
if (lastDir.exists() && lastDir.isDirectory()) {
|
dirChooser.setCurrentDirectory(lastDir);
|
}
|
}
|
|
dirChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
|
dirChooser.setDialogTitle("选择输出目录");
|
styleFileChooser(dirChooser);
|
|
int result = dirChooser.showOpenDialog(supper);
|
if (result == JFileChooser.APPROVE_OPTION) {
|
outputDirectory = dirChooser.getSelectedFile();
|
outputDirLabel.setText(outputDirectory.getAbsolutePath());
|
log("已选择输出目录: " + outputDirectory.getAbsolutePath());
|
|
prefs.put("lastOutputDir", outputDirectory.getAbsolutePath());
|
}
|
}
|
|
/**
|
* 输出文件
|
* @param newFileName 新文件名
|
* @param file 源文件
|
* @param fileSuffix 文件后缀
|
* @param targetPath 目标路径
|
*/
|
private void writeFile(String newFileName,File file,String fileSuffix,File targetPath) throws IOException {
|
String outputFileName = newFileName + fileSuffix;
|
File outputFile = new File(targetPath, outputFileName);
|
if (!outputFile.getParentFile().exists()) {
|
outputFile.getParentFile().mkdirs();
|
}
|
IOUtils.copy(Files.newInputStream(file.toPath()),outputFile);
|
}
|
|
/**
|
* 处理合同编号方法
|
*/
|
private void processFiles() {
|
if (selectedFiles.isEmpty()) {
|
JOptionPane.showMessageDialog(supper, "请先选择要处理的文件", "提示", JOptionPane.WARNING_MESSAGE);
|
return;
|
}
|
|
if (outputDirectory == null || !outputDirectory.exists()) {
|
JOptionPane.showMessageDialog(supper, "请先选择有效的输出目录", "提示", JOptionPane.WARNING_MESSAGE);
|
return;
|
}
|
|
log("开始处理文件...");
|
//识别到的合同编号列表
|
final List<ContractNumberExcelData> contractNumberList = new CopyOnWriteArrayList<>();
|
|
new Thread(() -> {
|
int successCount = 0;
|
int failCount = 0;
|
int processCount = 0;
|
|
for (File file : selectedFiles) {
|
processCount++;
|
//获取识别到的第一个内容
|
String text = file.getName().replace(".pdf","");
|
try {
|
//截取pdf选区图像
|
String pathStr = capturePdfArea(file, prefs);
|
// ToFile.preprocessImage(pathStr);
|
//读取图像内容
|
String ocrFullText = FileNameValidator.validateAndCleanFileName(ocrService.ocr(pathStr.replaceFirst("/", "")));
|
if(StringUtils.isNotBlank(ocrFullText) && !StringUtils.equals(ocrFullText,text)){
|
text = ocrFullText;
|
String finalText = text;
|
//如果合同编号重复,则在文件名后加一个序号
|
if(contractNumberList.stream().anyMatch(f -> f.getContractNumber().equals(finalText))){
|
text+="("+ fileIndex.get() +")";
|
fileIndex.getAndIncrement();
|
}
|
//将识别的内容设置为文件名,导出到指定目录
|
writeFile(text,file, ".pdf",outputDirectory);
|
}
|
successCount++;
|
contractNumberList.add(new ContractNumberExcelData(text));
|
log("处理成功("+processCount+"/"+selectedFiles.size()+"): " + file.getName());
|
} catch (Exception e) {
|
failCount++;
|
e.printStackTrace();
|
log("处理失败: " + file.getName() + " - " + e.getMessage());
|
//处理失败的文件也输出
|
try {
|
writeFile(text+"_fail", file, ".pdf",outputDirectory);
|
} catch (IOException ex) {
|
throw new RuntimeException(ex);
|
}
|
}finally {
|
//删除临时目录
|
ToFile.deleteTempFiles(OcrSwingConstants.cacheDir);
|
}
|
}
|
|
//导出识别到的合同编号列表
|
try {
|
String outputExcelFileName = "合同编号列表_" + LocalDate.now().format(DateTimeFormatter.ofPattern("yyyyMMdd")) + ExcelTypeEnum.XLSX.getValue();
|
File outputExcelFile = new File(outputDirectory, outputExcelFileName);
|
if (!outputExcelFile.getParentFile().exists()) {
|
outputExcelFile.getParentFile().mkdirs();
|
}
|
EasyExcel.write(outputExcelFile, ContractNumberExcelData.class).sheet().doWrite(contractNumberList);
|
log("文件已导出到: " + outputExcelFile.getAbsolutePath());
|
} catch (Exception e) {
|
log("导出合同编号列表失败: " + e.getMessage());
|
}
|
|
log("处理完成 - 成功: " + successCount + ", 失败: " + failCount);
|
int finalSuccessCount = successCount;
|
int finalFailCount = failCount;
|
SwingUtilities.invokeLater(() ->
|
JOptionPane.showMessageDialog(supper,
|
"处理完成\n成功: " + finalSuccessCount + "\n失败: " + finalFailCount,
|
"处理结果", JOptionPane.INFORMATION_MESSAGE)
|
);
|
}).start();
|
}
|
|
// 加载上次的PDF区域选择信息
|
private Map<String, Object> loadLastPdfSelectionInfo() {
|
Map<String, Object> info = new HashMap<>();
|
|
int pageNumber = prefs.getInt(PREF_PDF_PAGE, 0);
|
float x = prefs.getFloat(PREF_PDF_X, 0);
|
float y = prefs.getFloat(PREF_PDF_Y, 0);
|
float width = prefs.getFloat(PREF_PDF_WIDTH, 0);
|
float height = prefs.getFloat(PREF_PDF_HEIGHT, 0);
|
|
info.put("page", pageNumber);
|
info.put("x", x);
|
info.put("y", y);
|
info.put("width", width);
|
info.put("height", height);
|
|
return info;
|
}
|
|
// PDF区域选择功能
|
private void selectPdfArea() {
|
// 检查是否有上次选择的PDF信息
|
Map<String, Object> lastSelection = loadLastPdfSelectionInfo();
|
File pdfFile = null;
|
int defaultPage = 0;
|
boolean hasReSelection = true;
|
// 如果有上次选择的信息,询问用户是否使用
|
if (!lastSelection.isEmpty()) {
|
int option = JOptionPane.showConfirmDialog(supper,
|
"是否使用上次选择的区域?",
|
"上次选择", JOptionPane.YES_NO_OPTION);
|
|
if (option == JOptionPane.YES_OPTION) {
|
hasReSelection = false; // 用户选择使用上次的文件
|
}
|
}
|
|
// 如果没有上次选择的文件或用户不使用上次的文件,则让用户选择新文件
|
if (hasReSelection) {
|
JFileChooser fileChooser = new JFileChooser();
|
setComponentFont(fileChooser, DEFAULT_FONT);
|
styleFileChooser(fileChooser);
|
|
// 过滤只显示PDF文件
|
fileChooser.setFileFilter(new FileFilter() {
|
@Override
|
public boolean accept(File f) {
|
return f.isDirectory() || f.getName().toLowerCase().endsWith(".pdf");
|
}
|
|
@Override
|
public String getDescription() {
|
return "PDF文件 (*.pdf)";
|
}
|
});
|
|
fileChooser.setDialogTitle("选择PDF文件");
|
|
int result = fileChooser.showOpenDialog(supper);
|
if (result != JFileChooser.APPROVE_OPTION) {
|
return;
|
}
|
|
pdfFile = fileChooser.getSelectedFile();
|
if (!pdfFile.getName().toLowerCase().endsWith(".pdf")) {
|
JOptionPane.showMessageDialog(supper, "请选择PDF文件", "提示", JOptionPane.WARNING_MESSAGE);
|
return;
|
}
|
|
// 加载PDF并显示选择面板
|
try (PDDocument document = PDDocument.load(Files.newInputStream(pdfFile.toPath()))) {
|
int totalPages = document.getNumberOfPages();
|
// 默认第一页
|
// 让用户输入页码,默认使用上次的页码
|
String pageStr = JOptionPane.showInputDialog(supper,
|
"请输入要选择区域的页码(共"+totalPages+"页):",
|
"输入页码",
|
JOptionPane.PLAIN_MESSAGE,
|
null,
|
null,
|
String.valueOf(defaultPage + 1)).toString();
|
|
if (pageStr == null || pageStr.trim().isEmpty()) {
|
return;
|
}
|
|
int pageNumber;
|
try {
|
pageNumber = Integer.parseInt(pageStr.trim()) - 1; // PDFBox页码从0开始
|
} catch (NumberFormatException e) {
|
JOptionPane.showMessageDialog(supper, "请输入有效的页码", "错误", JOptionPane.ERROR_MESSAGE);
|
return;
|
}
|
if (pageNumber < 0 || pageNumber >= totalPages) {
|
JOptionPane.showMessageDialog(supper, "页码超出范围", "错误", JOptionPane.ERROR_MESSAGE);
|
return;
|
}
|
|
// 获取PDF页面尺寸
|
float pdfWidth = document.getPage(pageNumber).getMediaBox().getWidth();
|
float pdfHeight = document.getPage(pageNumber).getMediaBox().getHeight();
|
|
// 获取上次选择的区域(如果存在且是当前文件和页面)
|
Rectangle2D lastArea = null;
|
if (!lastSelection.isEmpty() && pageNumber == (int)lastSelection.get("page")) {
|
float x = (float)lastSelection.get("x");
|
float y = (float)lastSelection.get("y");
|
float width = (float)lastSelection.get("width");
|
float height = (float)lastSelection.get("height");
|
|
// 转换为PDF坐标系统的区域(未缩放的)
|
lastArea = new Rectangle2D.Float(x, y, width, height);
|
}
|
|
// 创建PDF预览和区域选择对话框
|
JDialog pdfDialog = new JDialog(supper, "选择PDF识别区域 - " + pdfFile.getName(), true);
|
pdfDialog.setSize(639, 850);
|
pdfDialog.setLocationRelativeTo(supper);
|
|
// 创建PDF预览面板,传入上次选择的区域
|
PdfPreviewPanel previewPanel = new PdfPreviewPanel(document, pageNumber, lastArea);
|
// 创建可滚动的PDF预览面板
|
JScrollPane scrollablePreview = new JScrollPane(previewPanel);
|
scrollablePreview.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
|
scrollablePreview.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED);
|
scrollablePreview.setPreferredSize(new Dimension(599, 750));
|
scrollablePreview.getVerticalScrollBar().setUnitIncrement(16); // 设置滚动速度
|
scrollablePreview.setBorder(BorderFactory.createEtchedBorder());
|
pdfDialog.add(scrollablePreview, BorderLayout.CENTER);
|
|
// 创建底部按钮面板
|
JPanel buttonPanel = new JPanel();
|
JButton confirmBtn = GenerateCustomizeComponent.createPrimaryButton("确认选择",DEFAULT_FONT);
|
JButton cancelBtn = GenerateCustomizeComponent.createStyledButton("取消",DEFAULT_FONT);
|
|
confirmBtn.addActionListener(e -> {
|
Rectangle2D selection = previewPanel.getSelection();
|
if (selection != null) {
|
// 转换为PDF坐标(考虑缩放和平移)
|
Point translation = previewPanel.getTranslation();
|
float scale = previewPanel.getScale();
|
|
// 计算选择区域在PDF文档中的实际坐标
|
float pdfX = (float)((selection.getX() - translation.x) / scale);
|
float pdfY = (float)((selection.getY() - translation.y) / scale);
|
float pdfWidthSel = (float)(selection.getWidth() / scale);
|
float pdfHeightSel = (float)(selection.getHeight() / scale);
|
|
// 保存选择信息
|
savePdfSelectionInfo(pageNumber, pdfX, pdfY, pdfWidthSel, pdfHeightSel);
|
|
String coordsInfo = String.format(
|
"新的区域坐标: X: %.2f, Y: %.2f, W: %.2f, H: %.2f",
|
pdfX, pdfY, pdfWidthSel, pdfHeightSel
|
);
|
|
log(coordsInfo);
|
// JOptionPane.showMessageDialog(pdfDialog, "确认选择该区域?", "区域坐标", JOptionPane.INFORMATION_MESSAGE);
|
} else {
|
JOptionPane.showMessageDialog(pdfDialog, "请先选择区域", "提示", JOptionPane.WARNING_MESSAGE);
|
return;
|
}
|
pdfDialog.dispose();
|
});
|
|
cancelBtn.addActionListener(e -> pdfDialog.dispose());
|
|
buttonPanel.add(confirmBtn);
|
buttonPanel.add(cancelBtn);
|
pdfDialog.add(buttonPanel, BorderLayout.SOUTH);
|
|
pdfDialog.setVisible(true);
|
|
} catch (Exception e) {
|
log("加载PDF失败: " + e.getMessage());
|
JOptionPane.showMessageDialog(supper, "加载PDF失败: " + e.getMessage(), "错误", JOptionPane.ERROR_MESSAGE);
|
}
|
}
|
|
}
|
|
|
// 保存PDF区域选择信息到偏好设置
|
private void savePdfSelectionInfo(int pageNumber, float x, float y, float width, float height) {
|
// prefs.put(PREF_PDF_PATH, pdfFile.getAbsolutePath());
|
prefs.putInt(PREF_PDF_PAGE, pageNumber);
|
prefs.putFloat(PREF_PDF_X, x);
|
prefs.putFloat(PREF_PDF_Y, y);
|
prefs.putFloat(PREF_PDF_WIDTH, width);
|
prefs.putFloat(PREF_PDF_HEIGHT, height);
|
|
// 更新界面显示
|
showLastPdfSelectionInfo();
|
}
|
|
private void loadLastPaths() {
|
String lastDirPath = prefs.get("lastOutputDir", "");
|
if (!lastDirPath.isEmpty()) {
|
File lastDir = new File(lastDirPath);
|
if (lastDir.exists() && lastDir.isDirectory()) {
|
outputDirectory = lastDir;
|
outputDirLabel.setText(outputDirectory.getAbsolutePath());
|
log("已加载上次使用的输出目录: " + outputDirectory.getAbsolutePath());
|
}
|
}
|
}
|
|
// 显示上次选择的PDF区域信息 - 修复了类型转换问题
|
private void showLastPdfSelectionInfo() {
|
|
float x = prefs.getFloat(PREF_PDF_X, 0);
|
float y = prefs.getFloat(PREF_PDF_Y, 0);
|
float width = prefs.getFloat(PREF_PDF_WIDTH, 0);
|
float height = prefs.getFloat(PREF_PDF_HEIGHT, 0);
|
|
String info = String.format("上次选择区域: - X: %.2f, Y: %.2f, W: %.2f, H: %.2f",
|
x, y, width, height);
|
|
// 直接使用成员变量更新上次选择信息,避免组件查找
|
lastSelectionLabel.setText(info);
|
log(info);
|
}
|
|
private void log(final String message) {
|
SwingUtilities.invokeLater(() -> {
|
String timestamp = new java.text.SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date());
|
logArea.append("["+timestamp+"] "+message + "\n");
|
logArea.setCaretPosition(logArea.getDocument().getLength());
|
});
|
}
|
|
/**
|
* 截取pdf文件指定区域的图像
|
* @param pdfFile pdf文件
|
* @param prefs 选区信息
|
*/
|
private String capturePdfArea(File pdfFile, Preferences prefs) throws IOException {
|
try (PDDocument document = PDDocument.load(Files.newInputStream(pdfFile.toPath()))) {
|
int page = prefs.getInt(PREF_PDF_PAGE, 0); // 转换为用户友好的页码(从1开始)
|
float x = prefs.getFloat(PREF_PDF_X, 0);
|
float y = prefs.getFloat(PREF_PDF_Y, 0);
|
float width = prefs.getFloat(PREF_PDF_WIDTH, 0);
|
float height = prefs.getFloat(PREF_PDF_HEIGHT, 0);
|
if (page < 0 || page > document.getNumberOfPages()) {
|
throw new IllegalArgumentException("页码超出范围: " + page);
|
}
|
PDFRenderer pdfRenderer = new PDFRenderer(document);
|
BufferedImage pageImage = pdfRenderer.renderImage(page);
|
document.close();
|
BufferedImage croppedImage = cropImage(pageImage, (int) x, (int) y, (int) width, (int) height);
|
//保存图片
|
File cacheDir = OcrSwingConstants.cacheDir;
|
String outputFilePath =cacheDir.getAbsolutePath() + File.separator + UUID.randomUUID() + ".png";
|
boolean saved = ToFile.saveImage(croppedImage, outputFilePath, "png");
|
if(saved){
|
return outputFilePath;
|
}
|
return "";
|
}
|
}
|
|
/**
|
* 裁剪图像指定区域
|
* @param originalImage 原始图像
|
* @param x 左上角 x 坐标
|
* @param y 左上角 y 坐标
|
* @param width 裁剪宽度
|
* @param height 裁剪高度
|
* @return 裁剪后的图像
|
*/
|
private static BufferedImage cropImage(BufferedImage originalImage, int x, int y, int width, int height) {
|
return originalImage.getSubimage(x, y, width, height);
|
}
|
|
}
|