📖 快速开始
什么是 JmsImage?
JmsImage 是一个通用的 Java 图片处理框架,采用执行器模式设计,支持丰富的处理器扩展。
它提供了简洁的流式 API、完善的资源管理机制,以及强大的撤销/重做功能。
💡 核心理念
- 流式 API,链式调用
- 处理器模块化,职责单一
- 完善的资源管理机制(Resource + AutoCloseableResource)
- 支持撤销/重做功能
- 拦截器模式,流程可控
第一个 JmsImage 程序
JmsImage image = JmsImage.read("input.png");
image.execute(new ImageWaterMark.BatchAddTextWaterMarkHandler(
"版权所有",
new Color(255, 255, 255, 64),
new Font("微软雅黑", 40),
30,
100,
true
));
image.write("output.jpg");
image.destroy();
✅ 简化版(推荐)
JmsImage.read("input.png")
.execute(new ImageWaterMark.BatchAddTextWaterMarkHandler(...))
.write("output.jpg")
.destroy();
📦 核心概念
1. JmsImage - 图片实体
JmsImage 是框架的核心类,负责管理图片的生命周期、执行处理器、保存和读取图片,以及资源销毁。
实现了 AutoCloseableResource 接口,支持 try-with-resources 语法。
重要特性
- 始终返回副本,保护原始数据
- 支持历史栈(撤销/重做)
- 链式调用,代码优雅
- 实现 AutoCloseableResource,支持自动资源管理
image.historySwitchOn()
.execute(handler1)
.execute(handler2)
.undo()
.redo()
.store();
try (JmsImage image = JmsImage.read("input.png")) {
image.execute(handler)
.write("output.jpg");
}
2. ImageContainer - 图片容器
ImageContainer 用于存储和管理图片对象,分为开放容器和内部容器两种模式。
实现了 AutoCloseableResource 接口,具有完整的生命周期管理。
开放容器(推荐):
ImageContainer container = new ImageContainer();
BufferedImage img = ImageIO.read(new File("input.png"));
container.set(img);
BufferedImage result = container.get();
container.destroy();
内部容器(高级用法):
ImageContainer container = new ImageContainer();
JmsImage image = JmsImage.read("input.png");
container.with(image);
image.putImageIntoInternalContainer();
BufferedImage img = container.getByJmsImage();
ImageContainer openContainer = image.releaseInternalContainer();
ImageContainer finalContainer = image.releaseInternalContainerAndDestroy();
⚠️ 容器使用注意
- 内部容器不能直接调用 get()/set(),必须通过 JmsImage 管理
- 开放容器不能调用 getByJmsImage()/setByJmsImage(),这些是内部方法
- 容器释放后,JmsImage 不再持有该容器的引用
3. Handler - 处理器
处理器是 JmsImage 的灵魂! 所有图片处理逻辑都在 Handler 中实现。
所有处理器都实现了 ImageHandler 接口,该接口继承了:
Handler<BufferedImage> - 执行器模式,提供 handle() 方法
AutoCloseableResource - 资源管理,提供 init()/destroy() 方法
(1)水印处理器(ImageWaterMark)
new BatchAddTextWaterMarkHandler(
"Jms Image",
new Color(255, 255, 255, 64),
new Font("Cambria", 40),
30,
100,
true
);
new AddTextWaterMarkHandler(
x, y, angle, "水印", color, font, autoDestroy
);
new RemoveWaterMarkBlurImprovedHandler(x, y, width, height, true);
new RemoveWaterMarkSurroundImprovedHandler(x, y, width, height, true);
new RemoveWaterMarkGradientHandler(x, y, width, height, true);
new RemoveWaterMarkNearestFillHandler(x, y, width, height, true);
new RemoveWaterMarkAverageHandler(x, y, width, height, true);
(2)滤镜处理器(ImageFilter)
new DarkColorFilterHandler(true);
new SmallColorFilterHandler(true);
new NegativeFilterHandler(true);
new MosaicFilterHandler(true);
(3)压缩处理器(ImageCompress)
new ProportionCompressHandler(0.5, true);
new QualityCompressHandler(0.8f, true);
(4)基础处理器(ImageBasicHandlers)
new AddNoiseHandler(100, true);
new AddLinesHandler(50, true);
4. AbstractImageHandler - 抽象处理器基类
所有自定义处理器都应继承 AbstractImageHandler,它提供了:
- 资源管理(init/destroy/status check)
- 像素操作工具(getPixels/writePixelsToImage)
- Graphics2D 工具(getGraphics2D/graphics2DDraw)
- 颜色工具(clamp/getColorAtPosition)
public class MyCustomFilter extends AbstractImageHandler {
public MyCustomFilter(boolean autoDestroy) {
super(autoDestroy);
}
@Override
protected void handleImage() {
graphics2DDraw(graphics2D -> {
graphics2D.setColor(Color.RED);
graphics2D.setStroke(new BasicStroke(5));
graphics2D.drawRect(0, 0, image.getWidth(), image.getHeight());
});
}
}
5. HandlerInterceptor - 拦截器
拦截器用于在执行处理器前后进行干预,实现流程控制、日志记录、异常处理等功能。
继承了基础的 Interceptor 标记接口。
image.execute(handler, new HandlerInterceptor() {
@Override
public boolean preHandle(ImageHandler handler) {
System.out.println("处理前检查...");
return true;
}
@Override
public BufferedImage postHandle(ImageHandler handler, BufferedImage result) {
System.out.println("处理后优化...");
return result;
}
@Override
public void exceptionHandle(ImageHandler handler, Exception e) {
System.out.println("捕获异常:" + e.getMessage());
}
});
💡 拦截器典型用途
- preHandle:权限校验、参数验证、前置日志
- postHandle:结果优化、质量检查、后置日志
- exceptionHandle:异常降级、错误报告、转人工处理
6. autoDestroy - 自动销毁
✅ 最佳实践:永远使用 true
让框架自动管理资源,避免内存泄漏!Handler 执行完成后会自动调用 destroy() 释放资源。
7. JmsImageException - 统一异常
所有 JmsImage 相关异常都继承自 JmsBasicException,提供统一的异常处理机制。
try {
image.execute(handler);
} catch (JmsImageException e) {
logger.error("图片处理失败", e);
}
💡 实战场景
场景 1:用户上传头像处理
@PostMapping("/upload/avatar")
public ResponseResult uploadAvatar(MultipartFile file) {
try {
String tempPath = saveTempFile(file);
JmsImage.read(tempPath)
.historySwitchOn()
.execute(new ImageCompress.ProportionCompressHandler(0.5, true))
.execute(new ImageWaterMark.AddTextWaterMarkHandler(
10, 10, 0, "@MyApp", Color.GRAY, new Font("Arial", 12), true
))
.write("avatars/" + userId + ".jpg")
.destroy();
Files.delete(Paths.get(tempPath));
return ResponseResult.success("上传成功");
} catch (Exception e) {
return ResponseResult.error("上传失败:" + e.getMessage());
}
}
场景 2:批量添加防伪水印
public void batchAddWatermark(List<String> imagePaths) {
for (String path : imagePaths) {
JmsImage.read(path)
.execute(new ImageWaterMark.BatchAddTextWaterMarkHandler(
"© 禁止盗用",
new Color(255, 255, 255, 64),
new Font("微软雅黑", Font.BOLD, 40),
30,
150,
true
))
.write(path.replace(".png", "_watermarked.jpg"))
.destroy();
}
}
场景 3:图片编辑器(支持撤销/重做)
public class ImageEditor {
private JmsImage image;
public void loadImage(String path) {
image = JmsImage.read(path).historySwitchOn();
}
public void applyGrayscale() {
image.execute(new DarkColorFilterHandler(true));
}
public void undo() {
image.undo();
}
public void redo() {
image.redo();
}
public void save(String path) {
image.write(path);
}
public void close() {
image.destroy();
}
}
⚙️ 高级用法
自定义处理器
public class MyCustomFilter extends AbstractImageHandler {
public MyCustomFilter(boolean autoDestroy) {
super(autoDestroy);
}
@Override
protected void handleImage() {
graphics2DDraw(graphics2D -> {
graphics2D.setColor(Color.RED);
graphics2D.setStroke(new BasicStroke(5));
graphics2D.drawRect(0, 0, image.getWidth(), image.getHeight());
});
}
}
image.execute(new MyCustomFilter(true));
拦截器:流程控制
image.execute(handler, new HandlerInterceptor() {
@Override
public boolean preHandle(ImageHandler handler) {
System.out.println("处理前检查...");
return true;
}
@Override
public BufferedImage postHandle(ImageHandler handler, BufferedImage result) {
System.out.println("处理后优化...");
return result;
}
@Override
public void exceptionHandle(ImageHandler handler, Exception e) {
System.out.println("捕获异常:" + e.getMessage());
}
});
图片容器的高级用法
ImageContainer sharedContainer = new ImageContainer();
JmsImage image1 = JmsImage.read("image1.png");
JmsImage image2 = JmsImage.read("image2.png");
image1.execute(handler1);
sharedContainer.set(image1.getImage());
image2.execute(handler2);
image2.getImage(sharedContainer);
BufferedImage finalResult = sharedContainer.get();
sharedContainer.destroy();
日志集成
Logger logger = LogAdapter.getLogger(SLF4J_LOGGER);
image.logInfo(logger, "开始处理图片")
.execute(handler1)
.logDebug(logger, "完成第一步处理")
.execute(handler2)
.logError(logger, "处理过程中发生警告", warning)
.destroy();
⚠️ 注意事项
❌ 常见错误
- 忘记调用
destroy() → 内存泄漏
- 重复使用已销毁的对象 → 抛出 JmsImageException
- Handler 复用 → 可能导致状态混乱
- 内部容器调用 get()/set() → 抛出异常
- 开放容器调用 getByJmsImage()/setByJmsImage() → 抛出异常
✅ 图片类型选择
- 保存为 JPEG:使用
TYPE_INT_RGB(快)
- 保存为 PNG:可以使用
TYPE_INT_ARGB(支持透明)
- 避免用 ARGB 保存为 JPEG(慢 10 倍)
资源生命周期管理
try (JmsImage image = JmsImage.read("input.png")) {
image.execute(handler).write("output.jpg");
} catch (IOException e) {
logger.error("处理失败", e);
}
JmsImage image = null;
try {
image = JmsImage.read("input.png");
image.execute(handler).write("output.jpg");
} finally {
if (image != null) {
image.destroy();
}
}
JmsImage image = JmsImage.read("input.png");
image.execute(handler);
性能优化建议
@PostConstruct
public void init() {
BufferedImage dummy = new BufferedImage(10, 10, BufferedImage.TYPE_INT_ARGB);
Graphics2D g2d = dummy.createGraphics();
g2d.setFont(new Font("微软雅黑", Font.BOLD, 40));
g2d.getFontMetrics();
g2d.dispose();
}
image.write("output.jpg");
image.write("output.png");
image.execute(new Handler(true));
image.execute(new Handler(false));
📊 性能参考
基于实测数据(2MB 图片,960×1280):
| 操作 |
耗时 |
说明 |
| Font 首次预热 |
~700ms |
JVM 字体加载机制 |
| 图片加载(PNG) |
~650ms |
IO 瓶颈 |
| 批量水印(378 个) |
~30ms |
✅ 框架性能优秀 |
| 图片保存(JPEG) |
~70ms |
✅ 很快 |
| 资源销毁 |
~2ms |
✅ 极快 |
结论
框架本身性能很好,瓶颈主要在 IO 和 JVM 机制。通过预热字体、使用 JPEG 格式,可以显著提升性能。
🎯 总结
JmsImage 的优势
- ✅ 易用性:流式 API,代码简洁
- ✅ 扩展性:模块化 Handler,易于定制
- ✅ 安全性:完善的资源管理机制(Resource + AutoCloseableResource)
- ✅ 功能性:支持撤销/重做、拦截器、图片容器等高级特性
- ✅ 规范性:统一异常体系、日志支持
适用场景
- Web 应用图片上传处理
- 桌面图片编辑器
- 批量图片处理工具
- 任何需要图片处理的 Java 应用
🚀 快速上手口诀
一读(read)、二处理(execute)、三保存(write)、四销毁(destroy)
Handler 传 true,资源不用愁
拦截器来把关,流程全掌控
历史栈开开关,撤销又重做
容器分内外,资源共享好