找回密码
 立即注册

QQ登录

只需一步,快速开始

Richard.Huang SpreadJS 开发认证

超级版主

40

主题

3180

帖子

4854

积分

超级版主

Rank: 8Rank: 8

积分
4854

SpreadJS 认证SpreadJS 高级认证

Richard.Huang SpreadJS 开发认证
超级版主   /  发表于:2024-5-27 15:47  /   查看:183  /  回复:0
本帖最后由 Richard.Huang 于 2024-5-27 16:08 编辑

背景
经过前面两篇枯燥的依赖准备以及底层原理讲解,相比大家都有些跃跃欲试了,这篇文章,是咱们的完结篇,详细分享了如何在代码上来实现这样一个将大象装入冰箱的效果。

步骤
大致流程
未命名绘图.drawio.png850116271.png
1. 继承PDFGraphicsStreamEngine类,便于分析PDF数据图层和资源归类
  1. public class OFDPageDrawer extends PDFGraphicsStreamEngine {
  2. }
复制代码
2. 重写构造方法,分析pdf每页的资源,并初始化OFD生成器
  1. /**
  2. * 构造器,调用super(page),这个操作的目的是将page资源准备好,并且添加对应的操作符,当下一次调用processPage或者processPageContentStream时执行对应的操作符对应的操作
  3. * @param idx
  4. * @param page
  5. * @param ofdCreator
  6. * @param scale
  7. * @throws IOException
  8. */
  9. protected OFDPageDrawer(int idx, PDPage page, OFDCreator ofdCreator, float scale) throws IOException {
  10.     super(page);
  11.     this.page = page;
  12.     this.ofdCreator = ofdCreator;
  13.     ctLayer = this.ofdCreator.createLayer();
  14.     this.scale = scale;
  15. }
复制代码
3. 重写drawImage方法收集整理pdf中分析出来的图片资源
  1. /**
  2. * 作用:将 PDF 图像对象转换为 OFD 格式进行绘制。此方法包括:
  3. *
  4. * 将图像写入字节流并保存。
  5. * 根据当前变换矩阵计算图像在页面上的位置和大小。
  6. * 创建 OFD 图像对象并设置其相关属性,然后添加到当前层中。
  7. *
  8. * @param pdImage
  9. * @throws IOException
  10. */
  11. @Override
  12. public void drawImage(PDImage pdImage) throws IOException {
  13.     ByteArrayOutputStream bosImage = new ByteArrayOutputStream();
  14.     String suffix = "png";
  15.     ImageIO.write(pdImage.getImage(), suffix, bosImage);
  16.     String name = String.format("%s.%s", bcMD5(bosImage.toByteArray()), suffix);
  17.     ofdCreator.putImage(name, bosImage.toByteArray(), suffix);

  18.     // 根据当前变换矩阵计算图像在页面上的位置和大小,实际上就是将PDF中该图像的属性信息转换成OFD中的形式
  19.     Matrix ctmNew = this.getGraphicsState().getCurrentTransformationMatrix();
  20.     float imageXScale = ctmNew.getScalingFactorX();
  21.     float imageYScale = ctmNew.getScalingFactorY();
  22.     double x = ctmNew.getTranslateX() * scale;
  23.     double y = (page.getCropBox().getHeight() - ctmNew.getTranslateY() - imageYScale) * scale;
  24.     double w = imageXScale * scale;
  25.     double h = imageYScale * scale;
  26.     ImageObject imageObject = new ImageObject(ofdCreator.getNextRid());
  27.     imageObject.setBoundary(x, y, w, h);
  28.     imageObject.setResourceID(new ST_RefID(ST_ID.getInstance(ofdCreator.getImageMap().get(name))));
  29.     imageObject.setCTM(ST_Array.getInstance(String.format("%.0f 0 0 %.0f 0 0", w, h)));
  30.     setImageClip(imageObject, x, y, w, h);
  31.     ctLayer.add(imageObject);
  32. }
复制代码
4. 通过继承PDFGraphicsStreamEngine类分析得到的文字内容重绘
  1. public void addPageContent(int idx, CT_Layer ctLayer, float width, float height) {
  2.     PageDir pageDirInv = new PageDir();// 资源归类
  3.     pageDirInv.setIndex(idx);
  4.     org.ofdrw.core.basicStructure.pageObj.Page pageInv = new org.ofdrw.core.basicStructure.pageObj.Page();
  5.     CT_PageArea areaInv = new CT_PageArea();// ofd可视区域(pdf的裁剪区)
  6.     areaInv.setPhysicalBox(0, 0, width, height);
  7.     pageInv.setArea(areaInv);
  8.     Content contentInv = new Content();// 内容
  9.     contentInv.addLayer(ctLayer);
  10.     pageInv.setContent(contentInv);
  11.     pageDirInv.setContent(pageInv);
  12.     docDir.getPages().add(pageDirInv);
  13. }
复制代码
5. 将收集到的资源进行打包生成OFD文件
  1. /**
  2. * 打包OFD文件包二进制数据
  3. *
  4. * @param virtualFileMap
  5. * @return
  6. * @throws IOException
  7. */
  8. public static void zip(Map<String, byte[]> virtualFileMap,OutputStream output) throws IOException {
  9.     ZipArchiveOutputStream zaos = new ZipArchiveOutputStream(output);

  10.     for (Map.Entry<String, byte[]> entry : virtualFileMap.entrySet()) {
  11.         zaos.putArchiveEntry(new ZipArchiveEntry(entry.getKey()));
  12.         zaos.write(entry.getValue());
  13.         zaos.closeArchiveEntry();
  14.     }

  15.     zaos.finish();
  16. }
复制代码

完整代码
GcExcelTestArea.rar (3.41 MB, 下载次数: 14)

0 个回复

您需要登录后才可以回帖 登录 | 立即注册
返回顶部