**图片压缩器**
命令:jave - jar jar包(文尾有源码,自己打包即可) 就是以上的窗口,比较明了了
inputPath: 源文件夹(以我目前的逻辑,需要保证文件夹里面全是jpg/jpeg/png的图片)
outputPath: 输出目标文件夹
thread: 线程数,自行斟酌,最大10个线程
quality: 压缩质量,0.1~1.0,压缩程度线性提升,输出图像质量线性下降
代码如下:
public class ImgTranslate {
private static String inputPath = "";
private static String outputPath = "";
private static String changeMessage = "";
private static int threadNum = 1;
private static float qualityNum = 0.1f;
public static void main(String[] args) {
// 创建 JFrame 实例
JFrame frame = new JFrame("IMG_TRANSLATE");
// 设置窗口大小
frame.setSize(450, 240);
// 设置窗口关闭时的操作
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocationRelativeTo(null);
// 创建面板,用于放置文件夹选择框和按钮
JPanel panel = new JPanel();
// 将面板放置在窗口中
frame.add(panel);
// 调用用户定义的方法添加文件夹选择框和按钮
placeComponents(panel);
// 使窗口可见
frame.setVisible(true);
}
private static void placeComponents(JPanel panel) {
panel.setLayout(null);
// 创建标签、文本框和按钮,用于显示文件夹路径和选择文件
JLabel folder1Label = new JLabel("inputPath:");
folder1Label.setBounds(10, 20, 80, 25);
panel.add(folder1Label);
JTextField folder1Field = new JTextField(30);
folder1Field.setBounds(100, 20, 200, 25);
panel.add(folder1Field);
JButton selectFile1Button = new JButton("choose");
selectFile1Button.setPreferredSize(new Dimension(100, 30));
selectFile1Button.setBounds(320, 20, 80, 25);
panel.add(selectFile1Button);
JLabel folder2Label = new JLabel("outputPath:");
folder2Label.setBounds(10, 50, 80, 25);
panel.add(folder2Label);
JTextField folder2Field = new JTextField(30);
folder2Field.setBounds(100, 50, 200, 25);
panel.add(folder2Field);
JButton selectFile2Button = new JButton("choose");
selectFile2Button.setPreferredSize(new Dimension(100, 30));
selectFile2Button.setBounds(320, 50, 80, 25);
panel.add(selectFile2Button);
JComboBox<String> thread = new JComboBox<>();
JComboBox<String> quality = new JComboBox<>();
for (int i = 1; i <= 10; i++) {
thread.addItem(i+"");
quality.addItem(new BigDecimal(i).divide(new BigDecimal(10)).toString());
}
JLabel folder3Label = new JLabel("thread:");
folder3Label.setBounds(10, 80, 80, 25);
panel.add(folder3Label);
thread.setBounds(100,80,200,25);
JLabel folder4Label = new JLabel("quality:");
folder4Label.setBounds(10, 110, 80, 25);
panel.add(folder4Label);
quality.setBounds(100,110,200,25);
panel.add(thread);
panel.add(quality);
thread.addItemListener(new ItemListener() {
public void itemStateChanged(ItemEvent e) {
if (e.getStateChange() == ItemEvent.SELECTED) {
// 当选项被选中时,获取选中的值并进行相应的操作
String selectedOption = (String) thread.getSelectedItem();
threadNum = Integer.parseInt(selectedOption);
}
}
});
quality.addItemListener(new ItemListener() {
public void itemStateChanged(ItemEvent e) {
if (e.getStateChange() == ItemEvent.SELECTED) {
// 当选项被选中时,获取选中的值并进行相应的操作
String selectedOption = (String) quality.getSelectedItem();
qualityNum = Float.parseFloat(selectedOption);
}
}
});
JLabel label = new JLabel(changeMessage);
label.setBounds(150, 170, 100, 25);
// label.setForeground(Color.RED); // 设置文本颜色为红色
panel.add(label);
// 为每个按钮添加选择文件的监听器
selectFile1Button.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
selectFile(folder1Field,0);
}
});
selectFile2Button.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
selectFile(folder2Field,1);
}
});
JButton okButton = new JButton("confirm");
okButton.setBounds(150, 140, 80, 25);
panel.add(okButton);
okButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
if("".equals(inputPath)||"".equals(outputPath)){
JOptionPane.showMessageDialog(null, "The inputPath or the outputPath cannot be null");
}else {
JOptionPane.showMessageDialog(null, "start translate...");
try {
Thread.sleep(3000);
} catch (Exception e1) {
e1.printStackTrace();
}
new Thread(() -> {
try {
translating();
} catch (Exception e1) {
e1.printStackTrace();
}
}).start();
Timer timer = new Timer(500, new ActionListener() {
public void actionPerformed(ActionEvent e) {
try {
changeMessage = "translated "+(new BigDecimal(new File(outputPath).listFiles().length).divide(new BigDecimal(new File(inputPath).listFiles().length)))
.multiply(new BigDecimal(100))+"%";
}catch (Exception e1){
changeMessage = "translated "+"0%";
}
label.setText(changeMessage);
if(changeMessage.contains("100%")){
label.setForeground(Color.pink);
}
}
});
timer.start();
}
}
private void translating() throws Exception {
translate(inputPath,outputPath,qualityNum);
}
});
}
private static void translate(String inputPath, String outputPath, float quality)throws Exception {
//分割源目录线程
//分线程执行后续方法
File inputFiles = new File(inputPath);
while (inputFiles.listFiles().length/threadNum==0){
threadNum--;
}
File[] files = inputFiles.listFiles();
java.util.List<File> fileList = Arrays.asList(files);
java.util.List<java.util.List<File>> partition = Lists.partition(fileList, fileList.size() / threadNum);
ExecutorService executor = Executors.newFixedThreadPool(threadNum);
for (java.util.List<File> smallList : partition) {
executor.submit(() -> {
// 在这里执行你的操作
for (File file : smallList) {
try {
BufferedImage inputImage = ImageIO.read(file);
String type = file.getName().split("\\.")[1];
switch (type){
case "jpg":
jpgTranslate(outputPath, quality, file, inputImage);
break;
case "jpeg":
jpgTranslate(outputPath, quality, file, inputImage);
break;
case "png":
pngTranslate(outputPath, quality,file, inputImage);
break;
}
} catch (IOException e) {
e.printStackTrace();
}
}
});
}
// 关闭线程池并等待任务完成
executor.shutdown();
}
private static void pngTranslate(String outputPath, float quality,File file, BufferedImage inputImage) {
int width = inputImage.getWidth();
int height = inputImage.getHeight();
BufferedImage compressedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
int rgb = inputImage.getRGB(x, y);
int r = (rgb >> 16) & 0xff;
int g = (rgb >> 8) & 0xff;
int b = rgb & 0xff;
int gray = (int) (0.2989 * r + 0.5870 * g + 0.1140 * b);
int grayCompressed = (int) (gray * quality);
int rgbCompressed = (grayCompressed << 16) | (grayCompressed << 8) | grayCompressed;
compressedImage.setRGB(x, y, rgbCompressed);
}
}
try {
ImageIO.write(compressedImage, "png", new File(outputPath+"\\"+file.getName()));
} catch (IOException e) {
e.printStackTrace();
}
}
private static void jpgTranslate(String outputPath, float quality, File file, BufferedImage inputImage) throws IOException {
Iterator<ImageWriter> writers = ImageIO.getImageWritersByFormatName("jpg");
ImageWriter writer = (ImageWriter) writers.next();
OutputStream outputStream = new FileOutputStream(outputPath+"\\"+file.getName());
ImageOutputStream imageOutputStream = ImageIO.createImageOutputStream(outputStream);
writer.setOutput(imageOutputStream);
ImageWriteParam param = writer.getDefaultWriteParam();
param.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
param.setCompressionQuality(quality);
writer.write(null, new IIOImage(inputImage, null, null), param);
imageOutputStream.close();
outputStream.close();
}
private static void selectFile(JTextField textField,int flag) {
JFileChooser fileChooser = new JFileChooser();
fileChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY); // 限制只能选择文件夹
int returnValue = fileChooser.showOpenDialog(null); // 显示打开文件对话框
if (returnValue == JFileChooser.APPROVE_OPTION) { // 如果用户选择了文件夹并点击了“打开”按钮
File selectedDirectory = fileChooser.getSelectedFile(); // 获取用户选择的文件夹
textField.setText(selectedDirectory.getAbsolutePath()); // 将文件夹路径设置到文本框中
if(flag==0){
inputPath = selectedDirectory.getAbsolutePath();
}else {
outputPath = selectedDirectory.getAbsolutePath();
}
} else { // 如果用户没有选择文件夹或点击了取消按钮,清空文本框内容
textField.setText("");
}
}
}