← 返回首页

JmsImage

高性能 Java 图片处理框架

Version 2.x.x

📖 快速开始

什么是 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-with-resources 用法(推荐) try (JmsImage image = JmsImage.read("input.png")) { image.execute(handler) .write("output.jpg"); // 退出 try 块时自动调用 destroy() }

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();

内部容器(高级用法):

// 创建容器并注册到 JmsImage ImageContainer container = new ImageContainer(); JmsImage image = JmsImage.read("input.png"); // 将容器注入 JmsImage,成为内部容器 container.with(image); // JmsImage 会自动将当前图片放入容器 image.putImageIntoInternalContainer(); // 从容器获取图片 BufferedImage img = container.getByJmsImage(); // 释放内部容器(变为开放容器) ImageContainer openContainer = image.releaseInternalContainer(); // 或者释放并销毁 JmsImage ImageContainer finalContainer = image.releaseInternalContainerAndDestroy();
⚠️ 容器使用注意
  • 内部容器不能直接调用 get()/set(),必须通过 JmsImage 管理
  • 开放容器不能调用 getByJmsImage()/setByJmsImage(),这些是内部方法
  • 容器释放后,JmsImage 不再持有该容器的引用

3. Handler - 处理器

处理器是 JmsImage 的灵魂! 所有图片处理逻辑都在 Handler 中实现。

所有处理器都实现了 ImageHandler 接口,该接口继承了:

(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 ); // 去除水印(6 种算法可选) 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); // 按比例压缩 50% new QualityCompressHandler(0.8f, true); // JPEG 质量 80%

(4)基础处理器(ImageBasicHandlers)

new AddNoiseHandler(100, true); // 添加 100 个噪点 new AddLinesHandler(50, true); // 添加 50 条随机线条

4. AbstractImageHandler - 抽象处理器基类

所有自定义处理器都应继承 AbstractImageHandler,它提供了:

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; // false 中断处理 } @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); // 统一处理所有 JmsImage 异常 }

💡 实战场景

场景 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; // false 中断处理 } @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()); } });

图片容器的高级用法

// 场景:需要在多个 JmsImage 之间共享图片 ImageContainer sharedContainer = new ImageContainer(); JmsImage image1 = JmsImage.read("image1.png"); JmsImage image2 = JmsImage.read("image2.png"); // 将 image1 的结果存入共享容器 image1.execute(handler1); sharedContainer.set(image1.getImage()); // 将共享容器的图片应用到 image2 image2.execute(handler2); image2.getImage(sharedContainer); // 最终从容器获取结果 BufferedImage finalResult = sharedContainer.get(); sharedContainer.destroy();

日志集成

// JmsImage 内置日志支持 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-with-resources try (JmsImage image = JmsImage.read("input.png")) { image.execute(handler).write("output.jpg"); } catch (IOException e) { logger.error("处理失败", e); } // ✅ 手动管理(必须确保 destroy) 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); // 没有 destroy() → 内存泄漏!

性能优化建议

// ① 应用启动时预热字体 @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(); } // ② 使用 JPEG 格式(比 PNG 快 5-10 倍) image.write("output.jpg"); // ✅ 快 image.write("output.png"); // ❌ 慢 // ③ 合理使用 autoDestroy image.execute(new Handler(true)); // ✅ 自动释放 image.execute(new Handler(false)); // ⚠️ 需要手动 destroy

📊 性能参考

基于实测数据(2MB 图片,960×1280):

操作 耗时 说明
Font 首次预热 ~700ms JVM 字体加载机制
图片加载(PNG) ~650ms IO 瓶颈
批量水印(378 个) ~30ms ✅ 框架性能优秀
图片保存(JPEG) ~70ms ✅ 很快
资源销毁 ~2ms ✅ 极快
结论

框架本身性能很好,瓶颈主要在 IO 和 JVM 机制。通过预热字体、使用 JPEG 格式,可以显著提升性能。

🎯 总结

JmsImage 的优势

适用场景

🚀 快速上手口诀

一读(read)、二处理(execute)、三保存(write)、四销毁(destroy)
Handler 传 true,资源不用愁
拦截器来把关,流程全掌控
历史栈开开关,撤销又重做
容器分内外,资源共享好

查看 API 文档