Compare commits
5 Commits
ec1728f4e2
...
dev
| Author | SHA1 | Date | |
|---|---|---|---|
| 6e7a1bfbee | |||
| bc5bfe0d00 | |||
| 341ec1b0f6 | |||
| 9817a41801 | |||
| e3263fc56e |
16
INFO.md
16
INFO.md
@@ -1,4 +1,4 @@
|
|||||||
1.3-SNAPSHOT
|
1.5-SNAPSHOT
|
||||||
|
|
||||||
此版本包含:
|
此版本包含:
|
||||||
1. 压缩/解压 (`compress`)
|
1. 压缩/解压 (`compress`)
|
||||||
@@ -6,11 +6,15 @@
|
|||||||
2.1 预定义颜色打印 — `ColorPrintln`
|
2.1 预定义颜色打印 — `ColorPrintln`
|
||||||
2.2 自定义颜色打印 — `ColorHexPrintln`
|
2.2 自定义颜色打印 — `ColorHexPrintln`
|
||||||
2.3 Minecraft 风格多色打印 — `ColorPrintlnPlus`
|
2.3 Minecraft 风格多色打印 — `ColorPrintlnPlus`
|
||||||
3. 随机生成器 (`random`)
|
3. 文件创建与保存 (`file/CreateFile`)
|
||||||
4. 硬件标识生成器 (`hwid`)
|
4. 文件加密/解密 (`file/EncryptionAndDecryption`)
|
||||||
5. 版本信息 (`version`)
|
5. 随机生成器 (`random`)
|
||||||
6. 运行时信息 (`runtime`)
|
6. 硬件标识生成器 (`hwid`)
|
||||||
|
7. 版本信息 (`version`)
|
||||||
|
8. 运行时信息 (`runtime`)
|
||||||
6.1 获取运行时临时目录
|
6.1 获取运行时临时目录
|
||||||
6.2 新建临时目录
|
6.2 新建临时目录
|
||||||
6.3 获取临时目录
|
6.3 获取临时目录
|
||||||
6.4 获取当前运行的JAR文件路径
|
6.4 获取当前运行的JAR文件路径
|
||||||
|
|
||||||
|
在 1.4-SNAPSHOT 的基础上调整了API接口,修复了一些BUG
|
||||||
|
|||||||
92
README.md
92
README.md
@@ -1,6 +1,6 @@
|
|||||||
# GNU Java Utils Library
|
# GNU Java Utils Library
|
||||||
|
|
||||||
一个轻量级 Java 工具库,提供压缩/解压、终端彩色输出、随机数生成、硬件标识等功能。
|
一个轻量级 Java 工具库,提供压缩/解压、终端彩色输出、文件创建与管理、文件加密/解密、随机数生成、硬件标识等功能。
|
||||||
|
|
||||||
> 注:此项目/仓库已同步到 Github:[https://github.com/databasemysql233-debug/gnu_java_utils_library.git](https://github.com/databasemysql233-debug/gnu_java_utils_library.git)
|
> 注:此项目/仓库已同步到 Github:[https://github.com/databasemysql233-debug/gnu_java_utils_library.git](https://github.com/databasemysql233-debug/gnu_java_utils_library.git)
|
||||||
> 原项目/仓库链接:[https://git.opensource-studio.info/database-mysql/gnu_java_utils_library.git](https://git.opensource-studio.info/database-mysql/gnu_java_utils_library.git)
|
> 原项目/仓库链接:[https://git.opensource-studio.info/database-mysql/gnu_java_utils_library.git](https://git.opensource-studio.info/database-mysql/gnu_java_utils_library.git)
|
||||||
@@ -21,6 +21,9 @@ src/main/java/top/gtb520/java/gnu/java/utils/library/
|
|||||||
└── utils/
|
└── utils/
|
||||||
├── compress/
|
├── compress/
|
||||||
│ └── compress.java # 压缩/解压工具类
|
│ └── compress.java # 压缩/解压工具类
|
||||||
|
├── file/
|
||||||
|
│ ├── CreateFile.java # 文件创建/保存工具类
|
||||||
|
│ └── EncryptionAndDecryption.java # 文件加密/解密工具类
|
||||||
├── print/
|
├── print/
|
||||||
│ ├── echo.java # 终端彩色输出工具类
|
│ ├── echo.java # 终端彩色输出工具类
|
||||||
│ └── ColorNameEnum.java # 颜色名称枚举
|
│ └── ColorNameEnum.java # 颜色名称枚举
|
||||||
@@ -190,7 +193,80 @@ main.echo.ColorHexPrintln("自定义颜色", "#FF0000");
|
|||||||
main.echo.ColorPrintlnPlus("&a多色 &c文本");
|
main.echo.ColorPrintlnPlus("&a多色 &c文本");
|
||||||
```
|
```
|
||||||
|
|
||||||
### 3. 随机生成器 (`random`)
|
### 3. 文件创建与保存 (`file/CreateFile`)
|
||||||
|
|
||||||
|
支持创建普通/二进制文件,以及异步字节流文件保存。
|
||||||
|
|
||||||
|
| 方法 | 说明 | 参数 |
|
||||||
|
|-------------------------------------------------------|---------------------------------------|-------------------------------------------------------------|
|
||||||
|
| `CreateFile.NewFile(FileName, isBin, binFileType)` | 创建空白文件,二进制文件自动写入文件头 | `FileName` 文件名,`isBin` 是否二进制,`binFileType` 二进制类型(普通文件传 `null`) |
|
||||||
|
| `CreateFile.StreamSaveFile(file, TargePath, FileName)` | 以字节流方式异步保存文件到目标路径 | `file` 源文件,`TargePath` 目标目录,`FileName` 保存的文件名 |
|
||||||
|
|
||||||
|
**二进制文件类型 (`BinFileType`):**
|
||||||
|
|
||||||
|
| 枚举值 | 文件头标识 |
|
||||||
|
|-------|----------------|
|
||||||
|
| `ELF` | `7F 45 4C 46` |
|
||||||
|
| `PE` | `4D 5A` |
|
||||||
|
|
||||||
|
```java
|
||||||
|
import top.gtb520.java.gnu.java.utils.library.utils.file.CreateFile;
|
||||||
|
import top.gtb520.java.gnu.java.utils.library.utils.file.CreateFile.BinFileType;
|
||||||
|
import java.io.File;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
|
||||||
|
// 创建普通空白文件
|
||||||
|
File plainFile = CreateFile.NewFile("/path/to/file.txt", false, null);
|
||||||
|
|
||||||
|
// 创建 ELF 二进制文件(自动写入 ELF 文件头)
|
||||||
|
File elfFile = CreateFile.NewFile("/path/to/program", true, BinFileType.ELF);
|
||||||
|
|
||||||
|
// 创建 PE 二进制文件(自动写入 MZ 文件头)
|
||||||
|
File peFile = CreateFile.NewFile("/path/to/app.exe", true, BinFileType.PE);
|
||||||
|
|
||||||
|
// 异步字节流保存文件
|
||||||
|
boolean success = CreateFile.StreamSaveFile(sourceFile, Path.of("/path/to/dest"), "output.bin");
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4. 文件加密/解密 (`file/EncryptionAndDecryption`)
|
||||||
|
|
||||||
|
支持 **AES**、**DES** 对称加密,加密后覆盖原文件,密钥单独保存到指定目录。解密时从密钥文件读取密钥,解密后覆盖还原原文件。
|
||||||
|
|
||||||
|
| 方法 | 说明 | 参数 |
|
||||||
|
|----------------------------------------------------------------|--------------------------|-----------------------------------------------|
|
||||||
|
| `EncryptionAndDecryption.EncryptionFile(file, type, keyPath)` | 异步加密文件,覆盖原文件,密钥保存到 keyPath | `file` 文件,`type` 加密类型,`keyPath` 密钥目录路径 |
|
||||||
|
| `EncryptionAndDecryption.DecryptionFile(file, type, keyfile)` | 异步解密文件,覆盖还原原文件 | `file` 加密文件,`type` 加密类型,`keyfile` 密钥文件 |
|
||||||
|
|
||||||
|
**加密类型 (`EncryptionType`):**
|
||||||
|
|
||||||
|
| 枚举值 | 算法 | 密钥长度 |
|
||||||
|
|-------|---------------------|---------|
|
||||||
|
| `AES` | AES/ECB/PKCS5Padding | 128 bit |
|
||||||
|
| `DES` | DES/ECB/PKCS5Padding | 56 bit |
|
||||||
|
| `RSA` | AES(对称替代) | 128 bit |
|
||||||
|
|
||||||
|
> 加密后密钥文件命名为 `原文件名.key`,保存在 `keyPath` 目录下。
|
||||||
|
> 加密/解密均覆盖写回原文件,不添加额外后缀。
|
||||||
|
|
||||||
|
```java
|
||||||
|
import top.gtb520.java.gnu.java.utils.library.utils.file.EncryptionAndDecryption;
|
||||||
|
import top.gtb520.java.gnu.java.utils.library.utils.file.EncryptionAndDecryption.EncryptionType;
|
||||||
|
import java.io.File;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
|
||||||
|
File file = new File("/path/to/data.txt");
|
||||||
|
Path keyDir = Path.of("/path/to/keys");
|
||||||
|
|
||||||
|
// 加密文件(密钥保存到 keyDir/data.txt.key)
|
||||||
|
File encrypted = EncryptionAndDecryption.EncryptionFile(file, EncryptionType.AES, keyDir);
|
||||||
|
|
||||||
|
// 解密文件(从密钥文件读取密钥)
|
||||||
|
File keyFile = keyDir.resolve("data.txt.key").toFile();
|
||||||
|
File decrypted = EncryptionAndDecryption.DecryptionFile(file, EncryptionType.AES, keyFile);
|
||||||
|
```
|
||||||
|
|
||||||
|
### 5. 随机生成器 (`random`)
|
||||||
|
|
||||||
| 方法 | 说明 | 参数 |
|
| 方法 | 说明 | 参数 |
|
||||||
|---------------------------------------------|--------------|------------------------------|
|
|---------------------------------------------|--------------|------------------------------|
|
||||||
@@ -204,7 +280,7 @@ int num = defaults.random(1, 100); // 生成 1~100 的随机整数
|
|||||||
String str = defaults.randomString(16); // 生成 16 位随机字符串(大小写字母+数字)
|
String str = defaults.randomString(16); // 生成 16 位随机字符串(大小写字母+数字)
|
||||||
```
|
```
|
||||||
|
|
||||||
### 4. 硬件标识生成器 (`hwid`)
|
### 6. 硬件标识生成器 (`hwid`)
|
||||||
|
|
||||||
组合 CPU、主板、MAC 地址、硬盘序列号等信息,通过 SHA-256 生成唯一的硬件标识符(HWID)。支持 Windows、macOS、Linux 及 Android 平台。
|
组合 CPU、主板、MAC 地址、硬盘序列号等信息,通过 SHA-256 生成唯一的硬件标识符(HWID)。支持 Windows、macOS、Linux 及 Android 平台。
|
||||||
|
|
||||||
@@ -219,7 +295,7 @@ String hwid = getHWID.generateHWID();
|
|||||||
System.out.println("HWID: " + hwid);
|
System.out.println("HWID: " + hwid);
|
||||||
```
|
```
|
||||||
|
|
||||||
### 5. 版本信息 (`version`)
|
### 7. 版本信息 (`version`)
|
||||||
|
|
||||||
提供项目版本信息及编译时 Java/OpenJDK 版本常量。
|
提供项目版本信息及编译时 Java/OpenJDK 版本常量。
|
||||||
|
|
||||||
@@ -248,7 +324,7 @@ main.version.getOpenJDKRuntimeEnvironment(); // OpenJDK 运行时环境
|
|||||||
main.version.getOpenJDK64BitServerVM(); // OpenJDK 64-Bit Server VM
|
main.version.getOpenJDK64BitServerVM(); // OpenJDK 64-Bit Server VM
|
||||||
```
|
```
|
||||||
|
|
||||||
### 6. 运行时信息 (`runtime`)
|
### 8. 运行时信息 (`runtime`)
|
||||||
|
|
||||||
获取当前 Java 运行时环境信息,包括 JAR 路径、JVM 版本、位数等。
|
获取当前 Java 运行时环境信息,包括 JAR 路径、JVM 版本、位数等。
|
||||||
|
|
||||||
@@ -316,7 +392,7 @@ mvn package
|
|||||||
|
|
||||||
## 使用
|
## 使用
|
||||||
|
|
||||||
编译成功后,将 `target/gnu-java-utils-library-1.3-SNAPSHOT.jar` 放入项目依赖中,或在 Releases 中下载最新版 JAR 包。
|
编译成功后,将 `target/gnu-java-utils-library-1.4-SNAPSHOT.jar` 放入项目依赖中,或在 Releases 中下载最新版 JAR 包。
|
||||||
|
|
||||||
**pom.xml 引入本地依赖:**
|
**pom.xml 引入本地依赖:**
|
||||||
|
|
||||||
@@ -325,9 +401,9 @@ mvn package
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>top.gtb520.java.gnu</groupId>
|
<groupId>top.gtb520.java.gnu</groupId>
|
||||||
<artifactId>gnu_java_utils_library</artifactId>
|
<artifactId>gnu_java_utils_library</artifactId>
|
||||||
<version>1.3-SNAPSHOT</version>
|
<version>1.4-SNAPSHOT</version>
|
||||||
<scope>system</scope>
|
<scope>system</scope>
|
||||||
<systemPath>${project.basedir}/lib/gnu_java_utils_library-1.3-SNAPSHOT.jar</systemPath>
|
<systemPath>${project.basedir}/lib/gnu_java_utils_library-1.4-SNAPSHOT.jar</systemPath>
|
||||||
</dependency>
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
```
|
```
|
||||||
|
|||||||
2
pom.xml
2
pom.xml
@@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
<groupId>top.gtb520.java.gnu</groupId>
|
<groupId>top.gtb520.java.gnu</groupId>
|
||||||
<artifactId>gnu_java_utils_library</artifactId>
|
<artifactId>gnu_java_utils_library</artifactId>
|
||||||
<version>1.4-SNAPSHOT</version>
|
<version>1.6-SNAPSHOT</version>
|
||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
<maven.compiler.source>25</maven.compiler.source>
|
<maven.compiler.source>25</maven.compiler.source>
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package top.gtb520.java.gnu.java.utils.library;
|
package top.gtb520.java.gnu.java.utils.library;
|
||||||
|
|
||||||
import top.gtb520.java.gnu.java.utils.library.utils.print.ColorNameEnum;
|
import top.gtb520.java.gnu.java.utils.library.utils.print.ColorNameEnum;
|
||||||
|
import top.gtb520.java.gnu.java.utils.library.utils.compress.CompressPNG.PNGThreshold;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
@@ -31,6 +32,11 @@ public interface main {
|
|||||||
static void UnZip(String sourceFilePanth, String destFilePanth) throws Exception {
|
static void UnZip(String sourceFilePanth, String destFilePanth) throws Exception {
|
||||||
top.gtb520.java.gnu.java.utils.library.utils.compress.compress.UnZip(sourceFilePanth, destFilePanth);
|
top.gtb520.java.gnu.java.utils.library.utils.compress.compress.UnZip(sourceFilePanth, destFilePanth);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 压缩png图片
|
||||||
|
static File CompressPNG(File pngFile, PNGThreshold threshold) {
|
||||||
|
return top.gtb520.java.gnu.java.utils.library.utils.compress.CompressPNG.PNG(pngFile, threshold);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 终端打印接口与方法
|
// 终端打印接口与方法
|
||||||
@@ -148,17 +154,17 @@ public interface main {
|
|||||||
return top.gtb520.java.gnu.java.utils.library.utils.file.CreateFile.StreamSaveFile(file, TargePath, FileName);
|
return top.gtb520.java.gnu.java.utils.library.utils.file.CreateFile.StreamSaveFile(file, TargePath, FileName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// 文件加解密操作
|
// 文件加解密操作
|
||||||
interface EncryptionAndDecryption {
|
interface EncryptionAndDecryption {
|
||||||
// 文件加密
|
// 文件加密
|
||||||
static File FileEncrypt(File file, EncryptionType type, Path keyPath) throws Exception {
|
static File FileEncrypt(File file, EncryptionType type, Path keyPath) throws Exception {
|
||||||
return top.gtb520.java.gnu.java.utils.library.utils.file.EncryptionAndDecryption.EncryptionFile(file, type, keyPath);
|
return top.gtb520.java.gnu.java.utils.library.utils.file.EncryptionAndDecryption.EncryptionFile(file, type, keyPath);
|
||||||
}
|
}
|
||||||
// 文件解密
|
// 文件解密
|
||||||
static File DecryptionFile(File file, EncryptionType type, File keyfile) throws Exception {
|
static File DecryptionFile(File file, EncryptionType type, File keyfile) throws Exception {
|
||||||
return top.gtb520.java.gnu.java.utils.library.utils.file.EncryptionAndDecryption.DecryptionFile(file, type, keyfile);
|
return top.gtb520.java.gnu.java.utils.library.utils.file.EncryptionAndDecryption.DecryptionFile(file, type, keyfile);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,82 @@
|
|||||||
|
package top.gtb520.java.gnu.java.utils.library.utils.compress;
|
||||||
|
|
||||||
|
import javax.imageio.IIOImage;
|
||||||
|
import javax.imageio.ImageIO;
|
||||||
|
import javax.imageio.ImageWriteParam;
|
||||||
|
import javax.imageio.ImageWriter;
|
||||||
|
import javax.imageio.stream.ImageOutputStream;
|
||||||
|
import java.io.File;
|
||||||
|
import java.awt.image.BufferedImage;
|
||||||
|
import java.util.Iterator;
|
||||||
|
|
||||||
|
public class CompressPNG {
|
||||||
|
/***
|
||||||
|
* 压缩PNG图片
|
||||||
|
* 传入未压缩的PNG图片文件,和压缩阈值,返回压缩后的PNG图片文件
|
||||||
|
* 5个等级的压缩阈值,从低到高,THRESHOLD_1 最低,THRESHOLD_5 最高
|
||||||
|
*
|
||||||
|
* @param pngFile 未压缩的PNG图片文件
|
||||||
|
* @param threshold 压缩阈值
|
||||||
|
* @return 压缩后的PNG图片文件
|
||||||
|
*/
|
||||||
|
public static File PNG(File pngFile, PNGThreshold threshold) {
|
||||||
|
if (!pngFile.exists()) {
|
||||||
|
System.out.println("文件不存在");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (pngFile.getName().endsWith(".png") || pngFile.getName().endsWith(".PNG")) {
|
||||||
|
try {
|
||||||
|
BufferedImage image = ImageIO.read(pngFile);
|
||||||
|
if (image == null) {
|
||||||
|
System.out.println("无法读取PNG文件");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
Iterator<ImageWriter> writers = ImageIO.getImageWritersByFormatName("png");
|
||||||
|
if (!writers.hasNext()) {
|
||||||
|
System.out.println("未找到PNG写入器");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
ImageWriter writer = writers.next();
|
||||||
|
|
||||||
|
try (ImageOutputStream ios = ImageIO.createImageOutputStream(pngFile)) {
|
||||||
|
writer.setOutput(ios);
|
||||||
|
|
||||||
|
ImageWriteParam param = writer.getDefaultWriteParam();
|
||||||
|
param.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
|
||||||
|
param.setCompressionQuality(getCompressionQuality(threshold));
|
||||||
|
|
||||||
|
writer.write(null, new IIOImage(image, null, null), param);
|
||||||
|
} finally {
|
||||||
|
writer.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
return pngFile;
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
System.out.println("文件不是PNG格式,无法压缩");
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static float getCompressionQuality(PNGThreshold threshold) {
|
||||||
|
return switch (threshold) {
|
||||||
|
case THRESHOLD_1 -> 0.7f;
|
||||||
|
case THRESHOLD_2 -> 0.5f;
|
||||||
|
case THRESHOLD_3 -> 0.3f;
|
||||||
|
case THRESHOLD_4 -> 0.1f;
|
||||||
|
case THRESHOLD_5 -> 0.0f;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum PNGThreshold {
|
||||||
|
THRESHOLD_1,
|
||||||
|
THRESHOLD_2,
|
||||||
|
THRESHOLD_3,
|
||||||
|
THRESHOLD_4,
|
||||||
|
THRESHOLD_5;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,7 +2,7 @@ package top.gtb520.java.gnu.java.utils.library;
|
|||||||
|
|
||||||
public class version {
|
public class version {
|
||||||
// 项目的版本信息,不代表实时运行环境
|
// 项目的版本信息,不代表实时运行环境
|
||||||
public static final String VERSION = "1.4";
|
public static final String VERSION = "1.5";
|
||||||
public static final String JAVA_VERSION = "25";
|
public static final String JAVA_VERSION = "25";
|
||||||
public static final String OpenJDK_VERSION = "25.0.0.0.1";
|
public static final String OpenJDK_VERSION = "25.0.0.0.1";
|
||||||
public static final String OpenJDK_Runtime_Environment = "25.0.0.0.1+36-GA";
|
public static final String OpenJDK_Runtime_Environment = "25.0.0.0.1+36-GA";
|
||||||
|
|||||||
@@ -0,0 +1,205 @@
|
|||||||
|
package top.gtb520.java.gnu.java.utils.library.utils.compress;
|
||||||
|
|
||||||
|
import javax.imageio.ImageIO;
|
||||||
|
import java.awt.*;
|
||||||
|
import java.awt.image.BufferedImage;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
public class CompressPNGTest {
|
||||||
|
|
||||||
|
static int passed = 0;
|
||||||
|
static int failed = 0;
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
System.out.println("========== CompressPNG 测试开始 ==========");
|
||||||
|
|
||||||
|
testCompressWithEachThreshold();
|
||||||
|
testNonPNGFile();
|
||||||
|
testNonExistentFile();
|
||||||
|
testCompressedFileIsValidPNG();
|
||||||
|
testCompressedFileSmallerOrEqual();
|
||||||
|
|
||||||
|
System.out.println("========================================");
|
||||||
|
System.out.println("测试完成: 通过 " + passed + ", 失败 " + failed);
|
||||||
|
if (failed > 0) {
|
||||||
|
System.exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 测试每个压缩阈值均能正常压缩并返回原文件
|
||||||
|
*/
|
||||||
|
static void testCompressWithEachThreshold() {
|
||||||
|
String testName = "testCompressWithEachThreshold";
|
||||||
|
for (CompressPNG.PNGThreshold threshold : CompressPNG.PNGThreshold.values()) {
|
||||||
|
File pngFile = null;
|
||||||
|
try {
|
||||||
|
pngFile = createTestPNG("test_threshold_" + threshold.name());
|
||||||
|
long originalSize = pngFile.length();
|
||||||
|
|
||||||
|
File result = CompressPNG.PNG(pngFile, threshold);
|
||||||
|
|
||||||
|
boolean returnedSameFile = result != null && result.equals(pngFile);
|
||||||
|
assertCondition(testName + " [" + threshold.name() + "] - 应返回原文件引用", returnedSameFile);
|
||||||
|
|
||||||
|
boolean fileExists = result != null && result.exists() && result.length() > 0;
|
||||||
|
assertCondition(testName + " [" + threshold.name() + "] - 压缩后文件应存在且非空", fileExists);
|
||||||
|
|
||||||
|
System.out.println(" [" + threshold.name() + "] 原始: " + originalSize + " bytes, 压缩后: " + (result != null ? result.length() : "N/A") + " bytes");
|
||||||
|
} catch (Exception e) {
|
||||||
|
assertCondition(testName + " [" + threshold.name() + "] - 不应抛出异常: " + e.getMessage(), false);
|
||||||
|
} finally {
|
||||||
|
deleteTestFile(pngFile);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 测试传入非PNG文件应返回null
|
||||||
|
*/
|
||||||
|
static void testNonPNGFile() {
|
||||||
|
String testName = "testNonPNGFile";
|
||||||
|
File txtFile = null;
|
||||||
|
try {
|
||||||
|
txtFile = File.createTempFile("test_not_png", ".txt");
|
||||||
|
java.nio.file.Files.writeString(txtFile.toPath(), "this is not a png");
|
||||||
|
|
||||||
|
File result = CompressPNG.PNG(txtFile, CompressPNG.PNGThreshold.THRESHOLD_3);
|
||||||
|
assertCondition(testName + " - 非PNG文件应返回null", result == null);
|
||||||
|
} catch (Exception e) {
|
||||||
|
assertCondition(testName + " - 不应抛出异常: " + e.getMessage(), false);
|
||||||
|
} finally {
|
||||||
|
deleteTestFile(txtFile);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 测试传入不存在的文件应返回null
|
||||||
|
*/
|
||||||
|
static void testNonExistentFile() {
|
||||||
|
String testName = "testNonExistentFile";
|
||||||
|
try {
|
||||||
|
File nonExistent = new File(System.getProperty("java.io.tmpdir"), "non_existent_file.png");
|
||||||
|
File result = CompressPNG.PNG(nonExistent, CompressPNG.PNGThreshold.THRESHOLD_3);
|
||||||
|
assertCondition(testName + " - 不存在的文件应返回null", result == null);
|
||||||
|
} catch (Exception e) {
|
||||||
|
assertCondition(testName + " - 不应抛出异常: " + e.getMessage(), false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 测试压缩后的文件仍然是有效的PNG图片
|
||||||
|
*/
|
||||||
|
static void testCompressedFileIsValidPNG() {
|
||||||
|
String testName = "testCompressedFileIsValidPNG";
|
||||||
|
File pngFile = null;
|
||||||
|
try {
|
||||||
|
pngFile = createTestPNG("test_valid_png");
|
||||||
|
CompressPNG.PNG(pngFile, CompressPNG.PNGThreshold.THRESHOLD_3);
|
||||||
|
|
||||||
|
BufferedImage compressed = ImageIO.read(pngFile);
|
||||||
|
boolean isValidPNG = compressed != null;
|
||||||
|
assertCondition(testName + " - 压缩后的文件应是有效的PNG图片", isValidPNG);
|
||||||
|
|
||||||
|
if (isValidPNG) {
|
||||||
|
assertCondition(testName + " - 压缩后图片宽度应一致", compressed.getWidth() == 100);
|
||||||
|
assertCondition(testName + " - 压缩后图片高度应一致", compressed.getHeight() == 100);
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
assertCondition(testName + " - 不应抛出异常: " + e.getMessage(), false);
|
||||||
|
} finally {
|
||||||
|
deleteTestFile(pngFile);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 测试压缩后文件大小不超过原始文件
|
||||||
|
*/
|
||||||
|
static void testCompressedFileSmallerOrEqual() {
|
||||||
|
String testName = "testCompressedFileSmallerOrEqual";
|
||||||
|
File pngFile = null;
|
||||||
|
try {
|
||||||
|
// 创建一个较大的、有压缩空间的测试图片(纯色+渐变)
|
||||||
|
pngFile = createLargeTestPNG("test_compression_ratio", 500, 500);
|
||||||
|
long originalSize = pngFile.length();
|
||||||
|
|
||||||
|
File result = CompressPNG.PNG(pngFile, CompressPNG.PNGThreshold.THRESHOLD_5);
|
||||||
|
|
||||||
|
if (result != null) {
|
||||||
|
long compressedSize = result.length();
|
||||||
|
assertCondition(testName + " - 压缩后文件大小(" + compressedSize + ")应不超过原始大小(" + originalSize + ")",
|
||||||
|
compressedSize <= originalSize);
|
||||||
|
System.out.println(" 原始: " + originalSize + " bytes, THRESHOLD_5压缩后: " + compressedSize + " bytes");
|
||||||
|
} else {
|
||||||
|
assertCondition(testName + " - 压缩不应返回null", false);
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
assertCondition(testName + " - 不应抛出异常: " + e.getMessage(), false);
|
||||||
|
} finally {
|
||||||
|
deleteTestFile(pngFile);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ========== 辅助方法 ==========
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建一个100x100的测试PNG图片
|
||||||
|
*/
|
||||||
|
static File createTestPNG(String name) throws IOException {
|
||||||
|
File file = File.createTempFile(name, ".png");
|
||||||
|
BufferedImage image = new BufferedImage(100, 100, BufferedImage.TYPE_INT_ARGB);
|
||||||
|
Graphics2D g2d = image.createGraphics();
|
||||||
|
// 绘制渐变图案,使图片有一定的压缩空间
|
||||||
|
for (int y = 0; y < 100; y++) {
|
||||||
|
for (int x = 0; x < 100; x++) {
|
||||||
|
image.setRGB(x, y, new Color(x * 2, y * 2, (x + y)).getRGB());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
g2d.dispose();
|
||||||
|
ImageIO.write(image, "png", file);
|
||||||
|
return file;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建一个指定尺寸的测试PNG图片(包含更多颜色变化以增加压缩效果差异)
|
||||||
|
*/
|
||||||
|
static File createLargeTestPNG(String name, int width, int height) throws IOException {
|
||||||
|
File file = File.createTempFile(name, ".png");
|
||||||
|
BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
|
||||||
|
Graphics2D g2d = image.createGraphics();
|
||||||
|
// 绘制大面积纯色区域(压缩率高)
|
||||||
|
g2d.setColor(Color.WHITE);
|
||||||
|
g2d.fillRect(0, 0, width, height);
|
||||||
|
g2d.setColor(Color.RED);
|
||||||
|
g2d.fillRect(0, 0, width / 2, height / 2);
|
||||||
|
g2d.setColor(Color.BLUE);
|
||||||
|
g2d.fillRect(width / 2, 0, width / 2, height / 2);
|
||||||
|
g2d.setColor(Color.GREEN);
|
||||||
|
g2d.fillRect(0, height / 2, width / 2, height / 2);
|
||||||
|
g2d.setColor(Color.YELLOW);
|
||||||
|
g2d.fillRect(width / 2, height / 2, width / 2, height / 2);
|
||||||
|
g2d.dispose();
|
||||||
|
ImageIO.write(image, "png", file);
|
||||||
|
return file;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 安全删除测试文件
|
||||||
|
*/
|
||||||
|
static void deleteTestFile(File file) {
|
||||||
|
if (file != null && file.exists()) {
|
||||||
|
file.delete();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void assertCondition(String message, boolean condition) {
|
||||||
|
if (condition) {
|
||||||
|
System.out.println("[PASS] " + message);
|
||||||
|
passed++;
|
||||||
|
} else {
|
||||||
|
System.out.println("[FAIL] " + message);
|
||||||
|
failed++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user