写点什么

Java 操作 Office:POI 之 word 图片处理

发布于: 3 小时前
Java 操作 Office:POI之word图片处理

系列文章:

Java 操作 Office:POI 之 word 生成


一 背景问题

本系列旨在分享一些 word 操作框架 POI 的一些使用技巧,系统学习可直接参考官方文档,或上一篇中提到的 Apache POI Word(docx) 入门示例教程。更多交流可添加公众号【程序员架构进阶】一起探讨。

本篇是根据一个真实场景,探索的实现方法。我们有一些希望插入 word 的图片,在插入时也要对图片本身添加一些标注,例如红框标记等等,也可能是添加文字标注。如果是手工操作,这显然比较简单,使用美图秀秀、Photoshop 等工具,或只是截图工具中直接划线、添加文字就可以快速实现。但当需要处理的是批量数据,手工方式就不适合了。

二 一个简单的想法


因为最终是要写入 word,所以暂时考虑还是使用 XWPFRun.addPicture 方法在单元格插入图片。但下一步,我们要在执行插入前,对图片做完所需的处理动作。这里可以考虑 ImageIO 和 Graphics,这两个 Java 中的图片图形处理工具类来实现了。

三 Graphics

3.1 简介

java.awt.Graphics 是一个抽象类,根据源码中的文档描述,

Graphics 类是所有图形上下文的抽象基类,允许应用程序绘制在各种设备上实现的组件以及屏幕外图像上。

Graphics 的使用已经被很多人整理过,所以本篇就不再赘述。可以参考文章:Java Graphics类的绘图方法了解完整的使用方法。这里只抽取所需的方法介绍,并给出示例。

3.2 矩形绘制

在图片中绘制一个矩形,来代表框选区域,通过配合颜色选择(红橙黄),可以起到标示作用。矩形区域,我们按照从左到右的方向,可以简单用起点横坐标:x,起点纵坐标:y,以及宽度 width+高度 height 来确定。当然,其实宽度和高度也可以替换终点横坐标 和 终点纵坐标来标示。

在 Graphics 中绘制矩形的方法:

public void drawRect(int x, int y, int width, int height)
复制代码

3.3 多边形绘制

矩形只有四个点,显示中可能需要绘制复杂的多边形,那么上述方法就无法满足了。所以 Graphics 提供了一个更为通用的绘制多边形方法:

public abstract void drawPolygon(int xPoints[], int yPoints[],                                     int nPoints);
复制代码

参数的 xPoints,yPoints,nPoints 分别代表横坐标数组,纵坐标数组,线段个数;xPoints 和 yPoints 大小必须相同。

这个方法会绘制由 nPoint 个线段定义的多边形,其中前 nPoint - 1 个线段是 1 ≤ i ≤ 时从 (xPoints[i - 1], yPoints[i - 1]) 到 (xPoints[i], yPoints[i]) 的线段。如果最后一个点和第一个点不同,则图形会通过在这两点间绘制一条线段来自动闭合。

除了直接输入坐标,也可以通过传入定义的 Polygon 类来进行封装,使用 drawPolygon(Polygon p)实现绘制:

public void drawPolygon(Polygon p) {        drawPolygon(p.xpoints, p.ypoints, p.npoints);    }
复制代码

3.4 实现示例

/*** 添加多边形* @param imgFile* @return* @throws Exception*/public static BufferedImage addPolygon(String imgFile) throws Exception {        BufferedImage image = ImageIO.read(new File(imgFile));        Graphics g = image.getGraphics();
int px2[]={100,480,470,480,240,100,110,100}; int py2[]={155,175,185,395,315,185,175,155};
g.setColor(Color.red); g.drawPolygon(px2,py2,8);
return image;}
复制代码



四 处理结果写入 word

4.1 参数转换

接下来回到另一个关键问题:图片处理结果怎样写入 word? 先回顾一下上一篇的内容:

run.addPicture 接收的参数依次为:图片的 InputStream 流,图片类型,图片名称(非文件名),图片宽度、图片高度。通过这个方法,我们就可以把图片插入到指定的表格中,并设置图片的宽高属性。

对于图片输入,addPicture 要求的参数是 InputStream,而我们上面的图片处理结果,是 BufferedImage。显然是无法直接插入到 word 的 Cell 中的。那么该怎么办? 两种方法,要么另寻出路,看是否有图片处理完成的结果是 InputStream;要么就是想办法把 BufferedImage 转成 InputStream。

写到这里,我想起了一句话:『当手里有锤子,看什么都像钉子』。这句话本来是说容易养成思维定势,但在现实中,如果我们看到的东西限制在某些场景,例如金属制品,那么当我们的需求是把其他东西固定住时,考虑用手中的锤子把已有的材料加工成钉子来达到目的也未尝不可,尽管可能不是最佳的方法。当然,这种尝试并不是盲目的,而是在目标明确,且对材料和手中的工具有一定了解的情况下

话说回来,BufferedImage 本身也是一种流的结构,那么就存在着转为 ImputStream 的可能。

4.2 代码实现与示例

将BufferedImage转换为InputStream,亲测可用 这篇文章就给出了解决方法,所以采用了这段代码加以实现:

/** * 将BufferedImage转换为InputStream * @param image * @return */public static InputStream bufferedImageToInputStream(BufferedImage image){    ByteArrayOutputStream os = new ByteArrayOutputStream();    try {        ImageIO.write(image, "png", os);        InputStream input = new ByteArrayInputStream(os.toByteArray());        return input;    } catch (IOException e) {        e.printStackTrace();    }    return null;}
复制代码

通过这种方式,结合 Graphics 对图片的处理,得到的 word 导出结果如下图所示:

五 总结

在日常开发中,经常会遇到各种问题。排除不合理需求,解决困难的技术问题,保证项目的按时保质完成也是我们作为开发者的几项重要职责。在解决问题的过程中,明确目标、识别关键问题、搜索能力、问题拆解和解决能力都很重要。所谓的『经验』,就是在日常大大小小的考验过后沉淀下来的各项能力,而不只是经历。这点需要特别注意,与大家共勉。

发布于: 3 小时前阅读数: 4
用户头像

磨炼中成长,痛苦中前行 2017.10.22 加入

微信公众号【程序员架构进阶】。多年项目实践,架构设计经验。曲折中向前,分享经验和教训

评论

发布
暂无评论
Java 操作 Office:POI之word图片处理