当前位置:   article > 正文

ofd文件解析和操作小记_ofd 解析

ofd 解析

1. 之前研究ofd文件的一些总结,ofd文件的组成是由各种xml以及上下文组成,主要的还是要看ofd.xml这个文件是最主要,记录了ofd的类型以及来源等信息

2.pom.xml如下:需要注意log4j和slf4j设计到的包,可能会跟项目的上的jar冲突

  1. <!--ofd操作类-->
  2. <dependency>
  3. <groupId>org.ofdrw</groupId>
  4. <artifactId>ofdrw-full</artifactId>
  5. <version>2.0.5</version>
  6. <exclusions><!--ofd 转换时需要去掉 否则会报jar冲突以及启动堆栈溢出-->
  7. <exclusion>
  8. <groupId>org.apache.logging.log4j</groupId>
  9. <artifactId>log4j-slf4j-impl</artifactId>
  10. </exclusion>
  11. </exclusions>
  12. </dependency>

3. ofd的一些操作类

3.1  图片合成ofd

  1. import org.ofdrw.graphics2d.OFDGraphicsDocument;
  2. import org.ofdrw.graphics2d.OFDPageGraphics2D;
  3. import javax.imageio.ImageIO;
  4. import java.awt.image.BufferedImage;
  5. import java.io.File;
  6. import java.nio.file.Path;
  7. import java.nio.file.Paths;
  8. import java.util.ArrayList;
  9. /**
  10. * @Description //TODO
  11. * @Date 2023/06/01 15:38
  12. * @Author kdc
  13. **/
  14. public class ImageToOfd {
  15. /**
  16. * @description: 图片转pdf
  17. * @param: [文件路径, 图片路径,多图片已“,”分隔]
  18. **/
  19. public static JSONObject imageToOfd(String filepath, String imgUrl){
  20. JSONObject returnResult=new JSONObject();
  21. Path dst = Paths.get(filepath);
  22. try {
  23. // File files=new File(filepath);
  24. // files.createNewFile();
  25. OFDGraphicsDocument doc = new OFDGraphicsDocument(dst);
  26. int width=210;
  27. ArrayList<String> imageUrllist = new ArrayList<String>(); //图片list集合
  28. String[] imgUrls = imgUrl.split(",");
  29. for (int i=0; i<imgUrls.length; i++) {
  30. File sourceimage = new File(imgUrls[i]);
  31. BufferedImage image = ImageIO.read(sourceimage);
  32. int w = image.getWidth();
  33. int h = image.getHeight();
  34. double hh= width*1.0000/w;
  35. double higth= hh*h;
  36. OFDPageGraphics2D g = doc.newPage(width,higth);
  37. g.drawImage(image, 0, 0, width, (int) higth, null);
  38. g.dispose();
  39. doc.addResImg(image);
  40. }
  41. doc.close();
  42. System.out.println(">> " + dst.toAbsolutePath());
  43. returnResult.put("code", ResultCode.SUCCESS.getCode());
  44. returnResult.put("msg","ofd合成成功");
  45. returnResult.put("fileSize",new File(filepath).length());
  46. } catch (Exception e) {
  47. returnResult.put("code",ResultCode.ERROR.getCode());
  48. returnResult.put("msg","OFD合成失败");
  49. e.printStackTrace();
  50. }
  51. return returnResult;
  52. }

3.2    ofd按页数拆图

  1. import org.ofdrw.converter.ImageMaker;
  2. import org.ofdrw.reader.OFDReader;
  3. import javax.imageio.ImageIO;
  4. import java.awt.image.BufferedImage;
  5. import java.io.File;
  6. import java.io.IOException;
  7. import java.nio.file.Path;
  8. import java.nio.file.Paths;
  9. /**
  10. * @Description //TODO ofd转图
  11. * @Author kdc
  12. **/
  13. public class OfdToImage {
  14. //ofd文件所有也都转图
  15. public static JSONArray OfdToImageByPage(String rootPath, String file_id, String batchId, String filename, String type) {
  16. // 将pdf装图片 并且自定义图片得格式大小
  17. filename =filename.substring(0, filename.lastIndexOf("."));
  18. JSONArray returnObj = new JSONArray();
  19. String filepath =TecrunUtils.getFilePathFromBatchIdAndFileId(rootPath, batchId, file_id, 0);
  20. Path src=Paths.get(filepath);
  21. try{
  22. OFDReader reader = new OFDReader(src);
  23. ImageMaker imageMaker = new ImageMaker(reader, 15);
  24. for (int i = 0; i < imageMaker.pageSize(); i++) {
  25. // 4. 指定页码转换图片
  26. BufferedImage image = imageMaker.makePage(i);
  27. String newFileId = TecrunUtils.createFileId();
  28. String imageName=filename+"_"+i+"."+type;
  29. String imagePath = TecrunUtils.getFilePathFromBatchIdAndFileId(rootPath, batchId, newFileId, 0);
  30. String thumbImagePath = TecrunUtils.getFilePathFromBatchIdAndFileId(rootPath, batchId, newFileId, 1);
  31. // String imagePath=fileFloder+newFileId+"_0";
  32. // String thumbImagePath=fileFloder+newFileId+"_1.jpg";
  33. Path dist = Paths.get(imagePath);
  34. // 5. 存储为指定格式图片
  35. ImageIO.write(image, "png", dist.toFile());
  36. ///生成每一页的缩略图
  37. Thumbnails.of(imagePath).size(200, 200)
  38. .outputFormat("jpg").toFile(thumbImagePath);
  39. JSONObject ofdimage=new JSONObject();
  40. ofdimage.put("file_id",newFileId);
  41. ofdimage.put("imagePath",imagePath);
  42. ofdimage.put("thumbImagePath",thumbImagePath);
  43. ofdimage.put("file_name",imageName);
  44. ofdimage.put("file_size", new File(imagePath).length());
  45. ofdimage.put("file_suffix",type);
  46. returnObj.add(ofdimage);
  47. }
  48. System.out.println("ofdtoPic-ok");
  49. }catch(Exception e){
  50. e.printStackTrace();
  51. }
  52. return returnObj;
  53. }
  54. //ofd文件第一页转图
  55. public static JSONObject OfdToImageByPageOne(String rootPath, String file_id, String batchId, String filename, String type) {
  56. // 将pdf装图片 并且自定义图片得格式大小
  57. filename =filename.substring(0, filename.lastIndexOf("."));
  58. JSONObject ofdimage=new JSONObject();
  59. // JSONArray returnObj = new JSONArray();
  60. String filepath =TecrunUtils.getFilePathFromBatchIdAndFileId(rootPath, batchId, file_id, 0);
  61. Path src=Paths.get(filepath);
  62. try{
  63. OFDReader reader = new OFDReader(src);
  64. ImageMaker imageMaker = new ImageMaker(reader, 15);
  65. // 4. 指定页码转换图片
  66. BufferedImage image = imageMaker.makePage(0);
  67. String newFileId = TecrunUtils.createFileId();
  68. String imageName=filename+"_"+0+"."+type;
  69. String imagePath = TecrunUtils.getFilePathFromBatchIdAndFileId(rootPath, batchId, newFileId, 0);
  70. String thumbImagePath = TecrunUtils.getFilePathFromBatchIdAndFileId(rootPath, batchId, newFileId, 1);
  71. // String imagePath=fileFloder+newFileId+"_0";
  72. // String thumbImagePath=fileFloder+newFileId+"_1.jpg";
  73. Path dist = Paths.get(imagePath);
  74. // 5. 存储为指定格式图片
  75. ImageIO.write(image, "png", dist.toFile());
  76. ///生成每一页的缩略图
  77. Thumbnails.of(imagePath).size(200, 200)
  78. .outputFormat("jpg").toFile(thumbImagePath);
  79. ofdimage.put("file_id",newFileId);
  80. ofdimage.put("imagePath",imagePath);
  81. ofdimage.put("thumbImagePath",thumbImagePath);
  82. ofdimage.put("file_name",imageName);
  83. ofdimage.put("file_size", new File(imagePath).length());
  84. ofdimage.put("file_suffix",type);
  85. System.out.println("ofdtoPic-ok");
  86. }catch(Exception e){
  87. e.printStackTrace();
  88. }
  89. return ofdimage;
  90. }
  91. //ofd文件从那一页转图
  92. public static JSONArray OfdToImageByPageByIndex(String rootPath, String file_id, String batchId, String filename, String type,int Index) {
  93. // 将pdf装图片 并且自定义图片得格式大小
  94. filename =filename.substring(0, filename.lastIndexOf("."));
  95. JSONArray returnObj = new JSONArray();
  96. String filepath =TecrunUtils.getFilePathFromBatchIdAndFileId(rootPath, batchId, file_id, 0);
  97. Path src=Paths.get(filepath);
  98. try{
  99. OFDReader reader = new OFDReader(src);
  100. ImageMaker imageMaker = new ImageMaker(reader, 15);
  101. for (int i = Index; i < imageMaker.pageSize(); i++) {
  102. // 4. 指定页码转换图片
  103. BufferedImage image = imageMaker.makePage(i);
  104. String newFileId = TecrunUtils.createFileId();
  105. String imageName=filename+"_"+i+"."+type;
  106. String imagePath = TecrunUtils.getFilePathFromBatchIdAndFileId(rootPath, batchId, newFileId, 0);
  107. String thumbImagePath = TecrunUtils.getFilePathFromBatchIdAndFileId(rootPath, batchId, newFileId, 1);
  108. // String imagePath=fileFloder+newFileId+"_0";
  109. // String thumbImagePath=fileFloder+newFileId+"_1.jpg";
  110. Path dist = Paths.get(imagePath);
  111. // 5. 存储为指定格式图片
  112. ImageIO.write(image, "png", dist.toFile());
  113. ///生成每一页的缩略图
  114. Thumbnails.of(imagePath).size(200, 200)
  115. .outputFormat("jpg").toFile(thumbImagePath);
  116. JSONObject ofdimage=new JSONObject();
  117. ofdimage.put("file_id",newFileId);
  118. ofdimage.put("imagePath",imagePath);
  119. ofdimage.put("thumbImagePath",thumbImagePath);
  120. ofdimage.put("file_name",imageName);
  121. ofdimage.put("file_size", new File(imagePath).length());
  122. ofdimage.put("file_suffix",type);
  123. returnObj.add(ofdimage);
  124. }
  125. System.out.println("ofdtoPic-ok");
  126. }catch(Exception e){
  127. e.printStackTrace();
  128. }
  129. return returnObj;
  130. }
  131. //ofd文件所有也都转图
  132. public static JSONObject OfdToImageByPageNum(String rootPath, String file_id, String batchId, String filename, String type,int PageNum) {
  133. // 将pdf装图片 并且自定义图片得格式大小
  134. filename =filename.substring(0, filename.lastIndexOf("."));
  135. JSONObject ofdimage=new JSONObject();
  136. String filepath =TecrunUtils.getFilePathFromBatchIdAndFileId(rootPath, batchId, file_id, 0);
  137. Path src=Paths.get(filepath);
  138. OFDReader reader =null;
  139. ImageMaker imageMaker =null;
  140. BufferedImage image =null;
  141. try{
  142. reader = new OFDReader(src);
  143. imageMaker = new ImageMaker(reader, 15);
  144. // 4. 指定页码转换图片
  145. image = imageMaker.makePage(PageNum);
  146. String newFileId = TecrunUtils.createFileId();
  147. String imageName=filename+"_"+PageNum+"."+type;
  148. String imagePath = TecrunUtils.getFilePathFromBatchIdAndFileId(rootPath, batchId, newFileId, 0);
  149. String thumbImagePath = TecrunUtils.getFilePathFromBatchIdAndFileId(rootPath, batchId, newFileId, 1);
  150. // String imagePath=fileFloder+newFileId+"_0";
  151. // String thumbImagePath=fileFloder+newFileId+"_1.jpg";
  152. Path dist = Paths.get(imagePath);
  153. // 5. 存储为指定格式图片
  154. ImageIO.write(image, "png", dist.toFile());
  155. ///生成每一页的缩略图
  156. Thumbnails.of(imagePath).size(200, 200)
  157. .outputFormat("jpg").toFile(thumbImagePath);
  158. ofdimage.put("file_id",newFileId);
  159. ofdimage.put("imagePath",imagePath);
  160. ofdimage.put("thumbImagePath",thumbImagePath);
  161. ofdimage.put("file_name",imageName);
  162. ofdimage.put("file_size", new File(imagePath).length());
  163. ofdimage.put("file_suffix",type);
  164. System.out.println("ofdtoPic-ok");
  165. }catch(Exception e){
  166. e.printStackTrace();
  167. }finally {
  168. reader =null;
  169. imageMaker =null;
  170. image =null;
  171. }
  172. return ofdimage;
  173. }
  174. public static void main(String[] args) {
  175. OfdToImage.OfdToImageByPage("","","","","");
  176. }
  177. }

3.3 ofd发票的识别解析,这个类之前参照其他博主的修改过,目前来看比较标准的数电,电票等解析效果比较好

  1. import com.tecrun.common.utils.ConvertUpMoneyUtil;
  2. import lombok.extern.slf4j.Slf4j;
  3. import org.apache.commons.lang3.StringUtils;
  4. import org.dom4j.*;
  5. import org.dom4j.io.SAXReader;
  6. import org.springframework.util.StreamUtils;
  7. import java.io.ByteArrayInputStream;
  8. import java.io.File;
  9. import java.io.IOException;
  10. import java.io.InputStream;
  11. import java.nio.charset.Charset;
  12. import java.util.ArrayList;
  13. import java.util.List;
  14. import java.util.Objects;
  15. import java.util.zip.ZipEntry;
  16. import java.util.zip.ZipFile;
  17. /**
  18. * 专用于处理电子发票识别的类
  19. *
  20. *
  21. */
  22. @Slf4j
  23. public class OfdInvoiceExtractor {
  24. /*
  25. 解析ofd发票,但有局限,ofd文件解压后必须要有Doc_0/Attachs/original_invoice.xml这个
  26. */
  27. public static Invoice extract(File file) throws IOException, DocumentException {
  28. ZipFile zipFile = new ZipFile(file);
  29. ZipEntry entry = zipFile.getEntry("Doc_0/Attachs/original_invoice.xml");
  30. ZipEntry entry1 = zipFile.getEntry("Doc_0/Pages/Page_0/Content.xml");
  31. InputStream input = zipFile.getInputStream(entry);
  32. InputStream input1 = zipFile.getInputStream(entry1);
  33. String body = StreamUtils.copyToString(input, Charset.forName("utf-8"));
  34. String content = StreamUtils.copyToString(input1, Charset.forName("utf-8"));
  35. zipFile.close();
  36. Document document = DocumentHelper.parseText(body);
  37. Element root = document.getRootElement();
  38. Invoice invoice = new Invoice();
  39. invoice.setMachineNumber(root.elementTextTrim("MachineNo"));
  40. invoice.setCode(root.elementTextTrim("InvoiceCode"));
  41. invoice.setNumber(root.elementTextTrim("InvoiceNo"));
  42. invoice.setDate(root.elementTextTrim("IssueDate"));
  43. invoice.setChecksum(root.elementTextTrim("InvoiceCheckCode"));
  44. invoice.setAmount( root.elementTextTrim("TaxExclusiveTotalAmount"));
  45. invoice.setTaxAmount(root.elementTextTrim("TaxTotalAmount"));
  46. int ind = content.indexOf("圆整</ofd:TextCode>");
  47. invoice.setTotalAmountString(content.substring(content.lastIndexOf(">", ind) + 1, ind + 2));
  48. invoice.setTotalAmount(root.elementTextTrim("TaxInclusiveTotalAmount"));
  49. invoice.setPayee(root.elementTextTrim("Payee"));
  50. invoice.setReviewer(root.elementTextTrim("Checker"));
  51. invoice.setDrawer(root.elementTextTrim("InvoiceClerk"));
  52. int index = content.indexOf("</ofd:TextCode>");
  53. invoice.setTitle(content.substring(content.lastIndexOf(">", index) + 1, index));
  54. invoice.setType("普通发票");
  55. if (invoice.getTitle().contains("专用发票")) {
  56. invoice.setType("专用发票");
  57. } else if (invoice.getTitle().contains("通行费")) {
  58. invoice.setType("通行费");
  59. }
  60. invoice.setPassword(root.elementText("TaxControlCode"));
  61. Element buyer = root.element("Buyer");
  62. {
  63. invoice.setBuyerName(buyer.elementTextTrim("BuyerName"));
  64. invoice.setBuyerCode(buyer.elementTextTrim("BuyerTaxID"));
  65. invoice.setBuyerAddress(buyer.elementTextTrim("BuyerAddrTel"));
  66. invoice.setBuyerAccount(buyer.elementTextTrim("BuyerFinancialAccount"));
  67. }
  68. Element seller = root.element("Seller");
  69. {
  70. invoice.setSellerName(seller.elementTextTrim("SellerName"));
  71. invoice.setSellerCode(seller.elementTextTrim("SellerTaxID"));
  72. invoice.setSellerAddress(seller.elementTextTrim("SellerAddrTel"));
  73. invoice.setSellerAccount(seller.elementTextTrim("SellerFinancialAccount"));
  74. }
  75. Element details = root.element("GoodsInfos");
  76. {
  77. List<Detail> detailList = new ArrayList<>();
  78. List<Element> elements = details.elements();
  79. for (Element element : elements) {
  80. Detail detail = new Detail();
  81. detail.setName(element.elementTextTrim("Item"));
  82. detail.setAmount(element.elementTextTrim("Amount"));
  83. detail.setTaxAmount(element.elementTextTrim("TaxAmount"));
  84. detail.setCount(element.elementTextTrim("Quantity"));
  85. detail.setPrice(element.elementTextTrim("Price"));
  86. detail.setUnit(element.elementTextTrim("MeasurementDimension"));
  87. detail.setModel(element.elementTextTrim("Specification"));
  88. detail.setTaxRate(element.elementTextTrim("TaxScheme").replace("%", ""));
  89. detailList.add(detail);
  90. }
  91. invoice.setDetailList(detailList);
  92. }
  93. return invoice;
  94. }
  95. /**
  96. * 解析ofd文件
  97. * @param file
  98. * @return
  99. * @throws IOException
  100. * @throws DocumentException
  101. */
  102. public static Invoice extractOFD(File file) throws IOException, DocumentException {
  103. ZipFile zipFile = new ZipFile(file);
  104. Invoice invoice = new Invoice();
  105. ZipEntry entry = zipFile.getEntry("OFD.xml");
  106. InputStream input = zipFile.getInputStream(entry);
  107. String body = StreamUtils.copyToString(input, Charset.forName("utf-8"));
  108. String content ="";
  109. String bodyAttachs ="";
  110. String contentinputTags="";
  111. try {
  112. ZipEntry entry1 = zipFile.getEntry("Doc_0/Pages/Page_0/Content.xml");
  113. InputStream input1 = zipFile.getInputStream(entry1);
  114. content = StreamUtils.copyToString(input1, Charset.forName("utf-8"));
  115. ZipEntry entryAttachs = zipFile.getEntry("Doc_0/Attachs/original_invoice.xml");
  116. ZipEntry CustomTag = zipFile.getEntry("Doc_0/Tags/CustomTag.xml");
  117. InputStream inputTags = zipFile.getInputStream(CustomTag);
  118. contentinputTags = StreamUtils.copyToString(inputTags, Charset.forName("utf-8"));
  119. if(null!=entryAttachs){
  120. InputStream inputAttachs = zipFile.getInputStream(entryAttachs);
  121. bodyAttachs = StreamUtils.copyToString(inputAttachs, Charset.forName("utf-8"));
  122. }else{
  123. log.info("不是标准发票!!!!没有Doc_0/Attachs/original_invoice.xml");
  124. // return invoice;
  125. }
  126. }catch (Exception ex) {
  127. ex.getMessage();
  128. System.out.println("不是发票!");
  129. return invoice;
  130. }
  131. zipFile.close();
  132. Document document = DocumentHelper.parseText(body);
  133. Element root = document.getRootElement();
  134. String DocBody = root.elementTextTrim("DocBody");
  135. System.out.println(DocBody);
  136. System.out.println(root.attributeValue("DocType"));用此判断是否ofd文件
  137. System.out.println(root.getName());
  138. List<Element> contactList =root.elements("DocBody");
  139. if ( !contactList.isEmpty() &&contactList.size()==1){
  140. Element docinfo= contactList.get(0);
  141. List<Element> docinfoList =docinfo.elements("DocInfo");
  142. if ( !docinfoList.isEmpty() &&docinfoList.size()==1){
  143. Element info= docinfoList.get(0);
  144. String CreationDate=info.elementTextTrim("CreationDate");
  145. System.out.println(CreationDate);
  146. List<Element> CustomDatas = info.elements("CustomDatas");
  147. if ( !CustomDatas.isEmpty() &&CustomDatas.size()>0){
  148. Element CustomData= CustomDatas.get(0);
  149. List<Element> Data= CustomData.elements("CustomData");
  150. for (Element element : Data) {
  151. String name=element.attributeValue("Name");
  152. System.out.println(name);
  153. if("发票代码".equals(name)){
  154. invoice.setCode(element.getText());
  155. 以此区分是不是全电发票,普通票有发票代码,
  156. invoice.setFormat("200");
  157. }else {
  158. invoice.setFormat("300");
  159. }
  160. if("发票号码".equals(name)){
  161. invoice.setNumber(element.getText());
  162. }
  163. if("合计税额".equals(name)){
  164. invoice.setTaxAmount(element.getText());
  165. }
  166. if("合计金额".equals(name)){
  167. invoice.setAmount(element.getText());
  168. }
  169. if("开票日期".equals(name)){
  170. invoice.setDate(element.getText());
  171. }
  172. if("校验码".equals(name)){
  173. invoice.setChecksum(element.getText());
  174. }
  175. if("购买方纳税人识别号".equals(name)){
  176. invoice.setBuyerCode(element.getText());
  177. }
  178. if("销售方纳税人识别号".equals(name)){
  179. invoice.setSellerCode(element.getText());
  180. }
  181. String text=element.getText();
  182. System.out.println(text);
  183. }
  184. }else {
  185. System.out.println("不是标准发票!!!!");
  186. return invoice;
  187. }
  188. }
  189. }
  190. ///解析的是Doc_0/Attachs/original_invoice.xml可有一些ofd发票不会有这个xml但是肯定有OFD.xml 必然能提取出发票代码等信息
  191. if(!"".equals(bodyAttachs)){
  192. Document documentAttachs = DocumentHelper.parseText(bodyAttachs);
  193. Element rootAttachs = documentAttachs.getRootElement();
  194. invoice.setMachineNumber(rootAttachs.elementTextTrim("MachineNo"));
  195. // invoice.setCode(rootAttachs.elementTextTrim("InvoiceCode"));
  196. // invoice.setNumber(rootAttachs.elementTextTrim("InvoiceNo"));
  197. // invoice.setDate(rootAttachs.elementTextTrim("IssueDate"));
  198. // invoice.setChecksum(rootAttachs.elementTextTrim("InvoiceCheckCode"));
  199. // invoice.setAmount( rootAttachs.elementTextTrim("TaxExclusiveTotalAmount"));spire.pdf.free
  200. // invoice.setTaxAmount(rootAttachs.elementTextTrim("TaxTotalAmount"));
  201. int ind = content.indexOf("圆整</ofd:TextCode>");
  202. invoice.setTotalAmountString(content.substring(content.lastIndexOf(">", ind) + 1, ind + 2));
  203. int index = content.indexOf("</ofd:TextCode>");
  204. invoice.setTitle(content.substring(content.lastIndexOf(">", index) + 1, index));
  205. invoice.setTotalAmount(rootAttachs.elementTextTrim("TaxInclusiveTotalAmount"));
  206. invoice.setPayee(rootAttachs.elementTextTrim("Payee"));
  207. invoice.setReviewer(rootAttachs.elementTextTrim("Checker"));
  208. invoice.setDrawer(rootAttachs.elementTextTrim("InvoiceClerk"));
  209. invoice.setType("普通发票");
  210. if ("200".equals(invoice.getFormat())){
  211. invoice.setFormat("202");
  212. }else if ("300".equals(invoice.getFormat())){
  213. invoice.setFormat("302");
  214. }
  215. if (invoice.getTitle().contains("专用发票")) {
  216. invoice.setType("专用发票");
  217. if ("200".equals(invoice.getFormat())){
  218. invoice.setFormat("201");
  219. }else if ("300".equals(invoice.getFormat())){
  220. invoice.setFormat("301");
  221. }
  222. } else if (invoice.getTitle().contains("通行费")) {
  223. invoice.setType("通行费");
  224. }
  225. invoice.setPassword(rootAttachs.elementText("TaxControlCode"));
  226. Element buyer = rootAttachs.element("Buyer");
  227. {
  228. invoice.setBuyerName(buyer.elementTextTrim("BuyerName"));
  229. // invoice.setBuyerCode(buyer.elementTextTrim("BuyerTaxID"));
  230. invoice.setBuyerAddress(buyer.elementTextTrim("BuyerAddrTel"));
  231. invoice.setBuyerAccount(buyer.elementTextTrim("BuyerFinancialAccount"));
  232. }
  233. Element seller = rootAttachs.element("Seller");
  234. {
  235. invoice.setSellerName(seller.elementTextTrim("SellerName"));
  236. // invoice.setSellerCode(seller.elementTextTrim("SellerTaxID"));
  237. invoice.setSellerAddress(seller.elementTextTrim("SellerAddrTel"));
  238. invoice.setSellerAccount(seller.elementTextTrim("SellerFinancialAccount"));
  239. }
  240. Element details = rootAttachs.element("GoodsInfos");
  241. {
  242. List<Detail> detailList = new ArrayList<>();
  243. List<Element> elements = details.elements();
  244. for (Element element : elements) {
  245. Detail detail = new Detail();
  246. detail.setName(element.elementTextTrim("Item"));
  247. detail.setAmount(element.elementTextTrim("Amount"));
  248. detail.setTaxAmount(element.elementTextTrim("TaxAmount"));
  249. detail.setCount(element.elementTextTrim("Quantity"));
  250. detail.setPrice(element.elementTextTrim("Price"));
  251. detail.setUnit(element.elementTextTrim("MeasurementDimension"));
  252. detail.setModel(element.elementTextTrim("Specification"));
  253. detail.setTaxRate(element.elementTextTrim("TaxScheme").replace("%", ""));
  254. detailList.add(detail);
  255. }
  256. invoice.setDetailList(detailList);
  257. }
  258. }else if(!"".equals(contentinputTags)){
  259. Element rootAttachs =null;
  260. Element Layer =null;
  261. try {
  262. Document documentAttachs = DocumentHelper.parseText(contentinputTags);
  263. rootAttachs = documentAttachs.getRootElement();
  264. Document contentstr = DocumentHelper.parseText(content);
  265. Element contentAttachs = contentstr.getRootElement();
  266. Element Content = contentAttachs.element("Content");
  267. // List<Node> list1 = Content.content();
  268. Layer = Content.element("Layer");
  269. }catch (Exception ce){
  270. log.error("ofd文件解析出错!!"+ce.getMessage());
  271. ce.printStackTrace();
  272. return invoice;
  273. }
  274. //
  275. // List<Node> list = Layer.content();
  276. // for( Node attribute:list){
  277. // String ss= attribute.getText();
  278. // Document ss1= attribute.getDocument();
  279. // Element ss2= ss1.getRootElement();
  280. // System.out.println(1);
  281. // }
  282. //
  283. // Attribute att=Layer.attribute("ID");
  284. // String value=att.getValue();//6946
  285. // Element TextObject = Layer.element("TextObject");
  286. // List<Attribute> attrlist=TextObject.attributes();
  287. //
  288. // Element TextCode = TextObject.element("TextCode");
  289. Element Buyer = rootAttachs.element("Buyer");
  290. if(Buyer!=null){
  291. Element BuyerName = Buyer.element("BuyerName");
  292. String BuyerNameObjectRef="";
  293. if(BuyerName!=null){
  294. BuyerNameObjectRef=BuyerName.elementTextTrim("ObjectRef");
  295. Element b=Layer.elementByID(BuyerNameObjectRef);
  296. String s=b.element("TextCode").getText();
  297. invoice.setBuyerName(s);
  298. }
  299. Element BuyerTaxID = Buyer.element("BuyerTaxID");
  300. String BuyerTaxIDObjectRef="";
  301. if(BuyerTaxID!=null){
  302. BuyerTaxIDObjectRef=BuyerTaxID.elementTextTrim("ObjectRef");
  303. Element b=Layer.elementByID(BuyerTaxIDObjectRef);
  304. String s=b.element("TextCode").getText();
  305. invoice.setBuyerCode(s);
  306. }
  307. Element BuyerAddrTel = Buyer.element("BuyerAddrTel");
  308. String BuyerAddrTelObjectRef="";
  309. if(BuyerAddrTel!=null){
  310. BuyerAddrTelObjectRef=BuyerAddrTel.elementTextTrim("ObjectRef");
  311. Element b=Layer.elementByID(BuyerAddrTelObjectRef);
  312. String s=b.element("TextCode").getText();
  313. invoice.setBuyerAddress(s);
  314. }
  315. Element BuyerFinancialAccount = Buyer.element("BuyerFinancialAccount");
  316. String BuyerFinancialAccountObjectRef="";
  317. if(BuyerFinancialAccount!=null){
  318. BuyerFinancialAccountObjectRef=BuyerFinancialAccount.elementTextTrim("ObjectRef");
  319. Element b=Layer.elementByID(BuyerFinancialAccountObjectRef);
  320. String s=b.element("TextCode").getText();
  321. invoice.setBuyerAccount(s);
  322. }
  323. }
  324. Element seller = rootAttachs.element("Seller");
  325. if(seller!=null) {
  326. Element SellerName = seller.element("SellerName");
  327. String SellerNameRef="";
  328. if(SellerName!=null){
  329. SellerNameRef=SellerName.elementTextTrim("ObjectRef");
  330. Element b=Layer.elementByID(SellerNameRef);
  331. String s=b.element("TextCode").getText();
  332. invoice.setSellerName(s);
  333. }
  334. Element SellerTaxID = seller.element("SellerTaxID");
  335. String SellerTaxIDRef="";
  336. if(SellerTaxID!=null){
  337. SellerTaxIDRef=SellerTaxID.elementTextTrim("ObjectRef");
  338. Element b=Layer.elementByID(SellerTaxIDRef);
  339. String s=b.element("TextCode").getText();
  340. invoice.setSellerCode(s);
  341. }
  342. Element SellerAddrTel = seller.element("SellerAddrTel");
  343. String SellerAddrTelRef="";
  344. if(SellerAddrTel!=null){
  345. SellerAddrTelRef=SellerAddrTel.elementTextTrim("ObjectRef");
  346. Element b=Layer.elementByID(SellerAddrTelRef);
  347. String s=b.element("TextCode").getText();
  348. invoice.setSellerAddress(s);
  349. }
  350. Element SellerFinancialAccount = seller.element("SellerFinancialAccount");
  351. String SellerFinancialAccountRef="";
  352. if(SellerFinancialAccount!=null){
  353. SellerFinancialAccountRef=SellerFinancialAccount.elementTextTrim("ObjectRef");
  354. Element b=Layer.elementByID(SellerFinancialAccountRef);
  355. String s=b.element("TextCode").getText();
  356. invoice.setSellerAccount(s);
  357. }
  358. }
  359. {
  360. Element InvoiceNo1= rootAttachs.element("InvoiceNo");///发票号码
  361. if(InvoiceNo1!=null && StringUtils.isBlank(invoice.getNumber())){
  362. String ref=InvoiceNo1.elementTextTrim("ObjectRef");
  363. Element b=Layer.elementByID(ref);
  364. String s=b.element("TextCode").getText();
  365. invoice.setNumber(s);
  366. }
  367. Element InvoiceCode= rootAttachs.element("InvoiceCode");///发票代码
  368. if(InvoiceCode!=null && StringUtils.isBlank(invoice.getCode())){
  369. String ref=InvoiceCode.elementTextTrim("ObjectRef");
  370. Element b=Layer.elementByID(ref);
  371. String s=b.element("TextCode").getText();
  372. invoice.setCode(s);
  373. }
  374. Element IssueDate= rootAttachs.element("IssueDate");开票日期
  375. if(IssueDate!=null && StringUtils.isBlank(invoice.getDate())){
  376. String ref=IssueDate.elementTextTrim("ObjectRef");
  377. Element b=Layer.elementByID(ref);
  378. String s=b.element("TextCode").getText();
  379. invoice.setDate(s);
  380. }
  381. Element TaxInclusiveTotalAmount= rootAttachs.element("TaxInclusiveTotalAmount");价税合计 小写
  382. if(TaxInclusiveTotalAmount!=null && StringUtils.isBlank(invoice.getTotalAmount())){
  383. List<Element> ObjectReflist=TaxInclusiveTotalAmount.elements("ObjectRef");
  384. String s="";
  385. for(Element obj:ObjectReflist){
  386. String ref=obj.getText();
  387. Element b=Layer.elementByID(ref);
  388. if (Objects.nonNull(b)) {
  389. s+=b.element("TextCode").getText();
  390. }
  391. }
  392. invoice.setTotalAmount(s.replaceAll("¥",""));
  393. invoice.setTotalAmountString(ConvertUpMoneyUtil.toChinese(invoice.getTotalAmount()));
  394. }
  395. Element TaxExclusiveTotalAmount= rootAttachs.element("TaxExclusiveTotalAmount");合计金额
  396. if(TaxExclusiveTotalAmount!=null && StringUtils.isBlank(invoice.getAmount())){
  397. List<Element> ObjectReflist=TaxExclusiveTotalAmount.elements("ObjectRef");
  398. String s="";
  399. for(Element obj:ObjectReflist){
  400. String ref=obj.getText();
  401. Element b=Layer.elementByID(ref);
  402. s+=b.element("TextCode").getText();
  403. }
  404. invoice.setAmount(s.replaceAll("¥",""));
  405. }
  406. Element TaxTotalAmount= rootAttachs.element("TaxTotalAmount");合计税额
  407. if(TaxTotalAmount!=null && StringUtils.isBlank(invoice.getTaxAmount())){
  408. List<Element> ObjectReflist=TaxTotalAmount.elements("ObjectRef");
  409. String s="";
  410. for(Element obj:ObjectReflist){
  411. String ref=obj.getText();
  412. Element b=Layer.elementByID(ref);
  413. s+=b.element("TextCode").getText();
  414. }
  415. invoice.setTaxAmount(s);
  416. }
  417. Element InvoiceClerk= rootAttachs.element("InvoiceClerk");开票人
  418. if(InvoiceClerk!=null && StringUtils.isBlank(invoice.getDrawer())){
  419. String ref=InvoiceClerk.elementTextTrim("ObjectRef");
  420. Element b=Layer.elementByID(ref);
  421. String s=b.element("TextCode").getText();
  422. invoice.setDrawer(s);
  423. }
  424. }
  425. }
  426. if (StringUtils.isBlank(invoice.getTotalAmountString())){
  427. int ind = content.indexOf("圆整</ofd:TextCode>");
  428. invoice.setTotalAmountString(content.substring(content.lastIndexOf(">", ind) + 1, ind + 2));
  429. }
  430. if (StringUtils.isBlank(invoice.getTitle())) {
  431. int index = content.indexOf("</ofd:TextCode>");
  432. invoice.setTitle(content.substring(content.lastIndexOf(">", index) + 1, index));
  433. }
  434. return invoice;
  435. }
  436. public static void main(String[] args) {
  437. try {
  438. Invoice Invoice= OfdInvoiceExtractor.extractOFD(new File("D:\\Desktop\\11169068(2).ofd"));
  439. // Invoice Invoice= OfdInvoiceExtractor.extractOFD(new File("D:\\Desktop\\ofd\\OFD\\dzfp_23512000000051695287_20230726100031.ofd"));
  440. System.out.println(Invoice.toString());
  441. // VoucherFileInfo json=api.VoucherFileUtil.extractXBRLFromOFD("D:\\Desktop\\ofd\\OFD\\dzfp_23512000000051695287_20230726100031.ofd");
  442. // System.out.println(json.toString());
  443. } catch (IOException e) {
  444. e.printStackTrace();
  445. } catch (DocumentException e) {
  446. e.printStackTrace();
  447. } catch (Exception e) {
  448. e.printStackTrace();
  449. }
  1. public class Invoice {
  2. private String format;//版式 电票目前支持 传统增票(专票201、普票202,200),全电发票(专票301、普票302,300)
  3. private String title; //发票名称
  4. private String machineNumber;//机器编号
  5. private String code;//发票代码
  6. private String number;//发票号码
  7. private String date;///开票日期
  8. private String checksum;//校验码
  9. private String buyerName; //购买方名字
  10. private String buyerCode; //购买方纳税人识别号
  11. private String buyerAddress; //购买方地址
  12. private String buyerAccount;//购买方账号
  13. private String password;//密码区
  14. private String amount;//合计金额
  15. private String taxAmount;//合计税额
  16. private String totalAmountString;
  17. private String totalAmount;//合计
  18. private String sellerName;//销售方名称
  19. private String sellerCode;//销售方纳税人识别号
  20. private String sellerAddress;//销售方地址电话
  21. private String sellerAccount;//销售方开户行及账号
  22. private String payee;//收款人
  23. private String reviewer;//复核人
  24. private String drawer;//开票人
  25. private String type;//发票类型 如type=普通发票,
  26. private List<Detail> detailList; //明细
  27. }
  28. public class Detail {
  29. private String name;
  30. private String model;
  31. private String unit;
  32. private String count;
  33. private String price;
  34. private String amount;
  35. private String taxRate;
  36. private String taxAmount;
  37. }

4. ofd内容的操作

4.1  内容抽取测试用例

  1. import org.ofdrw.core.basicStructure.doc.CT_PageArea;
  2. import org.ofdrw.reader.ContentExtractor;
  3. import org.ofdrw.reader.OFDReader;
  4. import org.ofdrw.reader.extractor.ExtractorFilter;
  5. import org.ofdrw.reader.extractor.RegionTextExtractorFilter;
  6. import java.awt.*;
  7. import java.io.IOException;
  8. import java.nio.file.Path;
  9. import java.nio.file.Paths;
  10. import java.util.List;
  11. /**
  12. * 内容抽取测试用例
  13. *
  14. */
  15. public class ContentExtractorTest {
  16. public static Path src = Paths.get("C:/Users/kong/Desktop/ofd/MutiLayer.ofd");
  17. /**
  18. * 提取指定页面的文本
  19. */
  20. public static void getPageContent() throws IOException {
  21. try (OFDReader reader = new OFDReader(src)) {
  22. ContentExtractor extractor = new ContentExtractor(reader);
  23. List<String> pageContent = extractor.getPageContent(1);
  24. System.out.println(pageContent);
  25. // assertEquals(pageContent.size(), 1);
  26. // assertEquals("你好呀,OFD Reader&Writer!", pageContent.get(0));
  27. }
  28. }
  29. /**
  30. * 提取矩形区域内的文字
  31. */
  32. public static void extractByFilter() throws IOException {
  33. try (OFDReader reader = new OFDReader("C:/Users/kong/Desktop/ofd/keyword.ofd")) {
  34. CT_PageArea area = reader.getPage(1).getArea();
  35. System.out.println(area.getPhysicalBox());
  36. Rectangle rectangle = new Rectangle(0, 0, 283, 120);
  37. ExtractorFilter filter = new RegionTextExtractorFilter(rectangle);
  38. ContentExtractor extractor = new ContentExtractor(reader, filter);
  39. List<String> pageContent = extractor.getPageContent(1);
  40. System.out.println(pageContent);
  41. }
  42. }
  43. /**
  44. * 提取所有页面出现的文本
  45. */
  46. public static void extractAll() throws IOException {
  47. Path src = Paths.get("C:/Users/kong/Desktop/ofd/2.ofd");
  48. try (OFDReader reader = new OFDReader(src)) {
  49. ContentExtractor extractor = new ContentExtractor(reader);
  50. List<String> pageContent = extractor.extractAll();
  51. System.out.println(pageContent);
  52. // assertEquals(pageContent.size(), 1);
  53. // assertEquals("你好呀,OFD Reader&Writer!", pageContent.get(0));
  54. }
  55. }
  56. /**
  57. * 含有PageBlock包裹的对象的文字提取测试
  58. */
  59. public static void extractAllPageBlock() throws IOException {
  60. Path src = Paths.get("C:/Users/kong/Desktop/ofd/helloworld_with_pageblock.ofd");
  61. try (OFDReader reader = new OFDReader(src)) {
  62. ContentExtractor extractor = new ContentExtractor(reader);
  63. List<String> pageContent = extractor.extractAll();
  64. System.out.println(pageContent);
  65. // assertEquals(pageContent.size(), 1);
  66. // assertEquals("你好呀,OFD Reader&Writer!", pageContent.get(0));
  67. }
  68. }
  69. /**
  70. * 页面内容迭代器,通过迭代器可以实现对每一页的内容处理
  71. */
  72. public static void traverse() throws IOException {
  73. Path src = Paths.get("C:/Users/kong/Desktop/ofd/2月乡厨发票(芳草地).ofd");
  74. try (OFDReader reader = new OFDReader(src)) {
  75. ContentExtractor extractor = new ContentExtractor(reader);
  76. extractor.traverse((pageNum, contents) -> {
  77. System.out.println(contents);
  78. // 在这里你可以做些你喜欢的事情
  79. // assertEquals(contents.size(), 1);
  80. // assertEquals("你好呀,OFD Reader&Writer!", contents.get(0));
  81. });
  82. }
  83. }
  84. }

4.2  文档编辑示例

  1. import org.ofdrw.core.action.actionType.actionGoto.CT_Dest;
  2. import org.ofdrw.core.action.actionType.actionGoto.DestType;
  3. import org.ofdrw.core.basicStructure.doc.Document;
  4. import org.ofdrw.core.basicStructure.doc.bookmark.Bookmark;
  5. import org.ofdrw.core.basicStructure.doc.bookmark.Bookmarks;
  6. import org.ofdrw.core.basicType.ST_Box;
  7. import org.ofdrw.core.basicType.ST_ID;
  8. import org.ofdrw.layout.OFDDoc;
  9. import org.ofdrw.layout.PageLayout;
  10. import org.ofdrw.layout.StreamCollect;
  11. import org.ofdrw.layout.VirtualPage;
  12. import org.ofdrw.layout.edit.AdditionVPage;
  13. import org.ofdrw.layout.edit.Attachment;
  14. import org.ofdrw.layout.element.*;
  15. import org.ofdrw.reader.OFDReader;
  16. import java.io.IOException;
  17. import java.nio.file.Path;
  18. import java.nio.file.Paths;
  19. /**
  20. * 文档编辑示例
  21. */
  22. public class DocEditDemos {
  23. /**
  24. * 向文档中插入页面新的页面使用模板作为背景
  25. */
  26. public static void vPageUseTemplateTest() throws IOException {
  27. Path srcP = Paths.get("C:/Users/kong/Desktop/ofd", "fptpl.ofd");
  28. Path outP = Paths.get("C:/Users/kong/Desktop/ofd/template_insert.ofd");
  29. try (OFDReader reader = new OFDReader(srcP);
  30. OFDDoc ofdDoc = new OFDDoc(reader, outP)) {
  31. final ST_Box box = reader.getPageSize(1);
  32. final PageLayout pageBox = new PageLayout(box);
  33. VirtualPage vPage2 = new VirtualPage(pageBox);
  34. Path imgPath = Paths.get("C:/Users/kong/Desktop/ofd", "eg_tulip.jpg");
  35. Img img = new Img(80, 53, imgPath);
  36. double x = (pageBox.getWidth() - img.getWidth()) / 2;
  37. double y = (pageBox.getHeight() - img.getHeight()) / 2;
  38. img.setPosition(Position.Absolute)
  39. .setX(x).setY(y);
  40. img.setBorder(0.5d);
  41. vPage2.add(img);
  42. vPage2.addTemplate("9", null);
  43. // 插入
  44. ofdDoc.addVPage(vPage2);
  45. }
  46. System.out.println(">> 生成文档位置:" + outP.toAbsolutePath());
  47. }
  48. /**
  49. * 向已有文档中 插入 流式布局的内容
  50. */
  51. public static void streamInsertTest() throws IOException {
  52. Path srcP = Paths.get("C:/Users/kong/Desktop/ofd", "拿来主义_page6.ofd");
  53. Path outP = Paths.get("C:/Users/kong/Desktop/ofd/StreamInserted.ofd");
  54. try (OFDReader reader = new OFDReader(srcP);
  55. OFDDoc ofdDoc = new OFDDoc(reader, outP)) {
  56. // 插入到第1页 位置,后面的所有内容从第1页开始递增
  57. StreamCollect sPage1 = new StreamCollect(1);
  58. sPage1.setPageNum(1);
  59. Paragraph p = new Paragraph("封面", 30d).setWidth(100d);
  60. sPage1.add(p);
  61. // 换页: 插入占位符告诉解析器
  62. sPage1.add(new PageAreaFiller());
  63. // 这里开始 第2页 内容
  64. Paragraph p2 = new Paragraph("前言", 15d).setWidth(40d);
  65. sPage1.add(p2);
  66. ofdDoc.addStreamCollect(sPage1);
  67. // 插入到最后一页
  68. Paragraph p3 = new Paragraph("尾页", 15d).setWidth(100d);
  69. ofdDoc.add(p3);
  70. }
  71. System.out.println("生成文档位置:" + outP.toAbsolutePath().toString());
  72. }
  73. /**
  74. * 向文档的指定页码插入页面
  75. * 原来位置上以及之后的页面,页面将会往后移动
  76. */
  77. public static void pageInsertTest() throws IOException {
  78. Path srcP = Paths.get("C:/Users/kong/Desktop/ofd", "拿来主义_page6.ofd");
  79. Path outP = Paths.get("C:/Users/kong/Desktop/ofd/PageInserted.ofd");
  80. try (OFDReader reader = new OFDReader(srcP);
  81. OFDDoc ofdDoc = new OFDDoc(reader, outP)) {
  82. PageLayout pageLayout = ofdDoc.getPageLayout();
  83. VirtualPage vPage1 = new VirtualPage(pageLayout);
  84. // 插入到第1页
  85. vPage1.setPageNum(1);
  86. Paragraph p = new Paragraph("封面", 30d);
  87. p.setPosition(Position.Absolute);
  88. p.setXY(60d, 60d);
  89. p.setWidth(100d);
  90. vPage1.add(p);
  91. ofdDoc.addVPage(vPage1);
  92. VirtualPage vPage2 = new VirtualPage(pageLayout);
  93. // 插入到第2页
  94. vPage2.setPageNum(2);
  95. Paragraph p2 = new Paragraph("前言", 15d);
  96. p2.setPosition(Position.Absolute);
  97. p2.setXY(20d, 20d);
  98. p2.setWidth(40d);
  99. vPage2.add(p2);
  100. ofdDoc.addVPage(vPage2);
  101. // 插入到最后一页
  102. VirtualPage vPage3 = new VirtualPage(pageLayout);
  103. Paragraph p3 = new Paragraph("尾页", 15d);
  104. p3.setPosition(Position.Absolute);
  105. p3.setXY(60d, 60d);
  106. p3.setWidth(100d);
  107. vPage3.add(p3);
  108. ofdDoc.addVPage(vPage3);
  109. }
  110. System.out.println("生成文档位置:" + outP.toAbsolutePath().toString());
  111. }
  112. /**
  113. * 向已经存在页面内追加内容那
  114. */
  115. public static void addContent2ExistPageTest() throws IOException {
  116. Path srcP = Paths.get("C:/Users/kong/Desktop/ofd", "helloworld.ofd");
  117. Path outP = Paths.get("C:/Users/kong/Desktop/ofd/EditedDoc.ofd");
  118. try (OFDReader reader = new OFDReader(srcP);
  119. OFDDoc ofdDoc = new OFDDoc(reader, outP)) {
  120. AdditionVPage avPage = ofdDoc.getAVPage(1);
  121. Div e = new Div(10d, 10d)
  122. .setPosition(Position.Absolute)
  123. .setX(70d).setY(113.5)
  124. .setBackgroundColor(255, 192, 203)
  125. .setBorder(0.353d)
  126. .setPadding(5d);
  127. Paragraph p = new Paragraph("测试文字测试文字测试文字测试文字", 15d)
  128. .setPosition(Position.Absolute)
  129. .setX(50d).setY(50d)
  130. .setWidth(50d)
  131. .setBorderColor(255, 0, 0)
  132. .setBorder(3d)
  133. .setPadding(3d);
  134. avPage.add(e);
  135. avPage.add(p);
  136. }
  137. System.out.println("生成文档位置:" + outP.toAbsolutePath().toString());
  138. }
  139. /**
  140. * 向文档末尾追加内容,新的内容会以新的页面追加到文档的最后一页
  141. */
  142. public static void appendLasTest() throws IOException {
  143. Path srcP = Paths.get("C:/Users/kong/Desktop/ofd", "helloworld.ofd");
  144. Path outP = Paths.get("C:/Users/kong/Desktop/ofd/AppendNewPage.ofd");
  145. try (OFDReader reader = new OFDReader(srcP);
  146. OFDDoc ofdDoc = new OFDDoc(reader, outP)) {
  147. String plaintext = "小时候\n" +
  148. "乡愁是一枚小小的邮票\n" +
  149. "我在这头\n" +
  150. "母亲在那头\n" +
  151. "\n" +
  152. "长大后\n" +
  153. "乡愁是一张窄窄的船票\n" +
  154. "我在这头\n" +
  155. "新娘在那头\n" +
  156. "\n" +
  157. "后来啊\n" +
  158. "乡愁是一方矮矮的坟墓\n" +
  159. "我在外头\n" +
  160. "母亲在里头\n" +
  161. "\n" +
  162. "而现在\n" +
  163. "乡愁是一湾浅浅的海峡\n" +
  164. "我在这头\n" +
  165. "大陆在那头\n";
  166. Span titleContent = new Span("乡愁").setBold(true).setFontSize(13d).setLetterSpacing(10d);
  167. Paragraph title = new Paragraph().add(titleContent);
  168. title.setFloat(AFloat.center).setMarginBottom(5d);
  169. ofdDoc.add(title);
  170. final String[] txtCollect = plaintext.split("\\\n");
  171. for (String txt : txtCollect) {
  172. Paragraph p = new Paragraph().setFontSize(4d)
  173. .setLineSpace(3d)
  174. .add(txt);
  175. ofdDoc.add(p);
  176. }
  177. }
  178. System.out.println("生成文档位置:" + outP.toAbsolutePath().toString());
  179. }
  180. /**
  181. * 设置不同的页面大小
  182. */
  183. public static void setDiffPageSizeTest() throws IOException {
  184. Path srcP = Paths.get("C:/Users/kong/Desktop/ofd", "helloworld.ofd");
  185. Path outP = Paths.get("C:/Users/kong/Desktop/ofd/SetDiffPageSizeTest.ofd");
  186. try (OFDReader reader = new OFDReader(srcP);
  187. OFDDoc ofdDoc = new OFDDoc(reader, outP)) {
  188. PageLayout pageLayout = ofdDoc.getPageLayout().clone();
  189. pageLayout.setWidth(595d).setHeight(842d);
  190. VirtualPage vPage1 = new VirtualPage(pageLayout);
  191. Paragraph p = new Paragraph("测试内容", 30d);
  192. p.setPosition(Position.Absolute);
  193. p.setXY(60d, 60d);
  194. p.setWidth(100d);
  195. vPage1.add(p);
  196. ofdDoc.addVPage(vPage1);
  197. }
  198. System.out.println("生成文档位置:" + outP.toAbsolutePath().toString());
  199. }
  200. /**
  201. * 向文件中加入附件文件
  202. */
  203. public static void addAttachmentTest() throws IOException {
  204. Path outP = Paths.get("C:/Users/kong/Desktop/ofd/AddAttachment.ofd");
  205. Path file = Paths.get("C:/Users/kong/Desktop/ofd", "eg_tulip.jpg");
  206. Path file2 = Paths.get("C:/Users/kong/Desktop/ofd", "NotoSerifCJKsc-Regular.otf");
  207. try (OFDDoc ofdDoc = new OFDDoc(outP)) {
  208. Paragraph p = new Paragraph();
  209. Span span = new Span("这是一个带有附件的OFD文件").setFontSize(10d);
  210. p.add(span);
  211. ofdDoc.add(p);
  212. // 加入附件文件
  213. ofdDoc.addAttachment(new Attachment("Gao", file));
  214. ofdDoc.addAttachment(new Attachment("FontFile", file2));
  215. }
  216. System.out.println("生成文档位置:" + outP.toAbsolutePath().toString());
  217. }
  218. /**
  219. * 替换附件文件
  220. */
  221. public static void replaceAttachmentTest() throws IOException {
  222. Path srcP = Paths.get("C:/Users/kong/Desktop/ofd/AddAttachment.ofd");
  223. Path outP = Paths.get("C:/Users/kong/Desktop/ofd/ReplaceAttachment.ofd");
  224. Path file = Paths.get("C:/Users/kong/Desktop/ofd", "ASCII字体宽度测量.html");
  225. try (OFDReader reader = new OFDReader(srcP);
  226. OFDDoc ofdDoc = new OFDDoc(reader, outP)) {
  227. // 加入附件文件
  228. ofdDoc.addAttachment(new Attachment("Gao", file));
  229. }
  230. System.out.println("生成文档位置:" + outP.toAbsolutePath().toString());
  231. }
  232. /**
  233. * 添加书签
  234. */
  235. public static void addBookmarkTest() throws IOException {
  236. Path srcP = Paths.get("C:/Users/kong/Desktop/ofd/Page5.ofd");
  237. Path outP = Paths.get("C:/Users/kong/Desktop/ofd/addBookmark.ofd");
  238. try (OFDReader reader = new OFDReader(srcP);
  239. OFDDoc ofdDoc = new OFDDoc(reader, outP)) {
  240. Document document = ofdDoc.getOfdDocument();
  241. ST_ID pageID = document.getPages().getPageByIndex(3).getID();
  242. CT_Dest dest = new CT_Dest()
  243. .setType(DestType.Fit)
  244. .setPageID(pageID.ref());
  245. Bookmarks bookmarks = document.getBookmarks();
  246. if (bookmarks == null) {
  247. bookmarks = new Bookmarks();
  248. document.setBookmarks(bookmarks);
  249. }
  250. bookmarks.addBookmark(new Bookmark("美好一天", dest));
  251. }
  252. }
  253. }

4.3   文档操作工具

  1. import org.junit.Test;
  2. import org.ofdrw.graphics2d.OFDGraphicsDocument;
  3. import org.ofdrw.graphics2d.OFDPageGraphics2D;
  4. import org.ofdrw.tool.merge.OFDMerger;
  5. import javax.imageio.ImageIO;
  6. import java.awt.*;
  7. import java.awt.image.BufferedImage;
  8. import java.io.File;
  9. import java.io.IOException;
  10. import java.nio.file.Path;
  11. import java.nio.file.Paths;
  12. /**
  13. * 文档操作工具
  14. * OFDMerger 提供了页面级别的多文档编辑功能,包括:
  15. * 多文档合并
  16. * 文档页裁剪
  17. * 多文档页重组
  18. * OFDMerger#add方法支持可选参数,指定需要合并的页面页码(从1开始),通过灵活使用该API可以实现多文档页面级别编辑功能。
  19. * 文档操作将会导致文档结构内容变更,这将导致数字签名无效,请悉知!
  20. *
  21. */
  22. public class OFDMergerTest {
  23. public static void add() throws IOException {
  24. Path dst = Paths.get("C:/Users/kong/Desktop/ofd/n1.ofd");
  25. Path d1Path = Paths.get("C:/Users/kong/Desktop/ofd", "y.ofd");
  26. Path d2Path = Paths.get("C:/Users/kong/Desktop/ofd", "发票示例.ofd");
  27. try (OFDMerger ofdMerger = new OFDMerger(dst)) {
  28. ofdMerger.add(d1Path, 2);
  29. ofdMerger.add(d2Path, 1);
  30. ofdMerger.add(d1Path, 1);
  31. }
  32. }
  33. public static void add2() throws IOException {
  34. Path dst = Paths.get("C:/Users/kong/Desktop/ofd/n2.ofd");
  35. Path d1Path = Paths.get("C:/Users/kong/Desktop/ofd", "y.ofd");
  36. Path d2Path = Paths.get("C:/Users/kong/Desktop/ofd", "发票示例.ofd");
  37. try (OFDMerger ofdMerger = new OFDMerger(dst)) {
  38. ofdMerger.add(d1Path,1,1);
  39. ofdMerger.add(d2Path);
  40. ofdMerger.add(d1Path);
  41. }
  42. }
  43. //多文档页重组
  44. //将多个文档中的页面合并到同一份文档中,并可以可用页面在新文档中的顺序。
  45. public static void add3() throws IOException {
  46. Path dst = Paths.get("dst.ofd");
  47. Path d1Path = Paths.get("file1.ofd");
  48. Path d2Path = Paths.get("file2.ofd");
  49. try (OFDMerger ofdMerger = new OFDMerger(dst)) {
  50. ofdMerger.add(d1Path, 1, 2);
  51. ofdMerger.add(d2Path, 1);
  52. ofdMerger.add(d1Path, 3);
  53. }
  54. }
  55. // 裁剪
  56. // 截取文档的部分页面生成新的文档。
  57. public static void add4() throws IOException {
  58. Path dst = Paths.get("dst.ofd");
  59. Path d1Path = Paths.get("file1.ofd");
  60. try (OFDMerger ofdMerger = new OFDMerger(dst)) {
  61. ofdMerger.add(d1Path, 1, 2);
  62. }
  63. }
  64. public static void main(String[] args) throws Exception {
  65. final Path dst = Paths.get("D:\\Desktop\\ofd\\HelloWorld撒旦法刚刚.ofd");
  66. try (OFDGraphicsDocument doc = new OFDGraphicsDocument(dst)) {
  67. int width=210;
  68. File sourceimage = new File("C:\\Users\\kong\\Pictures\\Saved Pictures\\1-869.jpg"); //source.gif图片要与HelloJava.java同在一目录下
  69. BufferedImage image = ImageIO.read(sourceimage);
  70. int w = image.getWidth();
  71. int h = image.getHeight();
  72. double hh= width*1.000/w;
  73. double higth= hh*h;
  74. OFDPageGraphics2D g = doc.newPage(width,higth);
  75. g.drawImage(image, 0, 0, width, (int) higth, null);
  76. g.dispose();
  77. // g.setColor(Color.BLACK);
  78. // g.setFont(new Font("宋体", Font.PLAIN, 7));
  79. // g.drawString("你好OFD Reader & Writer Graphics-2D", 40, 40);
  80. doc.addResImg(image);
  81. }
  82. System.out.println(">> " + dst.toAbsolutePath());
  83. // drawImage();
  84. // drawImage2();
  85. // drawImageAffineTransform();
  86. }
  87. @Test
  88. public static void drawImage() throws Exception {
  89. final Path dst = Paths.get("D:\\Desktop\\ofd\\HelloWorld.ofd");
  90. try (OFDGraphicsDocument doc = new OFDGraphicsDocument(dst)) {
  91. Path file = Paths.get("C:\\Users\\kong\\Pictures\\Saved Pictures\\1-869.jpg");
  92. BufferedImage img1 = ImageIO.read(file.toFile());
  93. int width = img1.getWidth(null);
  94. int height = img1.getHeight(null);
  95. OFDPageGraphics2D g = doc.newPage(width, height);
  96. g.drawImage(img1, 0, 0, width, height, null);
  97. }
  98. System.out.println(">> " + dst.toAbsolutePath());
  99. }
  100. @Test
  101. public static void drawImage2() throws Exception {
  102. final Path dst = Paths.get("D:\\Desktop\\ofd\\HelloWorld1.ofd");
  103. try (OFDGraphicsDocument doc = new OFDGraphicsDocument(dst)) {
  104. OFDPageGraphics2D g = doc.newPage(500, 500);
  105. Path file = Paths.get("C:\\Users\\kong\\Pictures\\Saved Pictures\\1-869.jpg");
  106. BufferedImage img1 = ImageIO.read(file.toFile());
  107. g.drawImage(img1, 0, 0, null);
  108. }
  109. System.out.println(">> " + dst.toAbsolutePath());
  110. }
  111. @Test
  112. public static void drawImageAffineTransform() throws Exception {
  113. final Path dst = Paths.get("D:\\Desktop\\ofd\\HelloWorld2.ofd");
  114. try (OFDGraphicsDocument doc = new OFDGraphicsDocument(dst)) {
  115. OFDPageGraphics2D g = doc.newPage(500, 500);
  116. Path file = Paths.get("C:\\Users\\kong\\Pictures\\Saved Pictures\\1-869.jpg");
  117. BufferedImage img1 = ImageIO.read(file.toFile());
  118. g.drawImage(img1, null, 10, 10);
  119. g.setPaint(Color.RED);
  120. g.fillRect(0, 0, 30, 30);
  121. }
  122. System.out.println(">> " + dst.toAbsolutePath());
  123. }
  124. }

4.4  段落布局演示

  1. import org.ofdrw.font.FontName;
  2. import org.ofdrw.layout.OFDDoc;
  3. import org.ofdrw.layout.element.*;
  4. import java.io.IOException;
  5. import java.nio.file.Path;
  6. import java.nio.file.Paths;
  7. /**
  8. * 段落布局演示
  9. *
  10. */
  11. public class ParagraphLayoutDemo {
  12. /**
  13. * 测试段落内文字浮动
  14. */
  15. void testParagraphInlineFloat() throws IOException {
  16. Path outP = Paths.get("C:/Users/kong/Desktop/ofd/testParagraphInlineFloat.ofd");
  17. try (OFDDoc ofdDoc = new OFDDoc(outP)) {
  18. // 向左浮动
  19. Paragraph p1 = new Paragraph("这是左浮动内容", 4d)
  20. .setTextAlign(TextAlign.left);
  21. Paragraph p2 = new Paragraph("这是\n多行的文本\n\n我将采用向左浮动", 4d)
  22. .setTextAlign(TextAlign.left);
  23. // 右浮动
  24. Paragraph p3 = new Paragraph("这是右浮动内容", 4d)
  25. .setTextAlign(TextAlign.right);
  26. Paragraph p4 = new Paragraph("这是\n多行的文本\n\n我将采用向右浮动", 4d)
  27. .setTextAlign(TextAlign.right);
  28. // 居中
  29. Paragraph p5 = new Paragraph("这是居中内容", 4d)
  30. .setTextAlign(TextAlign.center);
  31. Paragraph p6 = new Paragraph("这是\n多行的文本\n\n我将采用向居中", 4d)
  32. .setTextAlign(TextAlign.center);
  33. ofdDoc.add(p1)
  34. .add(p2)
  35. .add(p3)
  36. .add(p4)
  37. .add(p5)
  38. .add(p6);
  39. }
  40. System.out.println("生成文档位置:" + outP.toAbsolutePath());
  41. }
  42. /**
  43. * 段落布局 各种情况演示
  44. *
  45. */
  46. void testParagraphLayout() throws IOException {
  47. Path outP = Paths.get("C:/Users/kong/Desktop/ofd/ParagraphLayoutDemo.ofd");
  48. try (OFDDoc ofdDoc = new OFDDoc(outP)) {
  49. // - 独占整个行
  50. Paragraph p1 = new Paragraph();
  51. p1.add("独占整个行").setBorder(0.1d).setMargin(3d, 0d);
  52. // - 共享模式(inline-block)
  53. Paragraph p2 = new Paragraph();
  54. p2.add("共享模式(inline-block),元素等同于内容宽度");
  55. p2.setClear(Clear.none).setBorder(0.1d).setMargin(3d, 0d);
  56. // 结束共享模式
  57. Paragraph hit1 = new Paragraph("插入一个Clear=both的元素中断共享模式");
  58. // - 手动指定宽度,仅在 Clear != both 模式有效
  59. Paragraph p3 = new Paragraph();
  60. p3.add("手动指定宽度,仅在 Clear != both 模式有效");
  61. p3.setWidth(55d);
  62. p3.setClear(Clear.none).setBorder(0.1d).setMargin(3d, 0d);
  63. Paragraph hit2 = new Paragraph("插入一个Clear=both的元素中断共享模式");
  64. // 居中
  65. Paragraph pn = new Paragraph();
  66. pn.setWidth(80d);
  67. pn.setHeight(20d);
  68. pn.setBorder(0.4d);
  69. pn.setPadding(5d);
  70. pn.setClear(Clear.none).setIntegrity(true);
  71. Span sp = new Span("序号")
  72. .setFont(FontName.SimHei.font())
  73. .setFontSize(4d);
  74. pn.add(sp);
  75. pn.setFloat(AFloat.center);
  76. Paragraph hit3 = new Paragraph("插入一个Clear=both的元素中断共享模式");
  77. // 共享模式下 多元素同行
  78. Paragraph p4A = new Paragraph("这是A部分");
  79. p4A.setClear(Clear.none).setFloat(AFloat.center).setBorder(0.1d).setPadding(3d).setMargin(1d);
  80. Paragraph p4B = new Paragraph("这是B部分");
  81. p4B.setClear(Clear.none).setFloat(AFloat.center).setBorder(0.1d).setPadding(3d).setMargin(1d);
  82. ofdDoc.add(p1);
  83. ofdDoc.add(p2);
  84. ofdDoc.add(hit1);
  85. ofdDoc.add(p3);
  86. ofdDoc.add(hit2);
  87. ofdDoc.add(pn);
  88. ofdDoc.add(hit3);
  89. ofdDoc.add(p4A).add(p4B);
  90. }
  91. System.out.println("生成文档位置:" + outP.toAbsolutePath());
  92. }
  93. /**
  94. * 段落首行缩进测试用例
  95. */
  96. void testParagraphFirstLineIndent() throws IOException {
  97. Path outP = Paths.get("C:/Users/kong/Desktop/ofd/ParagraphFirstLineIndent.ofd");
  98. try (OFDDoc ofdDoc = new OFDDoc(outP)) {
  99. String titleStr = "济南的冬天";
  100. String p1Str = "对于一个在北平住惯的人,像我,冬天要是不刮风,便觉得是奇迹;济南的冬天是没有风声的。对于一个刚由伦敦回来的人,像我,冬天要能看得见日光,便觉得是怪事;济南的冬天是响晴的。自然,在热带的地方,日光是永远那么毒,响亮的天气,反有点叫人害怕。可是,在北中国的冬天,而能有温晴的天气,济南真得算个宝地。";
  101. String p2Str = "设若单单是有阳光,那也算不了出奇。请闭上眼睛想:一个老城,有山有水,全在天底下晒着阳光,暖和安适地睡着,只等春风来把它们唤醒,这是不是个理想的境界?";
  102. Span spTitle = new Span(titleStr)
  103. .setFont(FontName.SimHei.font()) // 设置字体
  104. .setBold(true)
  105. .setFontSize(7d)
  106. .setLetterSpacing(5d);
  107. Paragraph title = new Paragraph().add(spTitle);
  108. title.setFloat(AFloat.center).setMargin(5d);
  109. Span sp1 = new Span(p1Str)
  110. .setFontSize(3d) // 设置字体大小
  111. .setLetterSpacing(3d); // 设置字间距
  112. Paragraph p1 = new Paragraph()
  113. .add(sp1)
  114. .setFirstLineIndent(2); // 设置首行缩进
  115. Span sp2 = new Span(p2Str).setLetterSpacing(3d);
  116. Paragraph p2 = new Paragraph()
  117. .add(sp2)
  118. .setFirstLineIndentWidth((3d + 3d) * 2); // 设置首行缩进宽度,单位mm
  119. // 将段落加入文档
  120. ofdDoc.add(title).add(p1).add(p2);
  121. }
  122. System.out.println("生成文档位置:" + outP.toAbsolutePath().toString());
  123. }
  124. /**
  125. * 段落布局模式
  126. */
  127. void testPLayoutPatten() throws IOException {
  128. Path outP = Paths.get("C:/Users/kong/Desktop/ofd/TestPLayoutPatten.ofd");
  129. try (OFDDoc ofdDoc = new OFDDoc(outP)) {
  130. // - 独占整个行
  131. Paragraph p1 = new Paragraph();
  132. p1.add("独占整个行").setBorder(0.1d).setMargin(3d, 0d);
  133. // - 共享模式(inline-block)
  134. Paragraph p2 = new Paragraph();
  135. p2.add("共享模式(inline-block),元素等同于内容宽度");
  136. p2.setClear(Clear.none).setBorder(0.1d).setMargin(3d, 0d);
  137. // 结束共享模式
  138. Paragraph hit1 = new Paragraph("插入一个Clear=both的元素中断共享模式");
  139. // - 手动指定宽度,仅在 Clear != both 模式有效
  140. Paragraph p3 = new Paragraph();
  141. p3.add("手动指定宽度,仅在 Clear != both 模式有效");
  142. p3.setWidth(55d);
  143. p3.setClear(Clear.none).setBorder(0.1d).setMargin(3d, 0d);
  144. Paragraph hit2 = new Paragraph("插入一个Clear=both的元素中断共享模式");
  145. // 居中
  146. Paragraph pn = new Paragraph();
  147. pn.setWidth(80d);
  148. pn.setHeight(20d);
  149. pn.setBorder(0.4d);
  150. pn.setPadding(5d);
  151. pn.setClear(Clear.none).setIntegrity(true);
  152. Span sp = new Span("序号")
  153. .setFont(FontName.SimHei.font())
  154. .setFontSize(4d);
  155. pn.add(sp);
  156. pn.setFloat(AFloat.center);
  157. Paragraph hit3 = new Paragraph("插入一个Clear=both的元素中断共享模式");
  158. // 共享模式下 多元素同行
  159. Paragraph p4A = new Paragraph("这是A部分");
  160. p4A.setClear(Clear.none).setFloat(AFloat.center).setBorder(0.1d).setPadding(3d).setMargin(1d);
  161. Paragraph p4B = new Paragraph("这是B部分");
  162. p4B.setClear(Clear.none).setFloat(AFloat.center).setBorder(0.1d).setPadding(3d).setMargin(1d);
  163. ofdDoc.add(p1);
  164. ofdDoc.add(p2);
  165. ofdDoc.add(hit1);
  166. ofdDoc.add(p3);
  167. ofdDoc.add(hit2);
  168. ofdDoc.add(pn);
  169. ofdDoc.add(hit3);
  170. ofdDoc.add(p4A).add(p4B);
  171. }
  172. System.out.println("生成文档位置:" + outP.toAbsolutePath());
  173. }
  174. /**
  175. * 文档示例
  176. */
  177. void testPLayoutDoc() throws IOException {
  178. Path path = Paths.get("C:/Users/kong/Desktop/ofd/TestPLayoutDoc.ofd");
  179. try (OFDDoc ofdDoc = new OFDDoc(path)) {
  180. ofdDoc.add(new Paragraph("青春 选节", 10d).setClear(Clear.none).setFloat(AFloat.center));
  181. ofdDoc.add(new Paragraph("李大钊", 3d).setFloat(AFloat.center).setClear(Clear.left));
  182. String[] pArr = new String[]{
  183. "人类之成一民族一国家者,亦各有其生命焉。有青春之民族,斯有白首之民族,有青春之国家,斯有白首之国家。吾之民族若国家,果为青春之民族、青春之国家欤,抑为白首之民族、白首之国家欤?苟已成白首之民族、白首之国家焉,吾辈青年之谋所以致之回春为之再造者,又应以何等信力与愿力从事,而克以著效?此则系乎青年之自觉何如耳。异族之觇吾国者,辄曰:支那者老大之邦也。支那之民族,濒灭之民族也。支那之国家,待亡之国家也。洪荒而后,民族若国家之递兴递亡者,然其不可纪矣。粤稽西史,罗马、巴比伦之盛时,丰功伟烈,彪著寰宇,曾几何时,一代声华,都成尘土矣。祗今屈指,欧土名邦,若意大利,若法兰西,若西班牙,若葡萄牙,若和兰,若比利时,若丹马,若瑞典,若那威,乃至若英吉利,罔不有积尘之历史,以重累其国家若民族之生命。回溯往祀,是等国族,固皆尝有其青春之期,以其畅盛之生命,展其特殊之天才。而今已矣,声华渐落,躯壳空存,纷纷者皆成文明史上之过客矣。其校新者,惟德意志与勃牙利,此次战血洪涛中,又为其生命力之所注,勃然暴发,以挥展其天才矣。由历史考之,新兴之国族与陈腐之国族遇,陈腐者必败;朝气横溢之生命力与死灰沉滞之生命力遇,死灰沉滞者必败;青春之国民与白首之国民遇,白首者必败,此殆天演公例,莫或能逃者也。支那自黄帝以降,赫赫然树独立之帜于亚东大陆者,四千八百余年于兹矣。历世久远,纵观横览,罕有其伦。稽其民族青春之期,远在有周之世,典章文物,灿然大备,过此以往,渐向衰歇之运,然犹浸衰浸微,扬其余辉。以至于今日者,得不谓为其民族之光欤?夫人寿之永,不过百年,民族之命,垂五千载,斯亦寿之至也。印度为生释迦而兴,故自释迦生而印度死;犹太为生耶稣而立,故自耶稣生而犹太亡;支那为生孔子而建,故自孔子生而支那衰,陵夷至于今日,残骸枯骨,满目黤然,民族之精英,澌灭尽矣,而欲不亡,庸可得乎?吾青年之骤闻斯言者,未有不变色裂眦,怒其侮我之甚也。虽然,勿怒也。吾之国族,已阅长久之历史,而此长久之历史,积尘重压,以桎梏其生命而臻于衰敝者,又宁容讳?然而吾族青年所当信誓旦旦,以昭示于世者,不在龈龈辩证白首中国之不死,乃在汲汲孕育青春中国之再生。吾族今后之能否立足于世界,不在白首中国之苟延残喘,而在青春中国之投胎复活。盖尝闻之,生命者,死与再生之连续也。今后人类之问题,民族之问题,非苟生残存之问题,乃复活更生、回春再造之问题也。与吾并称为老大帝国之土耳其,则青年之政治运动,屡试不一试焉。巴尔干诸邦,则各谋离土自立,而为民族之运动,兵连祸结,干戈频兴,卒以酿今兹世界之大变焉。遥望喜马拉亚山之巅,恍见印度革命之烽烟一缕,引而弥长,是亦欲回其民族之青春也。吾华自辛亥首义,癸丑之役继之,喘息未安,风尘澒洞,又复倾动九服,是亦欲再造其神州也。而在是等国族,凡以冲决历史之桎梏,涤荡历史之积秽,新造民族之生命,挽回民族之青春者,固莫不惟其青年是望矣。建国伊始,肇锡嘉名,实维中华。中华之义,果何居乎?中者,宅中位正之谓也。吾辈青年之大任,不仅以于空间能致中华为天下之中而遂足,并当于时间而谛时中之旨也。旷观世界之历史,古往今来,变迁何极!吾人当于今岁之青春,画为中点,中以前之历史,不过如进化论仅于考究太阳地球动植各物乃至人类之如何发生、如何进化者,以纪人类民族国家之如何发生、如何进化也。中以后之历史,则以是为古代史之职,而别以纪人类民族国家之更生回春为其中心之的也。中以前之历史,封闭之历史,焚毁之历史,葬诸坟墓之历史也。中以后之历史,洁白之历史,新装之历史,待施绚绘之历史也。中以前之历史,白首之历史,陈死人之历史也。中以后之历史,青春之历史,活青年之历史也。青年乎!其以中立不倚之精神,肩兹砥柱中流之责任,即由今年今春之今日今刹那为时中之起点,取世界一切白首之历史,一火而摧焚之,而专以发挥青春中华之中,缀其一生之美于中以后历史之首页,为其职志,而勿逡巡不前。华者,文明开敷之谓也,华与实相为轮回,即开敷与废落相为嬗代。白首中华者,青春中华本以胚孕之实也。青春中华者,白首中华托以再生之华也。白首中华者,渐即废落之中华也。青春中华者,方复开敷之中华也。有渐即废落之中华,所以有方复开敷之中华。有前之废落以供今之开敷,斯有后之开敷以续今之废落,即废落,即开敷,即开敷,即废落,终竟如是废落,终竟如是开敷。宇宙有无尽之青春,斯宇宙有不落之华,而栽之、培之、灌之、溉之、赏玩之、享爱之者,舍青春中华之青年,更谁为归矣?青年乎,勿徒发愿,愿春常在华常好也,愿华常得青春,青春常在于华也。宜有即华不得青春,青春不在于华,亦必奋其回春再造之努力,使废落者复为开敷,开敷者终不废落,使华不能不得青春,青春不能不在于华之决心也。抑吾闻之化学家焉,土质虽腴,肥料虽多,耕种数载,地力必耗,砂土硬化,无能免也,将欲柔融之,俾再反于丰穰,惟有一种草木为能致之,为其能由空中吸收窒素肥料,注入土中而沃润之也。神州赤县,古称天府,胡以至今徒有万木秋声、萧萧落叶之悲,昔时繁华之盛,荒凉废落至于此极也!毋亦无此种草木为之交柔和润之耳。青年之于社会,殆犹此种草木之于田也。从此广植根蒂,深固不可复拔,不数年间,将见青春中华之参天蓊郁,错节盘根,树于世界,而神州之域,还其丰穰,复其膏腴矣。则谓此菁菁茁茁之青年,即此方复开敷之青春中华可也。",
  184. "顾人之生也,苟不能窥见宇宙有无尽之青春,则自呱呱堕地,迄于老死,觉其间之春光,迅于电波石火,不可淹留,浮生若梦,直菌鹤马蜩之过乎前耳。是以川上尼父,有逝者如斯之嗟,湘水灵均,兴春秋代序之感。其他风骚雅士,或秉烛夜游,勤事劳人,或重惜分寸。而一代帝王,一时豪富,当其垂暮之年,绝诀之际,贪恋幸福,不忍离舍,每为咨嗟太息,尽其权力黄金之用,无能永一瞬之天年,而重留遗憾于长生之无术焉。秦政并吞八荒,统制四海,固一世之雄也,晚年畏死,遍遣羽客,搜觅神仙,求不老之药,卒未能获,一旦魂断,宫车晚出。汉武穷兵,蛮荒慑伏,汉代之英主也,暮年永叹,空有“欢乐极矣哀情多,少壮几时老奈何”之慨。最近美国富豪某,以毕生之奋斗,博得式之王冠,衰病相催,濒于老死,则抚枕而叹曰:“苟能延一月之命,报以千万金弗惜也。”然是又安可得哉?夫人之生也有限,其欲也无穷,以无穷之欲,逐有限之生,坐令似水年华,滔滔东去,红颜难再,白发空悲,其殆人之无奈无何者欤!涉念及此,灰肠断气,灰世之思,油然而生。贤者仁智俱穷,不肖者流连忘返,而人生之蕲向荒矣,是又岂青年之所宜出哉?人生兹世,更无一刹那不在青春,为其居无尽青春之一部,为无尽青春之过程也。顾青年之人,或不得常享青春之乐者,以其有黄金权力一切烦忧苦恼机械生活,为青春之累耳。谚云:“百金买骏马,千金买美人,万金买爵禄,何处买青春?”岂惟无处购买,邓氏铜山,郭家金穴,愈有以障青春之路俾无由达于其境也。罗马亚布达尔曼帝,位在皇极,富有四海,不可谓不尊矣,临终语其近侍,谓四十年间,真感愉快者,仅有三日。权力之不足福人,以视黄金,又无差等。而以四十年之青春,娱心不过三日,悼心悔憾,宁有穷耶?夫青年安心立命之所,乃在循今日主义以进,以吾人之生,洵如卡莱尔所云,特为时间所执之无限而已。无限现而为我,乃为现在,非为过去与将来也。苟了现在,即了无限矣。昔者圣叹作诗,有“何处谁人玉笛声”之句。释弓年小,窃以玉字为未安,而质之圣叹。圣叹则曰:“彼若说‘我所吹本是铁笛,汝何得用作玉笛’。我便云:”我已用作玉笛,汝何得更吹铁笛?‘天生我才,岂为汝铁笛作奴儿婢子来耶?“夫铁字与玉字,有何不可通融更易之处。圣叹顾与之争一字之短长而不惮烦者,亦欲与之争我之现在耳。诗人拜轮,放浪不羁,时人诋之,谓于来世必当酷受地狱之苦。拜轮答曰:”基督教徒自苦于现世,而欲祈福于来世。非基督教徒,则于现世旷逸自遣,来世之苦,非所辞也。“二者相校,但有先后之别,安有分量之差。拜轮此言,固甚矫激,且寓风刺之旨。以余观之,现世有现世之乐,来世有来世之乐。现世有现世之青春,来世有来世之青春。为贪来世之乐与青春,而迟吾现世之乐与青春,固所不许。而为贪现世之乐与青春,遽弃吾来世之乐与青春,亦所弗应也。人生求乐,何所不可,亦何必妄分先后,区异今来也?耶曼孙曰:”尔若爱千古,当利用现在。昨日不能呼还,明日尚未确实。尔能确有把握者,惟有今日。今日之一日,适当明晨之二日。“斯言足发吾人之深省矣。盖现在者吾人青春中之青春也。青春作伴以还于大漠之乡,无如而不自得,更何烦忧之有焉。烦忧既解,恐怖奚为?耶比古达士曰:”贫不足恐,流窜不足恐,囹圄不足恐,最可恐者,恐怖其物也。“美之政雄罗斯福氏,解政之后,游猎荒山,奋其銕腕,以与虎豹熊罴相搏战。一日猎白熊,险遭吞噬,自传其事,谓为不以恐怖误其稍纵即逝之机之效,始获免焉。于以知恐怖为物,决不能拯人于危。苟其明日将有大祸临于吾躬,无论如何恐怖,明日之祸万不能因是而减其豪末。而今日之我,则因是而大损其气力,俾不足以御明日之祸而与之抗也。艰虞万难之境,横于吾前,吾惟有我、有我之现在而足恃。堂堂七尺之躯,徘徊回顾,前不见古人,后不见来者,惟有昂头阔步,独往独来,何待他人之援手,始以遂其生者,更胡为乎念天地之悠悠,独怆然而涕下哉?惟足为累于我之现在及现在之我者,机械生活之重荷,与过去历史之积尘,殆有同一之力焉。今人之赴利禄之途也,如蚁之就膻,蛾之投火,究其所企,克致志得意满之果,而营营扰扰,已逾半生,以孑然之身,强负黄金与权势之重荷以趋,几何不为所重压而僵毙耶?盖其优于权富即其短于青春者也。耶经有云:”富人之欲入天国,犹之骆驼欲潜身于针孔。“此以喻重荷之与青春不并存也。总之,青年之自觉,一在冲决过去历史之网罗,破坏陈腐学说之囹圄,勿令僵尸枯骨,束缚现在活泼泼地之我,进而纵现在青春之我,扑杀过去青春之我,促今日青春之我,禅让明日青春之我。一在脱绝浮世虚伪之机械生活,以特立独行之我,立于行健不息之大机轴。祖裼裸裎,去来无罫,全其优美高尚之天,不仅以今日青春之我,追杀今日白首之我,并宜以今日青春之我,豫杀来日白首之我,此固人生唯一之蕲向,青年唯一之责任也矣。拉凯尔曰:”长保青春,为人生无上之幸福,尔欲享兹幸福,当死于少年之中。“吾愿吾亲爱之青年,生于青春死于青春,生于少年死于少年也。德国史家孟孙氏,评骘锡札曰:”彼由青春之杯,饮人生之水,并泡沫而干之。“吾愿吾亲爱之青年,擎此夜光之杯,举人生之醍醐浆液,一饮而干也。人能如是,方为不役于物,物莫之伤。大浸稽天而不溺,大旱金石流土山焦而不热,是其尘垢粃糠,将犹陶铸尧、舜。自我之青春,何能以外界之变动而改易,历史上残骸枯骨之灰,又何能塞蔽青年之聪明也哉?市南宜僚见鲁侯,鲁侯有忧色,市南子乃示以去累除忧之道,有曰,”吾愿君去国捐俗,与道相辅而行。“君曰:”彼其道远而险,又有江山,我无舟车,奈何?“市南子曰:”君无形倨,无留居,以为舟车。“君曰:”彼其道幽远而无人,吾谁与为邻?吾无粮,我无食,安得而至焉?“市南子曰:”少君之费,寡君之欲,虽无粮而乃足,君其涉于江而浮于海,望之而不见其崖,愈往而不知其所穷,送君者将自崖而反,君自此远矣。“此其谓道,殆即达于青春之大道。",
  185. "青年循蹈乎此,本其理性,加以努力,进前而勿顾后,背黑暗而向光明,为世界进文明,为人类造幸福,以青春之我,创建青春之家庭,青春之国家,青春之民族,青春之人类,青春之地球,青春之宇宙,资以乐其无涯之生。乘风破浪,迢迢乎远矣,复何无计留春望尘莫及之忧哉?吾文至此,已嫌冗赘,请诵漆园之语,以终斯篇。"
  186. };
  187. for (String s : pArr) {
  188. ofdDoc.add(new Paragraph(s, 5d).setFirstLineIndent(2));
  189. }
  190. }
  191. System.out.println("生成文档位置: " + path.toAbsolutePath());
  192. }
  193. }

4.5  水印测试用例

  1. import org.ofdrw.converter.ImageMaker;
  2. import org.ofdrw.core.annotation.pageannot.AnnotType;
  3. import org.ofdrw.core.basicType.ST_Box;
  4. import org.ofdrw.font.FontName;
  5. import org.ofdrw.layout.OFDDoc;
  6. import org.ofdrw.layout.edit.Annotation;
  7. import org.ofdrw.layout.element.canvas.FontSetting;
  8. import org.ofdrw.reader.OFDReader;
  9. import java.io.IOException;
  10. import java.nio.file.Path;
  11. import java.nio.file.Paths;
  12. /**
  13. * 水印测试用例
  14. *
  15. **/
  16. public class WatermarkTest {
  17. /**
  18. * 水印处理
  19. */
  20. public void addWatermark() throws IOException {
  21. Path srcP = Paths.get("C:/Users/kong/Desktop/ofd", "2月乡厨发票(芳草地).ofd");
  22. Path outP = Paths.get("C:/Users/kong/Desktop/ofd/AddWatermarkAnnot.ofd");
  23. try (OFDReader reader = new OFDReader(srcP);
  24. OFDDoc ofdDoc = new OFDDoc(reader, outP)) {
  25. Double width = ofdDoc.getPageLayout().getWidth();
  26. Double height = ofdDoc.getPageLayout().getHeight();
  27. Annotation annotation = new Annotation(new ST_Box(0d, 0d, width, height), AnnotType.Watermark, ctx -> {
  28. FontSetting setting = new FontSetting(8, FontName.SimSun.font());
  29. ctx.setFillColor(170, 160, 165)
  30. .setFont(setting)
  31. .setGlobalAlpha(0.4);
  32. for (int i = 0; i <= 8; i++) {
  33. for (int j = 0; j <= 8; j++) {
  34. ctx.save();
  35. ctx.translate(22.4 * i, j * 50);
  36. ctx.rotate(45);
  37. ctx.fillText("保密资料", 10, 10);
  38. ctx.restore();
  39. }
  40. }
  41. });
  42. ///给ofd文档所有页打上水印
  43. ImageMaker imageMaker = new ImageMaker(reader, 15);
  44. for (int i = 1; i <=imageMaker.pageSize(); i++) {
  45. ofdDoc.addAnnotation( i, annotation);
  46. }
  47. }
  48. System.out.println("生成文档位置:" + outP.toAbsolutePath().toString());
  49. }
  50. }

5. ofd转其他文件

  1. import org.ofdrw.converter.ConvertHelper;
  2. import org.ofdrw.converter.GeneralConvertException;
  3. import org.ofdrw.converter.ImageMaker;
  4. import org.ofdrw.converter.SVGMaker;
  5. import org.ofdrw.reader.OFDReader;
  6. import javax.imageio.ImageIO;
  7. import java.awt.image.BufferedImage;
  8. import java.io.IOException;
  9. import java.nio.file.Files;
  10. import java.nio.file.Path;
  11. import java.nio.file.Paths;
  12. /**
  13. *
  14. * PDF转换概述: 通过对OFD的文档进行解析,使用 Apache Pdfbox生成并转换OFD中的元素为PDF内的元素实现PDF的转换。
  15. * 图片转换概述: 通过对OFD的文档进行解析,采用java.awt绘制图片,支持转换为PNG、JPEG图片格式。
  16. * SVG矢量图形转换概述: 使用Apachebatik-transcoder提供的图形绘制实现java.awtAPI绘制,最终生成SVG矢量图形。
  17. * HTML转换概述: 使用上述SVG矢量图形转换作为显示效果层A,再将OFD文档中的文字(仅)解析为SVG作为文字复制层B,B置于A层之上,
  18. * 文字颜色transparent,无需关心字体,在移动端同样正常显示。
  19. *
  20. *
  21. */
  22. public class OFDUtils {
  23. /**
  24. * 1.正常的ofd文件
  25. * 2.图片的ofd
  26. * 3.进过其他转换器转换而来的ofd
  27. */
  28. public static void ofdtoPdf(Path input, Path output) {
  29. /****************************************************
  30. * 转换成PDF 如图不是全屏图转成pdf后显示会乱
  31. */
  32. // 1. 文件输入路径
  33. Path src =input;// Paths.get("C:/Users/kong/Desktop/ofd/OFD/第三方ofd/60830858_578.ofd");
  34. // 2. 转换后文件输出位置
  35. Path dst = Paths.get(src.toAbsolutePath()+"_1.pdf");; // Paths.get("C:/Users/kong/Desktop/ofd/60830858_578.pdf");
  36. try {
  37. // 3. OFD转换PDF
  38. ConvertHelper.toPdf(src, dst);
  39. System.out.println("生成文档位置: " + dst.toAbsolutePath());
  40. } catch (GeneralConvertException e) {
  41. // GeneralConvertException 类型错误表明转换过程中发生异常
  42. e.printStackTrace();
  43. }
  44. }
  45. /**
  46. * 按页数转
  47. * @param input
  48. * @param output
  49. */
  50. public static void ofdtoPic(Path input, Path output) {
  51. /***********************************************************
  52. * 转换成图片
  53. */
  54. // // 1. 文件输入路径
  55. Path src =input; // Paths.get("C:/Users/kong/Desktop/ofd/2.ofd");
  56. // output = Paths.get(src.toAbsolutePath()+"_1.jpeg");
  57. // 2. 加载指定目录字体(非必须)
  58. // FontLoader.getInstance().scanFontDir(new File("src/test/resources/fonts"));
  59. // 3. 创建转换转换对象,设置 每毫米像素数量(Pixels per millimeter)
  60. try{
  61. OFDReader reader = new OFDReader(src);
  62. ImageMaker imageMaker = new ImageMaker(reader, 15);
  63. for (int i = 0; i < imageMaker.pageSize(); i++) {
  64. // 4. 指定页码转换图片
  65. BufferedImage image = imageMaker.makePage(i);
  66. Path dist = Paths.get(src.getParent().toString(), src.getFileName()+""+i+"-1.jpeg");
  67. // 5. 存储为指定格式图片
  68. ImageIO.write(image, "JPEG", dist.toFile());
  69. }
  70. System.out.println("ofdtoPic-ok");
  71. }catch(Exception e){
  72. e.printStackTrace();
  73. }finally {
  74. }
  75. }
  76. public static void ofdtoSvg(Path input, Path output) {
  77. /********************************************************
  78. * 转换成svg
  79. */
  80. // 1. 文件输入路径
  81. Path src =input; // Paths.get("C:/Users/kong/Desktop/ofd/2.ofd");
  82. // output = Paths.get(src.toAbsolutePath()+"_1.svg");
  83. // 2. 加载指定目录字体(非必须)
  84. // FontLoader.getInstance().scanFontDir(new File("src/test/resources/fonts"));
  85. // 3. 创建转换转换对象,设置 每毫米像素数量(Pixels per millimeter)
  86. try{
  87. OFDReader reader = new OFDReader(src);
  88. SVGMaker svgMaker = new SVGMaker(reader, 20d);
  89. for (int i = 0; i < svgMaker.pageSize(); i++) {
  90. // 4. 指定页码转换SVG,得到SVG(XML)
  91. String svg = svgMaker.makePage(i);
  92. Path dist = Paths.get(src.getParent().toString(), src.getFileName()+""+i+"-1.svg");
  93. // 5. 存储到文件。
  94. Files.write(dist, svg.getBytes());
  95. }
  96. System.out.println("ofdtoSvg-ok");
  97. }catch(Exception e)
  98. {
  99. e.printStackTrace();
  100. }
  101. }
  102. public static void ofdtoHtml(Path input, Path output) {
  103. /***************************************************************
  104. * 转换成html
  105. */
  106. try {
  107. // 1. 提供文档
  108. Path ofdIn =input; // Paths.get("C:/Users/kong/Desktop/ofd/1.ofd");
  109. Path htmlOut = Paths.get(ofdIn.toAbsolutePath()+"_1.html");
  110. // 2. [可选]配置字体,别名,扫描目录等
  111. // FontLoader.getInstance().addAliasMapping(null, "小标宋体", "方正小标宋简体", "方正小标宋简体")
  112. // FontLoader.getInstance().scanFontDir(new File("src/test/resources/fonts"));
  113. // 3. 配置参数(HTML页面宽度(px)),转换并存储HTML到文件。
  114. ConvertHelper.toHtml(ofdIn, htmlOut, 1000);
  115. System.out.println("ofdtoHtml-ok");
  116. } catch (Exception e) {
  117. e.printStackTrace();
  118. }
  119. }
  120. public static void main(String[] args) throws IOException {
  121. /* Path ofdIn= Paths.get("C:/Users/kong/Desktop/ofd/OFD/1.ofd");
  122. OFDUtils.ofdtoPdf(ofdIn,Paths.get(""));
  123. OFDUtils.ofdtoHtml(ofdIn,Paths.get(""));
  124. OFDUtils.ofdtoPic(ofdIn,Paths.get(""));
  125. OFDUtils.ofdtoSvg(ofdIn,Paths.get(""));
  126. */
  127. // ofdU.vPageLayerTest();
  128. // ofdU.streamTestParagraphPageSplit();
  129. // ofdU.OFDRWCanvas();
  130. // ContentExtractorTest.getPageContent();
  131. // Path ofdIn= Paths.get("C:/Users/kong/Desktop/ofd/OFD/第三方ofd/60830858_578.ofd");
  132. // OFDUtils.ofdtoPic(ofdIn,Paths.get(""));
  133. // new WatermarkTest().addWatermark();//加水印
  134. // ContentExtractorTest.traverse();
  135. Path ofdIn= Paths.get("D:\\images\\2023\\05\\29\\rcav0p2M20230188664c3ca705000329\\20230529145734261005860540000001_0.ofd");
  136. // OFDUtils.ofdtoPdf(ofdIn,Paths.get(""));
  137. // Path ofdIn= Paths.get("C:\\Users\\kong\\Desktop\\ofd\\2.ofd");
  138. OFDUtils.ofdtoPic(ofdIn,Paths.get(""));
  139. }
  140. }

参考资料:ofdrw: OFD Reader & Writer 开源的OFD处理库,支持文档生成、数字签名、文档保护、文档合并、转换等功能,文档格式遵循《GB/T 33190-2016 电子文件存储与交换格式版式文档》。 - Gitee.com

声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:【wpsshop博客】
推荐阅读
相关标签
  

闽ICP备14008679号