1 package edu.jiangxin.apktoolbox.pdf.pic2pdf;
2
3 import edu.jiangxin.apktoolbox.pdf.PdfUtils;
4 import edu.jiangxin.apktoolbox.swing.extend.EasyPanel;
5 import edu.jiangxin.apktoolbox.swing.extend.FileListPanel;
6 import edu.jiangxin.apktoolbox.swing.extend.filepanel.FilePanel;
7 import edu.jiangxin.apktoolbox.utils.Constants;
8 import edu.jiangxin.apktoolbox.utils.FileUtils;
9
10 import javax.swing.*;
11 import java.awt.event.ActionEvent;
12 import java.awt.event.ActionListener;
13 import java.io.File;
14 import java.io.Serial;
15 import java.util.List;
16 import java.util.Set;
17 import java.util.TreeSet;
18 import java.util.concurrent.ExecutorService;
19 import java.util.concurrent.Executors;
20
21 public class Pic2PdfPanel extends EasyPanel {
22 @Serial
23 private static final long serialVersionUID = 1L;
24
25 private FileListPanel fileListPanel;
26
27 private JCheckBox isRecursiveSearched;
28
29 private FilePanel targetDirPanel;
30
31 private JButton startButton;
32 private JButton cancelButton;
33
34 private transient WorkderThread convertThread;
35
36 @Override
37 public void initUI() {
38 BoxLayout boxLayout = new BoxLayout(this, BoxLayout.Y_AXIS);
39 setLayout(boxLayout);
40
41 createInputPanel();
42 add(Box.createVerticalStrut(Constants.DEFAULT_Y_BORDER));
43
44 createOutputPanel();
45 add(Box.createVerticalStrut(Constants.DEFAULT_Y_BORDER));
46
47 createOptionPanel();
48 add(Box.createVerticalStrut(Constants.DEFAULT_Y_BORDER));
49
50 createOperationPanel();
51 }
52
53 private void createInputPanel() {
54 fileListPanel = new FileListPanel();
55 fileListPanel.initialize();
56 add(fileListPanel);
57 }
58
59 private void createOutputPanel() {
60 targetDirPanel = new FilePanel("Target Directory");
61 targetDirPanel.initialize();
62 targetDirPanel.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
63 add(targetDirPanel);
64 }
65
66 private void createOptionPanel() {
67 JPanel optionPanel = new JPanel();
68 optionPanel.setLayout(new BoxLayout(optionPanel, BoxLayout.X_AXIS));
69 optionPanel.setBorder(BorderFactory.createTitledBorder("Options"));
70
71 isRecursiveSearched = new JCheckBox("Recursive Search");
72 isRecursiveSearched.setSelected(true);
73 optionPanel.add(isRecursiveSearched);
74 optionPanel.add(Box.createHorizontalGlue());
75
76 add(optionPanel);
77 }
78
79 private void createOperationPanel() {
80 JPanel operationPanel = new JPanel();
81 operationPanel.setLayout(new BoxLayout(operationPanel, BoxLayout.X_AXIS));
82 operationPanel.setBorder(BorderFactory.createTitledBorder("Operations"));
83
84 startButton = new JButton("Start");
85 cancelButton = new JButton("Cancel");
86 cancelButton.setEnabled(false);
87 startButton.addActionListener(new OperationButtonActionListener());
88 cancelButton.addActionListener(new OperationButtonActionListener());
89 operationPanel.add(startButton);
90 operationPanel.add(Box.createHorizontalStrut(Constants.DEFAULT_X_BORDER));
91 operationPanel.add(Box.createHorizontalStrut(Constants.DEFAULT_X_BORDER));
92 operationPanel.add(cancelButton);
93 operationPanel.add(Box.createHorizontalGlue());
94
95 add(operationPanel);
96 }
97
98 private void processFile(File encryptedFile, File targetDir) {
99 try {
100 if (Thread.currentThread().isInterrupted()) {
101 return;
102 }
103 PdfUtils.removePasswordWithIText(encryptedFile, targetDir);
104 } catch (Throwable t) {
105 logger.error("Process file failed: {}", encryptedFile.getAbsolutePath(), t);
106 }
107 }
108
109 class OperationButtonActionListener implements ActionListener {
110 @Override
111 public void actionPerformed(ActionEvent e) {
112 Object source = e.getSource();
113 if (source.equals(startButton)) {
114 startButton.setEnabled(false);
115 cancelButton.setEnabled(true);
116 convertThread = new WorkderThread(isRecursiveSearched.isSelected());
117 convertThread.start();
118 } else if (source.equals(cancelButton)) {
119 startButton.setEnabled(true);
120 cancelButton.setEnabled(false);
121 if (convertThread.isAlive()) {
122 convertThread.interrupt();
123 convertThread.executorService.shutdownNow();
124 }
125 }
126
127 }
128 }
129
130 class WorkderThread extends Thread {
131 public final ExecutorService executorService;
132 private final boolean isRecursiveSearched;
133
134 public WorkderThread(boolean isRecursiveSearched) {
135 super();
136 this.isRecursiveSearched = isRecursiveSearched;
137 this.executorService = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
138 }
139
140 @Override
141 public void run() {
142 try {
143 List<File> fileList = fileListPanel.getFileList();
144 Set<File> fileSet = new TreeSet<>();
145 String[] extensions = new String[]{"jpg", "jpeg", "png"};
146 for (File file : fileList) {
147 fileSet.addAll(FileUtils.listFiles(file, extensions, isRecursiveSearched));
148 }
149
150 PdfUtils.imagesToPdf(fileSet, new File(targetDirPanel.getFile(), "result.pdf"));
151 } catch (Exception e) {
152 logger.error("Remove process failed", e);
153 } finally {
154 executorService.shutdown();
155 SwingUtilities.invokeLater(() -> {
156 startButton.setEnabled(true);
157 cancelButton.setEnabled(false);
158 });
159 }
160 }
161 }
162 }