系列文章:
Java 操作 Office:POI 之 word 生成
Java 操作 Office:POI 之 word 图片处理
一 前言
在前面两篇,我们已经知道了 Java 通过 POI 生成 Word 表格、表格内插入图片,并在插入前对图片进行标注操作,本篇将再通过一个更贴近真实场景的案例的实现,来了解一下 poi 在 word 导出场景的实战应用。
二 需求
还是以 word 导出作为主体需求,考虑加载网络图片(通常来自内网,外网会考虑先下载到内网环境并保存内网地址,避免耗时过多),并对图片进行标注。这个标注的含义可能是图片某一个区域的标记物,也可能是识别出一些异常情况,通过特殊颜色的区域标识来突出表现。
三 分解实现
3.1 网络图片加载
如果您之前有写下载工具的经验,那么这将会是一个很简单的问题。使用已有的网络工具包会更简化这个过程。
这里假设没有过类似经历,我们一切从零开始。使用 Java 的 java.net 包来做实现。
String imageClueUrl = "http://192.168.1.1:8488/file/image/" +
"xxx.jpg";
FileOutputStream fos = null;
BufferedInputStream bis = null;
HttpURLConnection httpUrl = null;
URL url = null;
try {
url = new URL(imageClueUrl);
httpUrl = (HttpURLConnection) url.openConnection();
httpUrl.connect();
bis = new BufferedInputStream(httpUrl.getInputStream());
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (fos != null){
fos.close();
}
if (bis != null){
bis.close();
}
if (httpUrl != null){
httpUrl.disconnect();
}
} catch (IOException e) {
e.printStackTrace();
}
}
复制代码
通过上面代码,我们可以把图片地址读到 BufferedInputStream 流中。
3.2 图片标注
回顾前面两节内容,既然我们能拿到图片流,那么接下来在图片流中进行处理就好了。考虑在图片中绘制两个区域,是包含关系。一个多边形,一个矩形。矩形在多边形区域内。
XWPFParagraph paragraph = row2.get(1).getParagraphs().get(0);
XWPFRun run = paragraph.createRun();
String imageClueUrl = "http://10.153.106.16:8488/file/image/" +
"police@MjAyMTA4MDgvMTg3M2I0YmQxNmRkNDMzMjhiZTI4Y2RmMThiZDYwNzg=";
FileOutputStream fos = null;
BufferedInputStream bis = null;
HttpURLConnection httpUrl = null;
URL url = null;
try {
url = new URL(imageClueUrl);
httpUrl = (HttpURLConnection) url.openConnection();
httpUrl.connect();
bis = new BufferedInputStream(httpUrl.getInputStream());
BufferedImage image = ImageIO.read(bis);
double[] detectArea = {0.5147,0.0135,0.9886,0.0136,0.9847,0.9842,0.5083,0.9819};
BufferedImage bufferedImage = ImageUtil.addPolygon(image, detectArea, Color.blue);
String alertArea = "0.8390625,0.08981481,0.0734375,0.38055557";
List<Rectangle> rectangleList = ImageUtil.str2RectangleList(alertArea);
System.out.println(rectangleList);
bufferedImage = ImageUtil.addRects(bufferedImage, rectangleList, Color.red);
InputStream stream1 = ImageUtil.bufferedImageToInputStream(bufferedImage);
run.addPicture(stream1, XWPFDocument.PICTURE_TYPE_PNG, "Generated",
Units.toEMU(364), Units.toEMU(256));
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (fos != null){
fos.close();
}
if (bis != null){
bis.close();
}
if (httpUrl != null){
httpUrl.disconnect();
}
} catch (IOException e) {
e.printStackTrace();
}
}
复制代码
3.3 其他相关方法
3.3.1 矩形区域绘制
绘制矩形区域标注,支持传入颜色参数:
public static BufferedImage addPolygon(BufferedImage image, double[] arr, Color color) throws Exception {
Graphics2D g = (Graphics2D) image.getGraphics();
int width = image.getWidth();
int height = image.getHeight();
int length = arr.length / 2;
int[] realPxs = new int[length];
int[] realPys = new int[length];
for (int i=0; i < arr.length; i++){
if (i % 2 == 0){
realPxs[i / 2] = (int) (width * arr[i]);
}else {
realPys[(i - 1) / 2] = (int) (height * arr[i]);
}
}
g.setColor(color);
g.setStroke(new BasicStroke(5.0f));
g.drawPolygon(realPxs, realPys, length);
return image;
}
复制代码
3.3.2 绘制多边形
public static List<Rectangle> str2RectangleList(String position){
List<EmdRectangle> rectangleList = new ArrayList<>();
String[] positions = position.split(";");
for (String p : positions){
String[] location = p.split(",");
Rectangle rectangle = new Rectangle(Double.parseDouble(location[0]),
Double.parseDouble(location[1]),
Double.parseDouble(location[2]),
Double.parseDouble(location[3]));
rectangleList.add(rectangle);
}
return rectangleList;
}
复制代码
有一点需要注意,这里使用的实体类 Rectangle 不是 poi 包的,而是我们自己定义的。用于解决与包内 Rectangle 只支持参数为 int 型的问题。
3.3.3 实体类
import lombok.Data;
@Data
public class Rectangle {
public double x;
public double y;
public double width;
public double height;
public Rectangle(double x, double y, double width, double height) {
this.x = x;
this.y = y;
this.width = width;
this.height = height;
}
}
复制代码
四 总结
至此,对 word 导出的研究示例,我们暂时告一段落。等后面有更为复杂的真实需求时,欢迎留言进行探讨。我也会在后续进行更新。
技术本身并不复杂,尤其是本系列的示例,都是一些基础内容的拼接。虽然有几个小难点,但只要思路清晰,还是比较容易找到解决方案的。所以,核心还是在如果对问题进行整理、拆解上,选择合适的解决方案,就可以实现我们问题解决方案的完整拼图。
评论