ofd文件解析和操作小记

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

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

<!--ofd操作类-->
       <dependency>
           <groupId>org.ofdrw</groupId>
           <artifactId>ofdrw-full</artifactId>
           <version>2.0.5</version>
           <exclusions><!--ofd 转换时需要去掉 否则会报jar冲突以及启动堆栈溢出-->
               <exclusion>
                   <groupId>org.apache.logging.log4j</groupId>
                   <artifactId>log4j-slf4j-impl</artifactId>
               </exclusion>
           </exclusions>
       </dependency>

3. ofd的一些操作类

3.1  图片合成ofd


import org.ofdrw.graphics2d.OFDGraphicsDocument;
import org.ofdrw.graphics2d.OFDPageGraphics2D;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.File;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;

/**
 * @Description //TODO
 * @Date 2023/06/01 15:38
 * @Author kdc
 **/
public class ImageToOfd {


    /**
     * @description: 图片转pdf
     * @param: [文件路径, 图片路径,多图片已“,”分隔]
     **/
    public static JSONObject imageToOfd(String filepath, String imgUrl){
        JSONObject returnResult=new JSONObject();
        Path dst = Paths.get(filepath);
        try {
//            File files=new File(filepath);
//            files.createNewFile();
            OFDGraphicsDocument doc = new OFDGraphicsDocument(dst);
            int width=210;
            ArrayList<String> imageUrllist = new ArrayList<String>(); //图片list集合
            String[] imgUrls = imgUrl.split(",");
            for (int i=0; i<imgUrls.length; i++) {
                File sourceimage = new File(imgUrls[i]);
                BufferedImage image = ImageIO.read(sourceimage);
                int w = image.getWidth();
                int h = image.getHeight();
                double hh= width*1.0000/w;
                double higth= hh*h;
                OFDPageGraphics2D g = doc.newPage(width,higth);
                g.drawImage(image, 0, 0, width, (int) higth, null);
                g.dispose();
                doc.addResImg(image);
            }
            doc.close();
            System.out.println(">> " + dst.toAbsolutePath());
            returnResult.put("code", ResultCode.SUCCESS.getCode());
            returnResult.put("msg","ofd合成成功");
            returnResult.put("fileSize",new File(filepath).length());
        } catch (Exception e) {
            returnResult.put("code",ResultCode.ERROR.getCode());
            returnResult.put("msg","OFD合成失败");
            e.printStackTrace();
        }
        return returnResult;
    }

3.2    ofd按页数拆图


import org.ofdrw.converter.ImageMaker;
import org.ofdrw.reader.OFDReader;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.nio.file.Path;
import java.nio.file.Paths;

/**
 * @Description //TODO   ofd转图
 * @Author kdc
 **/
public class OfdToImage {


    //ofd文件所有也都转图
   public static JSONArray OfdToImageByPage(String rootPath, String file_id, String batchId, String filename, String type) {
        // 将pdf装图片 并且自定义图片得格式大小
        filename =filename.substring(0, filename.lastIndexOf("."));
        JSONArray returnObj = new JSONArray();
       String filepath =TecrunUtils.getFilePathFromBatchIdAndFileId(rootPath, batchId, file_id, 0);
        Path src=Paths.get(filepath);
        try{
            OFDReader reader = new OFDReader(src);
            ImageMaker imageMaker = new ImageMaker(reader, 15);
            for (int i = 0; i < imageMaker.pageSize(); i++) {
                // 4. 指定页码转换图片
                BufferedImage image = imageMaker.makePage(i);
                String newFileId = TecrunUtils.createFileId();
                String imageName=filename+"_"+i+"."+type;
                String imagePath = TecrunUtils.getFilePathFromBatchIdAndFileId(rootPath, batchId, newFileId, 0);
                String thumbImagePath = TecrunUtils.getFilePathFromBatchIdAndFileId(rootPath, batchId, newFileId, 1);
//                String imagePath=fileFloder+newFileId+"_0";
//                String thumbImagePath=fileFloder+newFileId+"_1.jpg";
                Path dist = Paths.get(imagePath);
                // 5. 存储为指定格式图片
                ImageIO.write(image, "png", dist.toFile());
                ///生成每一页的缩略图
                Thumbnails.of(imagePath).size(200, 200)
                        .outputFormat("jpg").toFile(thumbImagePath);

                JSONObject ofdimage=new JSONObject();
                ofdimage.put("file_id",newFileId);
                ofdimage.put("imagePath",imagePath);
                ofdimage.put("thumbImagePath",thumbImagePath);
                ofdimage.put("file_name",imageName);
                ofdimage.put("file_size", new File(imagePath).length());
                ofdimage.put("file_suffix",type);
                returnObj.add(ofdimage);

            }
            System.out.println("ofdtoPic-ok");
        }catch(Exception e){
            e.printStackTrace();
        }
        return returnObj;
    }

    //ofd文件第一页转图
    public static JSONObject OfdToImageByPageOne(String rootPath, String file_id, String batchId, String filename, String type) {
        // 将pdf装图片 并且自定义图片得格式大小
        filename =filename.substring(0, filename.lastIndexOf("."));
        JSONObject ofdimage=new JSONObject();
//        JSONArray returnObj = new JSONArray();
        String filepath =TecrunUtils.getFilePathFromBatchIdAndFileId(rootPath, batchId, file_id, 0);
        Path src=Paths.get(filepath);
        try{
            OFDReader reader = new OFDReader(src);
            ImageMaker imageMaker = new ImageMaker(reader, 15);
                // 4. 指定页码转换图片
                BufferedImage image = imageMaker.makePage(0);
                String newFileId = TecrunUtils.createFileId();
                String imageName=filename+"_"+0+"."+type;
                String imagePath = TecrunUtils.getFilePathFromBatchIdAndFileId(rootPath, batchId, newFileId, 0);
                String thumbImagePath = TecrunUtils.getFilePathFromBatchIdAndFileId(rootPath, batchId, newFileId, 1);
//                String imagePath=fileFloder+newFileId+"_0";
//                String thumbImagePath=fileFloder+newFileId+"_1.jpg";
                Path dist = Paths.get(imagePath);
                // 5. 存储为指定格式图片
                ImageIO.write(image, "png", dist.toFile());
                ///生成每一页的缩略图
                Thumbnails.of(imagePath).size(200, 200)
                        .outputFormat("jpg").toFile(thumbImagePath);

                ofdimage.put("file_id",newFileId);
                ofdimage.put("imagePath",imagePath);
                ofdimage.put("thumbImagePath",thumbImagePath);
                ofdimage.put("file_name",imageName);
                ofdimage.put("file_size", new File(imagePath).length());
                ofdimage.put("file_suffix",type);
            System.out.println("ofdtoPic-ok");
        }catch(Exception e){
            e.printStackTrace();
        }
        return ofdimage;
    }


    //ofd文件从那一页转图
    public static JSONArray OfdToImageByPageByIndex(String rootPath, String file_id, String batchId, String filename, String type,int Index) {
        // 将pdf装图片 并且自定义图片得格式大小
        filename =filename.substring(0, filename.lastIndexOf("."));
        JSONArray returnObj = new JSONArray();
        String filepath =TecrunUtils.getFilePathFromBatchIdAndFileId(rootPath, batchId, file_id, 0);
        Path src=Paths.get(filepath);
        try{
            OFDReader reader = new OFDReader(src);
            ImageMaker imageMaker = new ImageMaker(reader, 15);
            for (int i = Index; i < imageMaker.pageSize(); i++) {
                // 4. 指定页码转换图片
                BufferedImage image = imageMaker.makePage(i);
                String newFileId = TecrunUtils.createFileId();
                String imageName=filename+"_"+i+"."+type;
                String imagePath = TecrunUtils.getFilePathFromBatchIdAndFileId(rootPath, batchId, newFileId, 0);
                String thumbImagePath = TecrunUtils.getFilePathFromBatchIdAndFileId(rootPath, batchId, newFileId, 1);
//                String imagePath=fileFloder+newFileId+"_0";
//                String thumbImagePath=fileFloder+newFileId+"_1.jpg";
                Path dist = Paths.get(imagePath);
                // 5. 存储为指定格式图片
                ImageIO.write(image, "png", dist.toFile());
                ///生成每一页的缩略图
                Thumbnails.of(imagePath).size(200, 200)
                        .outputFormat("jpg").toFile(thumbImagePath);

                JSONObject ofdimage=new JSONObject();
                ofdimage.put("file_id",newFileId);
                ofdimage.put("imagePath",imagePath);
                ofdimage.put("thumbImagePath",thumbImagePath);
                ofdimage.put("file_name",imageName);
                ofdimage.put("file_size", new File(imagePath).length());
                ofdimage.put("file_suffix",type);
                returnObj.add(ofdimage);

            }
            System.out.println("ofdtoPic-ok");
        }catch(Exception e){
            e.printStackTrace();
        }
        return returnObj;
    }


    //ofd文件所有也都转图
    public static JSONObject OfdToImageByPageNum(String rootPath, String file_id, String batchId, String filename, String type,int PageNum) {
        // 将pdf装图片 并且自定义图片得格式大小
        filename =filename.substring(0, filename.lastIndexOf("."));
        JSONObject ofdimage=new JSONObject();
        String filepath =TecrunUtils.getFilePathFromBatchIdAndFileId(rootPath, batchId, file_id, 0);
        Path src=Paths.get(filepath);
        OFDReader reader =null;
        ImageMaker imageMaker =null;
        BufferedImage image =null;
        try{
            reader = new OFDReader(src);
            imageMaker = new ImageMaker(reader, 15);
            // 4. 指定页码转换图片
            image = imageMaker.makePage(PageNum);
            String newFileId = TecrunUtils.createFileId();
            String imageName=filename+"_"+PageNum+"."+type;
            String imagePath = TecrunUtils.getFilePathFromBatchIdAndFileId(rootPath, batchId, newFileId, 0);
            String thumbImagePath = TecrunUtils.getFilePathFromBatchIdAndFileId(rootPath, batchId, newFileId, 1);
//                String imagePath=fileFloder+newFileId+"_0";
//                String thumbImagePath=fileFloder+newFileId+"_1.jpg";
            Path dist = Paths.get(imagePath);
            // 5. 存储为指定格式图片
            ImageIO.write(image, "png", dist.toFile());
            ///生成每一页的缩略图
            Thumbnails.of(imagePath).size(200, 200)
                    .outputFormat("jpg").toFile(thumbImagePath);

            ofdimage.put("file_id",newFileId);
            ofdimage.put("imagePath",imagePath);
            ofdimage.put("thumbImagePath",thumbImagePath);
            ofdimage.put("file_name",imageName);
            ofdimage.put("file_size", new File(imagePath).length());
            ofdimage.put("file_suffix",type);
            System.out.println("ofdtoPic-ok");
        }catch(Exception e){
            e.printStackTrace();
        }finally {
              reader =null;
              imageMaker =null;
              image =null;
        }
        return ofdimage;
    }

    public static void main(String[] args) {
       OfdToImage.OfdToImageByPage("","","","","");
    }

}

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


import com.tecrun.common.utils.ConvertUpMoneyUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.dom4j.*;
import org.dom4j.io.SAXReader;
import org.springframework.util.StreamUtils;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;


/**
 * 专用于处理电子发票识别的类
 *
 *
 */

@Slf4j
public class OfdInvoiceExtractor {


    /*
    解析ofd发票,但有局限,ofd文件解压后必须要有Doc_0/Attachs/original_invoice.xml这个
     */
    public static Invoice extract(File file) throws IOException, DocumentException {
        ZipFile zipFile = new ZipFile(file);
        ZipEntry entry = zipFile.getEntry("Doc_0/Attachs/original_invoice.xml");
        ZipEntry entry1 = zipFile.getEntry("Doc_0/Pages/Page_0/Content.xml");
        InputStream input = zipFile.getInputStream(entry);
        InputStream input1 = zipFile.getInputStream(entry1);
        String body = StreamUtils.copyToString(input, Charset.forName("utf-8"));
        String content = StreamUtils.copyToString(input1, Charset.forName("utf-8"));
        zipFile.close();
        Document document = DocumentHelper.parseText(body);
        Element root = document.getRootElement();
        Invoice invoice = new Invoice();
        invoice.setMachineNumber(root.elementTextTrim("MachineNo"));
        invoice.setCode(root.elementTextTrim("InvoiceCode"));
        invoice.setNumber(root.elementTextTrim("InvoiceNo"));
        invoice.setDate(root.elementTextTrim("IssueDate"));
        invoice.setChecksum(root.elementTextTrim("InvoiceCheckCode"));
        invoice.setAmount( root.elementTextTrim("TaxExclusiveTotalAmount"));
        invoice.setTaxAmount(root.elementTextTrim("TaxTotalAmount"));
        int ind = content.indexOf("圆整</ofd:TextCode>");
        invoice.setTotalAmountString(content.substring(content.lastIndexOf(">", ind) + 1, ind + 2));
        invoice.setTotalAmount(root.elementTextTrim("TaxInclusiveTotalAmount"));
        invoice.setPayee(root.elementTextTrim("Payee"));
        invoice.setReviewer(root.elementTextTrim("Checker"));
        invoice.setDrawer(root.elementTextTrim("InvoiceClerk"));
        int index = content.indexOf("</ofd:TextCode>");
        invoice.setTitle(content.substring(content.lastIndexOf(">", index) + 1, index));
        invoice.setType("普通发票");
        if (invoice.getTitle().contains("专用发票")) {
            invoice.setType("专用发票");
        } else if (invoice.getTitle().contains("通行费")) {
            invoice.setType("通行费");
        }
        invoice.setPassword(root.elementText("TaxControlCode"));
        Element buyer = root.element("Buyer");
        {
            invoice.setBuyerName(buyer.elementTextTrim("BuyerName"));
            invoice.setBuyerCode(buyer.elementTextTrim("BuyerTaxID"));
            invoice.setBuyerAddress(buyer.elementTextTrim("BuyerAddrTel"));
            invoice.setBuyerAccount(buyer.elementTextTrim("BuyerFinancialAccount"));
        }
        Element seller = root.element("Seller");
        {
            invoice.setSellerName(seller.elementTextTrim("SellerName"));
            invoice.setSellerCode(seller.elementTextTrim("SellerTaxID"));
            invoice.setSellerAddress(seller.elementTextTrim("SellerAddrTel"));
            invoice.setSellerAccount(seller.elementTextTrim("SellerFinancialAccount"));
        }
        Element details = root.element("GoodsInfos");
        {
            List<Detail> detailList = new ArrayList<>();
            List<Element> elements = details.elements();
            for (Element element : elements) {
                Detail detail = new Detail();
                detail.setName(element.elementTextTrim("Item"));
                detail.setAmount(element.elementTextTrim("Amount"));
                detail.setTaxAmount(element.elementTextTrim("TaxAmount"));
                detail.setCount(element.elementTextTrim("Quantity"));
                detail.setPrice(element.elementTextTrim("Price"));
                detail.setUnit(element.elementTextTrim("MeasurementDimension"));
                detail.setModel(element.elementTextTrim("Specification"));
                detail.setTaxRate(element.elementTextTrim("TaxScheme").replace("%", ""));
                detailList.add(detail);
            }
            invoice.setDetailList(detailList);
        }
        return invoice;
    }

    /**
     * 解析ofd文件
     * @param file
     * @return
     * @throws IOException
     * @throws DocumentException
     */
    public static Invoice extractOFD(File file) throws IOException, DocumentException {
        ZipFile zipFile = new ZipFile(file);
        Invoice invoice = new Invoice();
        ZipEntry entry = zipFile.getEntry("OFD.xml");
        InputStream input = zipFile.getInputStream(entry);
        String body = StreamUtils.copyToString(input, Charset.forName("utf-8"));
        String content ="";
        String bodyAttachs ="";
        String contentinputTags="";
        try {
            ZipEntry entry1 = zipFile.getEntry("Doc_0/Pages/Page_0/Content.xml");
            InputStream input1 = zipFile.getInputStream(entry1);
            content = StreamUtils.copyToString(input1, Charset.forName("utf-8"));

            ZipEntry entryAttachs = zipFile.getEntry("Doc_0/Attachs/original_invoice.xml");

            ZipEntry CustomTag = zipFile.getEntry("Doc_0/Tags/CustomTag.xml");
            InputStream inputTags = zipFile.getInputStream(CustomTag);
            contentinputTags = StreamUtils.copyToString(inputTags, Charset.forName("utf-8"));

            if(null!=entryAttachs){
                InputStream inputAttachs = zipFile.getInputStream(entryAttachs);
                bodyAttachs = StreamUtils.copyToString(inputAttachs, Charset.forName("utf-8"));

            }else{
                log.info("不是标准发票!!!!没有Doc_0/Attachs/original_invoice.xml");
//            return invoice;
            }
        }catch (Exception ex) {
          ex.getMessage();
          System.out.println("不是发票!");
          return invoice;
        }

        zipFile.close();

        Document document = DocumentHelper.parseText(body);
        Element root = document.getRootElement();
        String DocBody = root.elementTextTrim("DocBody");
        System.out.println(DocBody);
        System.out.println(root.attributeValue("DocType"));用此判断是否ofd文件
        System.out.println(root.getName());
        List<Element> contactList =root.elements("DocBody");
        if ( !contactList.isEmpty() &&contactList.size()==1){
            Element docinfo= contactList.get(0);
            List<Element> docinfoList =docinfo.elements("DocInfo");
            if ( !docinfoList.isEmpty() &&docinfoList.size()==1){
                Element info= docinfoList.get(0);
                String  CreationDate=info.elementTextTrim("CreationDate");
                System.out.println(CreationDate);
                List<Element> CustomDatas = info.elements("CustomDatas");

                if ( !CustomDatas.isEmpty() &&CustomDatas.size()>0){
                    Element CustomData= CustomDatas.get(0);
                    List<Element> Data= CustomData.elements("CustomData");
                    for (Element element : Data) {
                        String name=element.attributeValue("Name");
                        System.out.println(name);
                        if("发票代码".equals(name)){
                            invoice.setCode(element.getText());
                            以此区分是不是全电发票,普通票有发票代码,
                            invoice.setFormat("200");
                        }else {
                            invoice.setFormat("300");
                        }
                        if("发票号码".equals(name)){
                            invoice.setNumber(element.getText());
                        }
                        if("合计税额".equals(name)){
                            invoice.setTaxAmount(element.getText());
                        }
                        if("合计金额".equals(name)){
                            invoice.setAmount(element.getText());
                        }
                        if("开票日期".equals(name)){
                            invoice.setDate(element.getText());
                        }
                        if("校验码".equals(name)){
                            invoice.setChecksum(element.getText());
                        }
                        if("购买方纳税人识别号".equals(name)){
                            invoice.setBuyerCode(element.getText());
                        }
                        if("销售方纳税人识别号".equals(name)){
                            invoice.setSellerCode(element.getText());
                        }
                        String text=element.getText();
                        System.out.println(text);

                    }
                }else {
                    System.out.println("不是标准发票!!!!");
                    return  invoice;
                }

            }

        }

        ///解析的是Doc_0/Attachs/original_invoice.xml可有一些ofd发票不会有这个xml但是肯定有OFD.xml 必然能提取出发票代码等信息
        if(!"".equals(bodyAttachs)){
            Document documentAttachs = DocumentHelper.parseText(bodyAttachs);
            Element rootAttachs = documentAttachs.getRootElement();
            invoice.setMachineNumber(rootAttachs.elementTextTrim("MachineNo"));
    //        invoice.setCode(rootAttachs.elementTextTrim("InvoiceCode"));
    //        invoice.setNumber(rootAttachs.elementTextTrim("InvoiceNo"));
    //        invoice.setDate(rootAttachs.elementTextTrim("IssueDate"));
    //        invoice.setChecksum(rootAttachs.elementTextTrim("InvoiceCheckCode"));
    //        invoice.setAmount( rootAttachs.elementTextTrim("TaxExclusiveTotalAmount"));spire.pdf.free
    //        invoice.setTaxAmount(rootAttachs.elementTextTrim("TaxTotalAmount"));


            int ind = content.indexOf("圆整</ofd:TextCode>");
            invoice.setTotalAmountString(content.substring(content.lastIndexOf(">", ind) + 1, ind + 2));
            int index = content.indexOf("</ofd:TextCode>");
            invoice.setTitle(content.substring(content.lastIndexOf(">", index) + 1, index));

            invoice.setTotalAmount(rootAttachs.elementTextTrim("TaxInclusiveTotalAmount"));
            invoice.setPayee(rootAttachs.elementTextTrim("Payee"));
            invoice.setReviewer(rootAttachs.elementTextTrim("Checker"));
            invoice.setDrawer(rootAttachs.elementTextTrim("InvoiceClerk"));
            invoice.setType("普通发票");
            if ("200".equals(invoice.getFormat())){
                invoice.setFormat("202");
            }else if ("300".equals(invoice.getFormat())){
                invoice.setFormat("302");
            }
            if (invoice.getTitle().contains("专用发票")) {
                invoice.setType("专用发票");
                if ("200".equals(invoice.getFormat())){
                    invoice.setFormat("201");
                }else if ("300".equals(invoice.getFormat())){
                    invoice.setFormat("301");
                }
            } else if (invoice.getTitle().contains("通行费")) {
                invoice.setType("通行费");
            }
            invoice.setPassword(rootAttachs.elementText("TaxControlCode"));
            Element buyer = rootAttachs.element("Buyer");
            {
                invoice.setBuyerName(buyer.elementTextTrim("BuyerName"));
    //            invoice.setBuyerCode(buyer.elementTextTrim("BuyerTaxID"));
                invoice.setBuyerAddress(buyer.elementTextTrim("BuyerAddrTel"));
                invoice.setBuyerAccount(buyer.elementTextTrim("BuyerFinancialAccount"));
            }
            Element seller = rootAttachs.element("Seller");
            {
                invoice.setSellerName(seller.elementTextTrim("SellerName"));
    //            invoice.setSellerCode(seller.elementTextTrim("SellerTaxID"));
                invoice.setSellerAddress(seller.elementTextTrim("SellerAddrTel"));
                invoice.setSellerAccount(seller.elementTextTrim("SellerFinancialAccount"));
            }
            Element details = rootAttachs.element("GoodsInfos");
            {
                List<Detail> detailList = new ArrayList<>();
                List<Element> elements = details.elements();
                for (Element element : elements) {
                    Detail detail = new Detail();
                    detail.setName(element.elementTextTrim("Item"));
                    detail.setAmount(element.elementTextTrim("Amount"));
                    detail.setTaxAmount(element.elementTextTrim("TaxAmount"));
                    detail.setCount(element.elementTextTrim("Quantity"));
                    detail.setPrice(element.elementTextTrim("Price"));
                    detail.setUnit(element.elementTextTrim("MeasurementDimension"));
                    detail.setModel(element.elementTextTrim("Specification"));
                    detail.setTaxRate(element.elementTextTrim("TaxScheme").replace("%", ""));
                    detailList.add(detail);
                }
                invoice.setDetailList(detailList);
            }
        }else if(!"".equals(contentinputTags)){
            Element rootAttachs =null;
            Element Layer =null;
            try {
                Document documentAttachs = DocumentHelper.parseText(contentinputTags);
                rootAttachs = documentAttachs.getRootElement();

                Document contentstr = DocumentHelper.parseText(content);
                Element contentAttachs = contentstr.getRootElement();

                Element Content = contentAttachs.element("Content");
//            List<Node> list1 = Content.content();
                Layer = Content.element("Layer");
            }catch (Exception ce){
                log.error("ofd文件解析出错!!"+ce.getMessage());
                ce.printStackTrace();
                return invoice;
            }

//
//            List<Node> list = Layer.content();
//            for( Node attribute:list){
//               String ss= attribute.getText();
//                Document ss1= attribute.getDocument();
//                Element ss2= ss1.getRootElement();
//                System.out.println(1);
//            }
//
//            Attribute att=Layer.attribute("ID");
//            String value=att.getValue();//6946
//            Element TextObject = Layer.element("TextObject");
//            List<Attribute> attrlist=TextObject.attributes();
//
//            Element TextCode = TextObject.element("TextCode");

                Element Buyer = rootAttachs.element("Buyer");
            if(Buyer!=null){
                    Element BuyerName = Buyer.element("BuyerName");
                    String  BuyerNameObjectRef="";
                    if(BuyerName!=null){
                        BuyerNameObjectRef=BuyerName.elementTextTrim("ObjectRef");
                        Element b=Layer.elementByID(BuyerNameObjectRef);
                        String s=b.element("TextCode").getText();
                        invoice.setBuyerName(s);

                    }
                    Element BuyerTaxID = Buyer.element("BuyerTaxID");
                    String  BuyerTaxIDObjectRef="";
                    if(BuyerTaxID!=null){
                          BuyerTaxIDObjectRef=BuyerTaxID.elementTextTrim("ObjectRef");
                          Element b=Layer.elementByID(BuyerTaxIDObjectRef);
                          String s=b.element("TextCode").getText();
                          invoice.setBuyerCode(s);
                    }
                    Element BuyerAddrTel = Buyer.element("BuyerAddrTel");
                    String  BuyerAddrTelObjectRef="";
                    if(BuyerAddrTel!=null){
                           BuyerAddrTelObjectRef=BuyerAddrTel.elementTextTrim("ObjectRef");
                           Element b=Layer.elementByID(BuyerAddrTelObjectRef);
                           String s=b.element("TextCode").getText();
                           invoice.setBuyerAddress(s);
                    }
                    Element BuyerFinancialAccount = Buyer.element("BuyerFinancialAccount");
                    String  BuyerFinancialAccountObjectRef="";
                    if(BuyerFinancialAccount!=null){
                           BuyerFinancialAccountObjectRef=BuyerFinancialAccount.elementTextTrim("ObjectRef");
                            Element b=Layer.elementByID(BuyerFinancialAccountObjectRef);
                            String s=b.element("TextCode").getText();
                            invoice.setBuyerAccount(s);
                    }

                }
                Element seller = rootAttachs.element("Seller");
            if(seller!=null) {
                    Element SellerName = seller.element("SellerName");
                    String  SellerNameRef="";
                    if(SellerName!=null){
                        SellerNameRef=SellerName.elementTextTrim("ObjectRef");
                        Element b=Layer.elementByID(SellerNameRef);
                        String s=b.element("TextCode").getText();
                        invoice.setSellerName(s);
                    }
                    Element SellerTaxID = seller.element("SellerTaxID");
                    String  SellerTaxIDRef="";
                    if(SellerTaxID!=null){
                        SellerTaxIDRef=SellerTaxID.elementTextTrim("ObjectRef");
                        Element b=Layer.elementByID(SellerTaxIDRef);
                        String s=b.element("TextCode").getText();
                        invoice.setSellerCode(s);
                    }
                    Element SellerAddrTel = seller.element("SellerAddrTel");
                    String  SellerAddrTelRef="";
                    if(SellerAddrTel!=null){
                        SellerAddrTelRef=SellerAddrTel.elementTextTrim("ObjectRef");
                        Element b=Layer.elementByID(SellerAddrTelRef);
                        String s=b.element("TextCode").getText();
                        invoice.setSellerAddress(s);
                    }
                    Element SellerFinancialAccount = seller.element("SellerFinancialAccount");
                    String  SellerFinancialAccountRef="";
                    if(SellerFinancialAccount!=null){
                        SellerFinancialAccountRef=SellerFinancialAccount.elementTextTrim("ObjectRef");
                        Element b=Layer.elementByID(SellerFinancialAccountRef);
                        String s=b.element("TextCode").getText();
                        invoice.setSellerAccount(s);
                    }
                }
            {
                Element InvoiceNo1= rootAttachs.element("InvoiceNo");///发票号码
                if(InvoiceNo1!=null &&  StringUtils.isBlank(invoice.getNumber())){
                    String ref=InvoiceNo1.elementTextTrim("ObjectRef");
                    Element b=Layer.elementByID(ref);
                    String s=b.element("TextCode").getText();
                    invoice.setNumber(s);
                }
                Element InvoiceCode= rootAttachs.element("InvoiceCode");///发票代码
                if(InvoiceCode!=null &&  StringUtils.isBlank(invoice.getCode())){
                    String ref=InvoiceCode.elementTextTrim("ObjectRef");
                    Element b=Layer.elementByID(ref);
                    String s=b.element("TextCode").getText();
                    invoice.setCode(s);
                }

                Element IssueDate= rootAttachs.element("IssueDate");开票日期
                if(IssueDate!=null &&  StringUtils.isBlank(invoice.getDate())){
                    String ref=IssueDate.elementTextTrim("ObjectRef");
                    Element b=Layer.elementByID(ref);
                    String s=b.element("TextCode").getText();
                    invoice.setDate(s);
                }

                Element TaxInclusiveTotalAmount= rootAttachs.element("TaxInclusiveTotalAmount");价税合计 小写
                if(TaxInclusiveTotalAmount!=null && StringUtils.isBlank(invoice.getTotalAmount())){
                   List<Element> ObjectReflist=TaxInclusiveTotalAmount.elements("ObjectRef");
                    String s="";
                   for(Element obj:ObjectReflist){
                       String ref=obj.getText();
                       Element b=Layer.elementByID(ref);
                       if (Objects.nonNull(b)) {
                           s+=b.element("TextCode").getText();
                       }
                   }
                    invoice.setTotalAmount(s.replaceAll("¥",""));
                    invoice.setTotalAmountString(ConvertUpMoneyUtil.toChinese(invoice.getTotalAmount()));
                }

                Element TaxExclusiveTotalAmount= rootAttachs.element("TaxExclusiveTotalAmount");合计金额
                if(TaxExclusiveTotalAmount!=null && StringUtils.isBlank(invoice.getAmount())){
                    List<Element> ObjectReflist=TaxExclusiveTotalAmount.elements("ObjectRef");
                    String s="";
                    for(Element obj:ObjectReflist){
                        String ref=obj.getText();
                        Element b=Layer.elementByID(ref);
                        s+=b.element("TextCode").getText();
                    }
                    invoice.setAmount(s.replaceAll("¥",""));
                }
                Element TaxTotalAmount= rootAttachs.element("TaxTotalAmount");合计税额
                if(TaxTotalAmount!=null && StringUtils.isBlank(invoice.getTaxAmount())){
                    List<Element> ObjectReflist=TaxTotalAmount.elements("ObjectRef");
                    String s="";
                    for(Element obj:ObjectReflist){
                        String ref=obj.getText();
                        Element b=Layer.elementByID(ref);
                        s+=b.element("TextCode").getText();
                    }
                    invoice.setTaxAmount(s);
                }

                Element InvoiceClerk= rootAttachs.element("InvoiceClerk");开票人
                if(InvoiceClerk!=null && StringUtils.isBlank(invoice.getDrawer())){
                    String ref=InvoiceClerk.elementTextTrim("ObjectRef");
                    Element b=Layer.elementByID(ref);
                    String s=b.element("TextCode").getText();
                    invoice.setDrawer(s);
                }



            }



            }

        if (StringUtils.isBlank(invoice.getTotalAmountString())){
            int ind = content.indexOf("圆整</ofd:TextCode>");
            invoice.setTotalAmountString(content.substring(content.lastIndexOf(">", ind) + 1, ind + 2));
        }

        if (StringUtils.isBlank(invoice.getTitle())) {
            int index = content.indexOf("</ofd:TextCode>");
            invoice.setTitle(content.substring(content.lastIndexOf(">", index) + 1, index));
        }


        return invoice;
    }

    public static void main(String[] args) {
        try {
            Invoice Invoice=  OfdInvoiceExtractor.extractOFD(new File("D:\\Desktop\\11169068(2).ofd"));
//            Invoice Invoice=  OfdInvoiceExtractor.extractOFD(new File("D:\\Desktop\\ofd\\OFD\\dzfp_23512000000051695287_20230726100031.ofd"));
            System.out.println(Invoice.toString());
//            VoucherFileInfo json=api.VoucherFileUtil.extractXBRLFromOFD("D:\\Desktop\\ofd\\OFD\\dzfp_23512000000051695287_20230726100031.ofd");
//            System.out.println(json.toString());

        } catch (IOException e) {
            e.printStackTrace();
        } catch (DocumentException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }

public class Invoice {
    private String format;//版式        电票目前支持  传统增票(专票201、普票202,200),全电发票(专票301、普票302,300)
    private String title; //发票名称
    private String machineNumber;//机器编号
    private String code;//发票代码
    private String number;//发票号码
    private String date;///开票日期
    private String checksum;//校验码
    private String buyerName; //购买方名字
    private String buyerCode; //购买方纳税人识别号
    private String buyerAddress; //购买方地址
    private String buyerAccount;//购买方账号
    private String password;//密码区
    private String amount;//合计金额
    private String taxAmount;//合计税额
    private String totalAmountString;
    private String totalAmount;//合计
    private String sellerName;//销售方名称
    private String sellerCode;//销售方纳税人识别号
    private String sellerAddress;//销售方地址电话
    private String sellerAccount;//销售方开户行及账号
    private String payee;//收款人
    private String reviewer;//复核人
    private String drawer;//开票人
    private String type;//发票类型 如type=普通发票,
    private List<Detail> detailList; //明细

}


public class Detail {
    private String name;
    private String model;
    private String unit;
    private String count;
    private String price;
    private String amount;
    private String taxRate;
    private String taxAmount;

}

4. ofd内容的操作

4.1  内容抽取测试用例




import org.ofdrw.core.basicStructure.doc.CT_PageArea;
import org.ofdrw.reader.ContentExtractor;
import org.ofdrw.reader.OFDReader;
import org.ofdrw.reader.extractor.ExtractorFilter;
import org.ofdrw.reader.extractor.RegionTextExtractorFilter;

import java.awt.*;
import java.io.IOException;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.List;


/**
 * 内容抽取测试用例
 *
 */
public class ContentExtractorTest {

    public static Path src = Paths.get("C:/Users/kong/Desktop/ofd/MutiLayer.ofd");

    /**
     * 提取指定页面的文本
     */
    public static void  getPageContent() throws IOException {
        try (OFDReader reader = new OFDReader(src)) {
            ContentExtractor extractor = new ContentExtractor(reader);

            List<String> pageContent = extractor.getPageContent(1);
            System.out.println(pageContent);
//            assertEquals(pageContent.size(), 1);
//            assertEquals("你好呀,OFD Reader&Writer!", pageContent.get(0));
        }
    }

    /**
     * 提取矩形区域内的文字
     */
    public static void  extractByFilter() throws IOException {
        try (OFDReader reader = new OFDReader("C:/Users/kong/Desktop/ofd/keyword.ofd")) {
            CT_PageArea area = reader.getPage(1).getArea();
            System.out.println(area.getPhysicalBox());
            Rectangle rectangle = new Rectangle(0, 0, 283, 120);
            ExtractorFilter filter = new RegionTextExtractorFilter(rectangle);
            ContentExtractor extractor = new ContentExtractor(reader, filter);

            List<String> pageContent = extractor.getPageContent(1);
            System.out.println(pageContent);
        }
    }

    /**
     * 提取所有页面出现的文本
     */
    public static void  extractAll() throws IOException {
        Path src = Paths.get("C:/Users/kong/Desktop/ofd/2.ofd");
        try (OFDReader reader = new OFDReader(src)) {
            ContentExtractor extractor = new ContentExtractor(reader);

            List<String> pageContent = extractor.extractAll();
            System.out.println(pageContent);
//            assertEquals(pageContent.size(), 1);
//            assertEquals("你好呀,OFD Reader&Writer!", pageContent.get(0));
        }
    }

    /**
     * 含有PageBlock包裹的对象的文字提取测试
     */
    public static void  extractAllPageBlock() throws IOException {
        Path src = Paths.get("C:/Users/kong/Desktop/ofd/helloworld_with_pageblock.ofd");
        try (OFDReader reader = new OFDReader(src)) {
            ContentExtractor extractor = new ContentExtractor(reader);

            List<String> pageContent = extractor.extractAll();
            System.out.println(pageContent);
//            assertEquals(pageContent.size(), 1);
//            assertEquals("你好呀,OFD Reader&Writer!", pageContent.get(0));
        }
    }

    /**
     * 页面内容迭代器,通过迭代器可以实现对每一页的内容处理
     */
    public static void  traverse() throws IOException {
        Path src = Paths.get("C:/Users/kong/Desktop/ofd/2月乡厨发票(芳草地).ofd");
        try (OFDReader reader = new OFDReader(src)) {
            ContentExtractor extractor = new ContentExtractor(reader);
            extractor.traverse((pageNum, contents) -> {
                System.out.println(contents);
                // 在这里你可以做些你喜欢的事情
//                assertEquals(contents.size(), 1);
//                assertEquals("你好呀,OFD Reader&Writer!", contents.get(0));
            });
        }
    }
}

4.2  文档编辑示例


import org.ofdrw.core.action.actionType.actionGoto.CT_Dest;
import org.ofdrw.core.action.actionType.actionGoto.DestType;
import org.ofdrw.core.basicStructure.doc.Document;
import org.ofdrw.core.basicStructure.doc.bookmark.Bookmark;
import org.ofdrw.core.basicStructure.doc.bookmark.Bookmarks;
import org.ofdrw.core.basicType.ST_Box;
import org.ofdrw.core.basicType.ST_ID;
import org.ofdrw.layout.OFDDoc;
import org.ofdrw.layout.PageLayout;
import org.ofdrw.layout.StreamCollect;
import org.ofdrw.layout.VirtualPage;
import org.ofdrw.layout.edit.AdditionVPage;
import org.ofdrw.layout.edit.Attachment;
import org.ofdrw.layout.element.*;
import org.ofdrw.reader.OFDReader;

import java.io.IOException;
import java.nio.file.Path;
import java.nio.file.Paths;

/**
 * 文档编辑示例
 */
public class DocEditDemos {

    /**
     * 向文档中插入页面新的页面使用模板作为背景
     */
    public static void  vPageUseTemplateTest() throws IOException {
        Path srcP = Paths.get("C:/Users/kong/Desktop/ofd", "fptpl.ofd");
        Path outP = Paths.get("C:/Users/kong/Desktop/ofd/template_insert.ofd");
        try (OFDReader reader = new OFDReader(srcP);
             OFDDoc ofdDoc = new OFDDoc(reader, outP)) {
            final ST_Box box = reader.getPageSize(1);

            final PageLayout pageBox = new PageLayout(box);
            VirtualPage vPage2 = new VirtualPage(pageBox);

            Path imgPath = Paths.get("C:/Users/kong/Desktop/ofd", "eg_tulip.jpg");
            Img img = new Img(80, 53, imgPath);
            double x = (pageBox.getWidth() - img.getWidth()) / 2;
            double y = (pageBox.getHeight() - img.getHeight()) / 2;
            img.setPosition(Position.Absolute)
                    .setX(x).setY(y);
            img.setBorder(0.5d);
            vPage2.add(img);
            vPage2.addTemplate("9", null);

            // 插入
            ofdDoc.addVPage(vPage2);
        }
        System.out.println(">> 生成文档位置:" + outP.toAbsolutePath());

    }


    /**
     * 向已有文档中 插入 流式布局的内容
     */
    public static void  streamInsertTest() throws IOException {
        Path srcP = Paths.get("C:/Users/kong/Desktop/ofd", "拿来主义_page6.ofd");
        Path outP = Paths.get("C:/Users/kong/Desktop/ofd/StreamInserted.ofd");
        try (OFDReader reader = new OFDReader(srcP);
             OFDDoc ofdDoc = new OFDDoc(reader, outP)) {
            // 插入到第1页 位置,后面的所有内容从第1页开始递增
            StreamCollect sPage1 = new StreamCollect(1);
            sPage1.setPageNum(1);
            Paragraph p = new Paragraph("封面", 30d).setWidth(100d);
            sPage1.add(p);
            // 换页: 插入占位符告诉解析器
            sPage1.add(new PageAreaFiller());
            // 这里开始 第2页 内容
            Paragraph p2 = new Paragraph("前言", 15d).setWidth(40d);
            sPage1.add(p2);
            ofdDoc.addStreamCollect(sPage1);

            // 插入到最后一页
            Paragraph p3 = new Paragraph("尾页", 15d).setWidth(100d);
            ofdDoc.add(p3);
        }
        System.out.println("生成文档位置:" + outP.toAbsolutePath().toString());
    }

    /**
     * 向文档的指定页码插入页面
     * 原来位置上以及之后的页面,页面将会往后移动
     */
    public static void  pageInsertTest() throws IOException {
        Path srcP = Paths.get("C:/Users/kong/Desktop/ofd", "拿来主义_page6.ofd");
        Path outP = Paths.get("C:/Users/kong/Desktop/ofd/PageInserted.ofd");
        try (OFDReader reader = new OFDReader(srcP);
             OFDDoc ofdDoc = new OFDDoc(reader, outP)) {
            PageLayout pageLayout = ofdDoc.getPageLayout();
            VirtualPage vPage1 = new VirtualPage(pageLayout);
            // 插入到第1页
            vPage1.setPageNum(1);
            Paragraph p = new Paragraph("封面", 30d);
            p.setPosition(Position.Absolute);
            p.setXY(60d, 60d);
            p.setWidth(100d);
            vPage1.add(p);
            ofdDoc.addVPage(vPage1);

            VirtualPage vPage2 = new VirtualPage(pageLayout);
            // 插入到第2页
            vPage2.setPageNum(2);
            Paragraph p2 = new Paragraph("前言", 15d);
            p2.setPosition(Position.Absolute);
            p2.setXY(20d, 20d);
            p2.setWidth(40d);
            vPage2.add(p2);
            ofdDoc.addVPage(vPage2);

            // 插入到最后一页
            VirtualPage vPage3 = new VirtualPage(pageLayout);
            Paragraph p3 = new Paragraph("尾页", 15d);
            p3.setPosition(Position.Absolute);
            p3.setXY(60d, 60d);
            p3.setWidth(100d);
            vPage3.add(p3);
            ofdDoc.addVPage(vPage3);
        }
        System.out.println("生成文档位置:" + outP.toAbsolutePath().toString());

    }


    /**
     * 向已经存在页面内追加内容那
     */
    public static void  addContent2ExistPageTest() throws IOException {
        Path srcP = Paths.get("C:/Users/kong/Desktop/ofd", "helloworld.ofd");
        Path outP = Paths.get("C:/Users/kong/Desktop/ofd/EditedDoc.ofd");
        try (OFDReader reader = new OFDReader(srcP);
             OFDDoc ofdDoc = new OFDDoc(reader, outP)) {
            AdditionVPage avPage = ofdDoc.getAVPage(1);
            Div e = new Div(10d, 10d)
                    .setPosition(Position.Absolute)
                    .setX(70d).setY(113.5)
                    .setBackgroundColor(255, 192, 203)
                    .setBorder(0.353d)
                    .setPadding(5d);
            Paragraph p = new Paragraph("测试文字测试文字测试文字测试文字", 15d)
                    .setPosition(Position.Absolute)
                    .setX(50d).setY(50d)
                    .setWidth(50d)
                    .setBorderColor(255, 0, 0)
                    .setBorder(3d)
                    .setPadding(3d);
            avPage.add(e);
            avPage.add(p);

        }
        System.out.println("生成文档位置:" + outP.toAbsolutePath().toString());
    }


    /**
     * 向文档末尾追加内容,新的内容会以新的页面追加到文档的最后一页
     */
    public static void  appendLasTest() throws IOException {
        Path srcP = Paths.get("C:/Users/kong/Desktop/ofd", "helloworld.ofd");
        Path outP = Paths.get("C:/Users/kong/Desktop/ofd/AppendNewPage.ofd");
        try (OFDReader reader = new OFDReader(srcP);
             OFDDoc ofdDoc = new OFDDoc(reader, outP)) {
            String plaintext = "小时候\n" +
                    "乡愁是一枚小小的邮票\n" +
                    "我在这头\n" +
                    "母亲在那头\n" +
                    "\n" +
                    "长大后\n" +
                    "乡愁是一张窄窄的船票\n" +
                    "我在这头\n" +
                    "新娘在那头\n" +
                    "\n" +
                    "后来啊\n" +
                    "乡愁是一方矮矮的坟墓\n" +
                    "我在外头\n" +
                    "母亲在里头\n" +
                    "\n" +
                    "而现在\n" +
                    "乡愁是一湾浅浅的海峡\n" +
                    "我在这头\n" +
                    "大陆在那头\n";
            Span titleContent = new Span("乡愁").setBold(true).setFontSize(13d).setLetterSpacing(10d);
            Paragraph title = new Paragraph().add(titleContent);
            title.setFloat(AFloat.center).setMarginBottom(5d);
            ofdDoc.add(title);
            final String[] txtCollect = plaintext.split("\\\n");
            for (String txt : txtCollect) {
                Paragraph p = new Paragraph().setFontSize(4d)
                        .setLineSpace(3d)
                        .add(txt);
                ofdDoc.add(p);
            }
        }
        System.out.println("生成文档位置:" + outP.toAbsolutePath().toString());
    }

    /**
     * 设置不同的页面大小
     */
    public static void  setDiffPageSizeTest() throws IOException {
        Path srcP = Paths.get("C:/Users/kong/Desktop/ofd", "helloworld.ofd");
        Path outP = Paths.get("C:/Users/kong/Desktop/ofd/SetDiffPageSizeTest.ofd");
        try (OFDReader reader = new OFDReader(srcP);
             OFDDoc ofdDoc = new OFDDoc(reader, outP)) {
            PageLayout pageLayout = ofdDoc.getPageLayout().clone();
            pageLayout.setWidth(595d).setHeight(842d);
            VirtualPage vPage1 = new VirtualPage(pageLayout);
            Paragraph p = new Paragraph("测试内容", 30d);
            p.setPosition(Position.Absolute);
            p.setXY(60d, 60d);
            p.setWidth(100d);
            vPage1.add(p);
            ofdDoc.addVPage(vPage1);
        }
        System.out.println("生成文档位置:" + outP.toAbsolutePath().toString());
    }


    /**
     * 向文件中加入附件文件
     */
    public static void  addAttachmentTest() throws IOException {
        Path outP = Paths.get("C:/Users/kong/Desktop/ofd/AddAttachment.ofd");
        Path file = Paths.get("C:/Users/kong/Desktop/ofd", "eg_tulip.jpg");
        Path file2 = Paths.get("C:/Users/kong/Desktop/ofd", "NotoSerifCJKsc-Regular.otf");

        try (OFDDoc ofdDoc = new OFDDoc(outP)) {
            Paragraph p = new Paragraph();
            Span span = new Span("这是一个带有附件的OFD文件").setFontSize(10d);
            p.add(span);
            ofdDoc.add(p);

            // 加入附件文件
            ofdDoc.addAttachment(new Attachment("Gao", file));
            ofdDoc.addAttachment(new Attachment("FontFile", file2));
        }
        System.out.println("生成文档位置:" + outP.toAbsolutePath().toString());
    }

    /**
     * 替换附件文件
     */
    public static void  replaceAttachmentTest() throws IOException {
        Path srcP = Paths.get("C:/Users/kong/Desktop/ofd/AddAttachment.ofd");
        Path outP = Paths.get("C:/Users/kong/Desktop/ofd/ReplaceAttachment.ofd");
        Path file = Paths.get("C:/Users/kong/Desktop/ofd", "ASCII字体宽度测量.html");

        try (OFDReader reader = new OFDReader(srcP);
             OFDDoc ofdDoc = new OFDDoc(reader, outP)) {
            // 加入附件文件
            ofdDoc.addAttachment(new Attachment("Gao", file));
        }
        System.out.println("生成文档位置:" + outP.toAbsolutePath().toString());
    }


    /**
     * 添加书签
     */
    public static void  addBookmarkTest() throws IOException {
        Path srcP = Paths.get("C:/Users/kong/Desktop/ofd/Page5.ofd");
        Path outP = Paths.get("C:/Users/kong/Desktop/ofd/addBookmark.ofd");
        try (OFDReader reader = new OFDReader(srcP);
             OFDDoc ofdDoc = new OFDDoc(reader, outP)) {
            Document document = ofdDoc.getOfdDocument();
            ST_ID pageID = document.getPages().getPageByIndex(3).getID();
            CT_Dest dest = new CT_Dest()
                    .setType(DestType.Fit)
                    .setPageID(pageID.ref());
            Bookmarks bookmarks = document.getBookmarks();
            if (bookmarks == null) {
                bookmarks = new Bookmarks();
                document.setBookmarks(bookmarks);
            }
            bookmarks.addBookmark(new Bookmark("美好一天", dest));
        }
    }
}

4.3   文档操作工具


import org.junit.Test;
import org.ofdrw.graphics2d.OFDGraphicsDocument;
import org.ofdrw.graphics2d.OFDPageGraphics2D;
import org.ofdrw.tool.merge.OFDMerger;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.nio.file.Path;
import java.nio.file.Paths;


/**
 * 文档操作工具
 * OFDMerger 提供了页面级别的多文档编辑功能,包括:
 * 多文档合并
 * 文档页裁剪
 * 多文档页重组
 * OFDMerger#add方法支持可选参数,指定需要合并的页面页码(从1开始),通过灵活使用该API可以实现多文档页面级别编辑功能。
 * 文档操作将会导致文档结构内容变更,这将导致数字签名无效,请悉知!
 *
 */
public class OFDMergerTest {

    public static void   add() throws IOException {
        Path dst = Paths.get("C:/Users/kong/Desktop/ofd/n1.ofd");
        Path d1Path = Paths.get("C:/Users/kong/Desktop/ofd", "y.ofd");
        Path d2Path = Paths.get("C:/Users/kong/Desktop/ofd", "发票示例.ofd");

        try (OFDMerger ofdMerger = new OFDMerger(dst)) {
            ofdMerger.add(d1Path, 2);
            ofdMerger.add(d2Path, 1);
            ofdMerger.add(d1Path, 1);
        }
    }

    public static void   add2() throws IOException {
        Path dst = Paths.get("C:/Users/kong/Desktop/ofd/n2.ofd");
        Path d1Path = Paths.get("C:/Users/kong/Desktop/ofd", "y.ofd");
        Path d2Path = Paths.get("C:/Users/kong/Desktop/ofd", "发票示例.ofd");

        try (OFDMerger ofdMerger = new OFDMerger(dst)) {
            ofdMerger.add(d1Path,1,1);
            ofdMerger.add(d2Path);
            ofdMerger.add(d1Path);
        }
    }

//多文档页重组
//将多个文档中的页面合并到同一份文档中,并可以可用页面在新文档中的顺序。
    public static void   add3() throws IOException {

        Path dst = Paths.get("dst.ofd");
        Path d1Path = Paths.get("file1.ofd");
        Path d2Path = Paths.get("file2.ofd");
        try (OFDMerger ofdMerger = new OFDMerger(dst)) {
            ofdMerger.add(d1Path, 1, 2);
            ofdMerger.add(d2Path, 1);
            ofdMerger.add(d1Path, 3);
        }

    }
//    裁剪
//    截取文档的部分页面生成新的文档。
    public static void   add4() throws IOException {
            Path dst = Paths.get("dst.ofd");
            Path d1Path = Paths.get("file1.ofd");
            try (OFDMerger ofdMerger = new OFDMerger(dst)) {
                ofdMerger.add(d1Path, 1, 2);
            }

    }
    public static void main(String[] args) throws Exception {
        final Path dst = Paths.get("D:\\Desktop\\ofd\\HelloWorld撒旦法刚刚.ofd");
        try (OFDGraphicsDocument doc = new OFDGraphicsDocument(dst)) {
            int width=210;
            File sourceimage = new File("C:\\Users\\kong\\Pictures\\Saved Pictures\\1-869.jpg");  //source.gif图片要与HelloJava.java同在一目录下
            BufferedImage image = ImageIO.read(sourceimage);
            int w = image.getWidth();
            int h = image.getHeight();
            double hh= width*1.000/w;
            double higth= hh*h;

            OFDPageGraphics2D g = doc.newPage(width,higth);
            g.drawImage(image, 0, 0, width, (int) higth, null);
            g.dispose();
//            g.setColor(Color.BLACK);
//            g.setFont(new Font("宋体", Font.PLAIN, 7));
//            g.drawString("你好OFD Reader & Writer Graphics-2D", 40, 40);

            doc.addResImg(image);
        }

        System.out.println(">> " + dst.toAbsolutePath());
//        drawImage();
//        drawImage2();
//        drawImageAffineTransform();
    }
    @Test
    public static void drawImage() throws Exception {
        final Path dst = Paths.get("D:\\Desktop\\ofd\\HelloWorld.ofd");
        try (OFDGraphicsDocument doc = new OFDGraphicsDocument(dst)) {
            Path file = Paths.get("C:\\Users\\kong\\Pictures\\Saved Pictures\\1-869.jpg");
            BufferedImage img1 = ImageIO.read(file.toFile());
            int width = img1.getWidth(null);
            int height = img1.getHeight(null);


            OFDPageGraphics2D g = doc.newPage(width, height);
            g.drawImage(img1, 0, 0, width, height, null);
        }
        System.out.println(">> " + dst.toAbsolutePath());
    }

    @Test
    public static void drawImage2() throws Exception {
        final Path dst = Paths.get("D:\\Desktop\\ofd\\HelloWorld1.ofd");
        try (OFDGraphicsDocument doc = new OFDGraphicsDocument(dst)) {
            OFDPageGraphics2D g = doc.newPage(500, 500);
            Path file = Paths.get("C:\\Users\\kong\\Pictures\\Saved Pictures\\1-869.jpg");
            BufferedImage img1 = ImageIO.read(file.toFile());

            g.drawImage(img1, 0, 0, null);
        }
        System.out.println(">> " + dst.toAbsolutePath());
    }

    @Test
    public static void drawImageAffineTransform() throws Exception {
        final Path dst = Paths.get("D:\\Desktop\\ofd\\HelloWorld2.ofd");
        try (OFDGraphicsDocument doc = new OFDGraphicsDocument(dst)) {
            OFDPageGraphics2D g = doc.newPage(500, 500);
            Path file = Paths.get("C:\\Users\\kong\\Pictures\\Saved Pictures\\1-869.jpg");
            BufferedImage img1 = ImageIO.read(file.toFile());

            g.drawImage(img1, null, 10, 10);
            g.setPaint(Color.RED);
            g.fillRect(0, 0, 30, 30);
        }
        System.out.println(">> " + dst.toAbsolutePath());
    }

}

4.4  段落布局演示

 

import org.ofdrw.font.FontName;
import org.ofdrw.layout.OFDDoc;
import org.ofdrw.layout.element.*;

import java.io.IOException;
import java.nio.file.Path;
import java.nio.file.Paths;

/**
 * 段落布局演示
 *
 */
public class ParagraphLayoutDemo {

    /**
     * 测试段落内文字浮动
     */
    void testParagraphInlineFloat() throws IOException {
        Path outP = Paths.get("C:/Users/kong/Desktop/ofd/testParagraphInlineFloat.ofd");
        try (OFDDoc ofdDoc = new OFDDoc(outP)) {

            // 向左浮动
            Paragraph p1 = new Paragraph("这是左浮动内容", 4d)
                    .setTextAlign(TextAlign.left);
            Paragraph p2 = new Paragraph("这是\n多行的文本\n\n我将采用向左浮动", 4d)
                    .setTextAlign(TextAlign.left);

            // 右浮动
            Paragraph p3 = new Paragraph("这是右浮动内容", 4d)
                    .setTextAlign(TextAlign.right);
            Paragraph p4 = new Paragraph("这是\n多行的文本\n\n我将采用向右浮动", 4d)
                    .setTextAlign(TextAlign.right);

            // 居中
            Paragraph p5 = new Paragraph("这是居中内容", 4d)
                    .setTextAlign(TextAlign.center);
            Paragraph p6 = new Paragraph("这是\n多行的文本\n\n我将采用向居中", 4d)
                    .setTextAlign(TextAlign.center);

            ofdDoc.add(p1)
                    .add(p2)
                    .add(p3)
                    .add(p4)
                    .add(p5)
                    .add(p6);
        }
        System.out.println("生成文档位置:" + outP.toAbsolutePath());

    }

    /**
     * 段落布局 各种情况演示
     * 
     */
    void testParagraphLayout() throws IOException {
        Path outP = Paths.get("C:/Users/kong/Desktop/ofd/ParagraphLayoutDemo.ofd");
        try (OFDDoc ofdDoc = new OFDDoc(outP)) {
            // - 独占整个行
            Paragraph p1 = new Paragraph();
            p1.add("独占整个行").setBorder(0.1d).setMargin(3d, 0d);
            // - 共享模式(inline-block)
            Paragraph p2 = new Paragraph();
            p2.add("共享模式(inline-block),元素等同于内容宽度");
            p2.setClear(Clear.none).setBorder(0.1d).setMargin(3d, 0d);
            // 结束共享模式
            Paragraph hit1 = new Paragraph("插入一个Clear=both的元素中断共享模式");
            // - 手动指定宽度,仅在 Clear != both 模式有效
            Paragraph p3 = new Paragraph();
            p3.add("手动指定宽度,仅在 Clear != both 模式有效");
            p3.setWidth(55d);
            p3.setClear(Clear.none).setBorder(0.1d).setMargin(3d, 0d);
            Paragraph hit2 = new Paragraph("插入一个Clear=both的元素中断共享模式");

            // 居中
            Paragraph pn = new Paragraph();
            pn.setWidth(80d);
            pn.setHeight(20d);
            pn.setBorder(0.4d);
            pn.setPadding(5d);
            pn.setClear(Clear.none).setIntegrity(true);
            Span sp = new Span("序号")
                    .setFont(FontName.SimHei.font())
                    .setFontSize(4d);
            pn.add(sp);
            pn.setFloat(AFloat.center);

            Paragraph hit3 = new Paragraph("插入一个Clear=both的元素中断共享模式");

            // 共享模式下 多元素同行
            Paragraph p4A = new Paragraph("这是A部分");
            p4A.setClear(Clear.none).setFloat(AFloat.center).setBorder(0.1d).setPadding(3d).setMargin(1d);
            Paragraph p4B = new Paragraph("这是B部分");
            p4B.setClear(Clear.none).setFloat(AFloat.center).setBorder(0.1d).setPadding(3d).setMargin(1d);


            ofdDoc.add(p1);
            ofdDoc.add(p2);
            ofdDoc.add(hit1);
            ofdDoc.add(p3);
            ofdDoc.add(hit2);
            ofdDoc.add(pn);
            ofdDoc.add(hit3);
            ofdDoc.add(p4A).add(p4B);

        }
        System.out.println("生成文档位置:" + outP.toAbsolutePath());
    }


    /**
     * 段落首行缩进测试用例
     */
    void testParagraphFirstLineIndent() throws IOException {
        Path outP = Paths.get("C:/Users/kong/Desktop/ofd/ParagraphFirstLineIndent.ofd");

        try (OFDDoc ofdDoc = new OFDDoc(outP)) {
            String titleStr = "济南的冬天";
            String p1Str = "对于一个在北平住惯的人,像我,冬天要是不刮风,便觉得是奇迹;济南的冬天是没有风声的。对于一个刚由伦敦回来的人,像我,冬天要能看得见日光,便觉得是怪事;济南的冬天是响晴的。自然,在热带的地方,日光是永远那么毒,响亮的天气,反有点叫人害怕。可是,在北中国的冬天,而能有温晴的天气,济南真得算个宝地。";
            String p2Str = "设若单单是有阳光,那也算不了出奇。请闭上眼睛想:一个老城,有山有水,全在天底下晒着阳光,暖和安适地睡着,只等春风来把它们唤醒,这是不是个理想的境界?";

            Span spTitle = new Span(titleStr)
                    .setFont(FontName.SimHei.font()) // 设置字体
                    .setBold(true)
                    .setFontSize(7d)
                    .setLetterSpacing(5d);
            Paragraph title = new Paragraph().add(spTitle);
            title.setFloat(AFloat.center).setMargin(5d);

            Span sp1 = new Span(p1Str)
                    .setFontSize(3d)        // 设置字体大小
                    .setLetterSpacing(3d);  // 设置字间距
            Paragraph p1 = new Paragraph()
                    .add(sp1)
                    .setFirstLineIndent(2); // 设置首行缩进

            Span sp2 = new Span(p2Str).setLetterSpacing(3d);
            Paragraph p2 = new Paragraph()
                    .add(sp2)
                    .setFirstLineIndentWidth((3d + 3d) * 2); // 设置首行缩进宽度,单位mm

            // 将段落加入文档
            ofdDoc.add(title).add(p1).add(p2);
        }
        System.out.println("生成文档位置:" + outP.toAbsolutePath().toString());
    }

    /**
     * 段落布局模式
     */
    void testPLayoutPatten() throws IOException {
        Path outP = Paths.get("C:/Users/kong/Desktop/ofd/TestPLayoutPatten.ofd");
        try (OFDDoc ofdDoc = new OFDDoc(outP)) {
            // - 独占整个行
            Paragraph p1 = new Paragraph();
            p1.add("独占整个行").setBorder(0.1d).setMargin(3d, 0d);
            // - 共享模式(inline-block)
            Paragraph p2 = new Paragraph();
            p2.add("共享模式(inline-block),元素等同于内容宽度");
            p2.setClear(Clear.none).setBorder(0.1d).setMargin(3d, 0d);
            // 结束共享模式
            Paragraph hit1 = new Paragraph("插入一个Clear=both的元素中断共享模式");
            // - 手动指定宽度,仅在 Clear != both 模式有效
            Paragraph p3 = new Paragraph();
            p3.add("手动指定宽度,仅在 Clear != both 模式有效");
            p3.setWidth(55d);
            p3.setClear(Clear.none).setBorder(0.1d).setMargin(3d, 0d);
            Paragraph hit2 = new Paragraph("插入一个Clear=both的元素中断共享模式");

            // 居中
            Paragraph pn = new Paragraph();
            pn.setWidth(80d);
            pn.setHeight(20d);
            pn.setBorder(0.4d);
            pn.setPadding(5d);
            pn.setClear(Clear.none).setIntegrity(true);
            Span sp = new Span("序号")
                    .setFont(FontName.SimHei.font())
                    .setFontSize(4d);
            pn.add(sp);
            pn.setFloat(AFloat.center);

            Paragraph hit3 = new Paragraph("插入一个Clear=both的元素中断共享模式");

            // 共享模式下 多元素同行
            Paragraph p4A = new Paragraph("这是A部分");
            p4A.setClear(Clear.none).setFloat(AFloat.center).setBorder(0.1d).setPadding(3d).setMargin(1d);
            Paragraph p4B = new Paragraph("这是B部分");
            p4B.setClear(Clear.none).setFloat(AFloat.center).setBorder(0.1d).setPadding(3d).setMargin(1d);
            ofdDoc.add(p1);
            ofdDoc.add(p2);
            ofdDoc.add(hit1);
            ofdDoc.add(p3);
            ofdDoc.add(hit2);
            ofdDoc.add(pn);
            ofdDoc.add(hit3);
            ofdDoc.add(p4A).add(p4B);
        }
        System.out.println("生成文档位置:" + outP.toAbsolutePath());
    }

    /**
     * 文档示例
     */
    void testPLayoutDoc() throws IOException {
        Path path = Paths.get("C:/Users/kong/Desktop/ofd/TestPLayoutDoc.ofd");
        try (OFDDoc ofdDoc = new OFDDoc(path)) {
            ofdDoc.add(new Paragraph("青春 选节", 10d).setClear(Clear.none).setFloat(AFloat.center));
            ofdDoc.add(new Paragraph("李大钊", 3d).setFloat(AFloat.center).setClear(Clear.left));
            String[] pArr = new String[]{
                    "人类之成一民族一国家者,亦各有其生命焉。有青春之民族,斯有白首之民族,有青春之国家,斯有白首之国家。吾之民族若国家,果为青春之民族、青春之国家欤,抑为白首之民族、白首之国家欤?苟已成白首之民族、白首之国家焉,吾辈青年之谋所以致之回春为之再造者,又应以何等信力与愿力从事,而克以著效?此则系乎青年之自觉何如耳。异族之觇吾国者,辄曰:支那者老大之邦也。支那之民族,濒灭之民族也。支那之国家,待亡之国家也。洪荒而后,民族若国家之递兴递亡者,然其不可纪矣。粤稽西史,罗马、巴比伦之盛时,丰功伟烈,彪著寰宇,曾几何时,一代声华,都成尘土矣。祗今屈指,欧土名邦,若意大利,若法兰西,若西班牙,若葡萄牙,若和兰,若比利时,若丹马,若瑞典,若那威,乃至若英吉利,罔不有积尘之历史,以重累其国家若民族之生命。回溯往祀,是等国族,固皆尝有其青春之期,以其畅盛之生命,展其特殊之天才。而今已矣,声华渐落,躯壳空存,纷纷者皆成文明史上之过客矣。其校新者,惟德意志与勃牙利,此次战血洪涛中,又为其生命力之所注,勃然暴发,以挥展其天才矣。由历史考之,新兴之国族与陈腐之国族遇,陈腐者必败;朝气横溢之生命力与死灰沉滞之生命力遇,死灰沉滞者必败;青春之国民与白首之国民遇,白首者必败,此殆天演公例,莫或能逃者也。支那自黄帝以降,赫赫然树独立之帜于亚东大陆者,四千八百余年于兹矣。历世久远,纵观横览,罕有其伦。稽其民族青春之期,远在有周之世,典章文物,灿然大备,过此以往,渐向衰歇之运,然犹浸衰浸微,扬其余辉。以至于今日者,得不谓为其民族之光欤?夫人寿之永,不过百年,民族之命,垂五千载,斯亦寿之至也。印度为生释迦而兴,故自释迦生而印度死;犹太为生耶稣而立,故自耶稣生而犹太亡;支那为生孔子而建,故自孔子生而支那衰,陵夷至于今日,残骸枯骨,满目黤然,民族之精英,澌灭尽矣,而欲不亡,庸可得乎?吾青年之骤闻斯言者,未有不变色裂眦,怒其侮我之甚也。虽然,勿怒也。吾之国族,已阅长久之历史,而此长久之历史,积尘重压,以桎梏其生命而臻于衰敝者,又宁容讳?然而吾族青年所当信誓旦旦,以昭示于世者,不在龈龈辩证白首中国之不死,乃在汲汲孕育青春中国之再生。吾族今后之能否立足于世界,不在白首中国之苟延残喘,而在青春中国之投胎复活。盖尝闻之,生命者,死与再生之连续也。今后人类之问题,民族之问题,非苟生残存之问题,乃复活更生、回春再造之问题也。与吾并称为老大帝国之土耳其,则青年之政治运动,屡试不一试焉。巴尔干诸邦,则各谋离土自立,而为民族之运动,兵连祸结,干戈频兴,卒以酿今兹世界之大变焉。遥望喜马拉亚山之巅,恍见印度革命之烽烟一缕,引而弥长,是亦欲回其民族之青春也。吾华自辛亥首义,癸丑之役继之,喘息未安,风尘澒洞,又复倾动九服,是亦欲再造其神州也。而在是等国族,凡以冲决历史之桎梏,涤荡历史之积秽,新造民族之生命,挽回民族之青春者,固莫不惟其青年是望矣。建国伊始,肇锡嘉名,实维中华。中华之义,果何居乎?中者,宅中位正之谓也。吾辈青年之大任,不仅以于空间能致中华为天下之中而遂足,并当于时间而谛时中之旨也。旷观世界之历史,古往今来,变迁何极!吾人当于今岁之青春,画为中点,中以前之历史,不过如进化论仅于考究太阳地球动植各物乃至人类之如何发生、如何进化者,以纪人类民族国家之如何发生、如何进化也。中以后之历史,则以是为古代史之职,而别以纪人类民族国家之更生回春为其中心之的也。中以前之历史,封闭之历史,焚毁之历史,葬诸坟墓之历史也。中以后之历史,洁白之历史,新装之历史,待施绚绘之历史也。中以前之历史,白首之历史,陈死人之历史也。中以后之历史,青春之历史,活青年之历史也。青年乎!其以中立不倚之精神,肩兹砥柱中流之责任,即由今年今春之今日今刹那为时中之起点,取世界一切白首之历史,一火而摧焚之,而专以发挥青春中华之中,缀其一生之美于中以后历史之首页,为其职志,而勿逡巡不前。华者,文明开敷之谓也,华与实相为轮回,即开敷与废落相为嬗代。白首中华者,青春中华本以胚孕之实也。青春中华者,白首中华托以再生之华也。白首中华者,渐即废落之中华也。青春中华者,方复开敷之中华也。有渐即废落之中华,所以有方复开敷之中华。有前之废落以供今之开敷,斯有后之开敷以续今之废落,即废落,即开敷,即开敷,即废落,终竟如是废落,终竟如是开敷。宇宙有无尽之青春,斯宇宙有不落之华,而栽之、培之、灌之、溉之、赏玩之、享爱之者,舍青春中华之青年,更谁为归矣?青年乎,勿徒发愿,愿春常在华常好也,愿华常得青春,青春常在于华也。宜有即华不得青春,青春不在于华,亦必奋其回春再造之努力,使废落者复为开敷,开敷者终不废落,使华不能不得青春,青春不能不在于华之决心也。抑吾闻之化学家焉,土质虽腴,肥料虽多,耕种数载,地力必耗,砂土硬化,无能免也,将欲柔融之,俾再反于丰穰,惟有一种草木为能致之,为其能由空中吸收窒素肥料,注入土中而沃润之也。神州赤县,古称天府,胡以至今徒有万木秋声、萧萧落叶之悲,昔时繁华之盛,荒凉废落至于此极也!毋亦无此种草木为之交柔和润之耳。青年之于社会,殆犹此种草木之于田也。从此广植根蒂,深固不可复拔,不数年间,将见青春中华之参天蓊郁,错节盘根,树于世界,而神州之域,还其丰穰,复其膏腴矣。则谓此菁菁茁茁之青年,即此方复开敷之青春中华可也。",
                    "顾人之生也,苟不能窥见宇宙有无尽之青春,则自呱呱堕地,迄于老死,觉其间之春光,迅于电波石火,不可淹留,浮生若梦,直菌鹤马蜩之过乎前耳。是以川上尼父,有逝者如斯之嗟,湘水灵均,兴春秋代序之感。其他风骚雅士,或秉烛夜游,勤事劳人,或重惜分寸。而一代帝王,一时豪富,当其垂暮之年,绝诀之际,贪恋幸福,不忍离舍,每为咨嗟太息,尽其权力黄金之用,无能永一瞬之天年,而重留遗憾于长生之无术焉。秦政并吞八荒,统制四海,固一世之雄也,晚年畏死,遍遣羽客,搜觅神仙,求不老之药,卒未能获,一旦魂断,宫车晚出。汉武穷兵,蛮荒慑伏,汉代之英主也,暮年永叹,空有“欢乐极矣哀情多,少壮几时老奈何”之慨。最近美国富豪某,以毕生之奋斗,博得式之王冠,衰病相催,濒于老死,则抚枕而叹曰:“苟能延一月之命,报以千万金弗惜也。”然是又安可得哉?夫人之生也有限,其欲也无穷,以无穷之欲,逐有限之生,坐令似水年华,滔滔东去,红颜难再,白发空悲,其殆人之无奈无何者欤!涉念及此,灰肠断气,灰世之思,油然而生。贤者仁智俱穷,不肖者流连忘返,而人生之蕲向荒矣,是又岂青年之所宜出哉?人生兹世,更无一刹那不在青春,为其居无尽青春之一部,为无尽青春之过程也。顾青年之人,或不得常享青春之乐者,以其有黄金权力一切烦忧苦恼机械生活,为青春之累耳。谚云:“百金买骏马,千金买美人,万金买爵禄,何处买青春?”岂惟无处购买,邓氏铜山,郭家金穴,愈有以障青春之路俾无由达于其境也。罗马亚布达尔曼帝,位在皇极,富有四海,不可谓不尊矣,临终语其近侍,谓四十年间,真感愉快者,仅有三日。权力之不足福人,以视黄金,又无差等。而以四十年之青春,娱心不过三日,悼心悔憾,宁有穷耶?夫青年安心立命之所,乃在循今日主义以进,以吾人之生,洵如卡莱尔所云,特为时间所执之无限而已。无限现而为我,乃为现在,非为过去与将来也。苟了现在,即了无限矣。昔者圣叹作诗,有“何处谁人玉笛声”之句。释弓年小,窃以玉字为未安,而质之圣叹。圣叹则曰:“彼若说‘我所吹本是铁笛,汝何得用作玉笛’。我便云:”我已用作玉笛,汝何得更吹铁笛?‘天生我才,岂为汝铁笛作奴儿婢子来耶?“夫铁字与玉字,有何不可通融更易之处。圣叹顾与之争一字之短长而不惮烦者,亦欲与之争我之现在耳。诗人拜轮,放浪不羁,时人诋之,谓于来世必当酷受地狱之苦。拜轮答曰:”基督教徒自苦于现世,而欲祈福于来世。非基督教徒,则于现世旷逸自遣,来世之苦,非所辞也。“二者相校,但有先后之别,安有分量之差。拜轮此言,固甚矫激,且寓风刺之旨。以余观之,现世有现世之乐,来世有来世之乐。现世有现世之青春,来世有来世之青春。为贪来世之乐与青春,而迟吾现世之乐与青春,固所不许。而为贪现世之乐与青春,遽弃吾来世之乐与青春,亦所弗应也。人生求乐,何所不可,亦何必妄分先后,区异今来也?耶曼孙曰:”尔若爱千古,当利用现在。昨日不能呼还,明日尚未确实。尔能确有把握者,惟有今日。今日之一日,适当明晨之二日。“斯言足发吾人之深省矣。盖现在者吾人青春中之青春也。青春作伴以还于大漠之乡,无如而不自得,更何烦忧之有焉。烦忧既解,恐怖奚为?耶比古达士曰:”贫不足恐,流窜不足恐,囹圄不足恐,最可恐者,恐怖其物也。“美之政雄罗斯福氏,解政之后,游猎荒山,奋其銕腕,以与虎豹熊罴相搏战。一日猎白熊,险遭吞噬,自传其事,谓为不以恐怖误其稍纵即逝之机之效,始获免焉。于以知恐怖为物,决不能拯人于危。苟其明日将有大祸临于吾躬,无论如何恐怖,明日之祸万不能因是而减其豪末。而今日之我,则因是而大损其气力,俾不足以御明日之祸而与之抗也。艰虞万难之境,横于吾前,吾惟有我、有我之现在而足恃。堂堂七尺之躯,徘徊回顾,前不见古人,后不见来者,惟有昂头阔步,独往独来,何待他人之援手,始以遂其生者,更胡为乎念天地之悠悠,独怆然而涕下哉?惟足为累于我之现在及现在之我者,机械生活之重荷,与过去历史之积尘,殆有同一之力焉。今人之赴利禄之途也,如蚁之就膻,蛾之投火,究其所企,克致志得意满之果,而营营扰扰,已逾半生,以孑然之身,强负黄金与权势之重荷以趋,几何不为所重压而僵毙耶?盖其优于权富即其短于青春者也。耶经有云:”富人之欲入天国,犹之骆驼欲潜身于针孔。“此以喻重荷之与青春不并存也。总之,青年之自觉,一在冲决过去历史之网罗,破坏陈腐学说之囹圄,勿令僵尸枯骨,束缚现在活泼泼地之我,进而纵现在青春之我,扑杀过去青春之我,促今日青春之我,禅让明日青春之我。一在脱绝浮世虚伪之机械生活,以特立独行之我,立于行健不息之大机轴。祖裼裸裎,去来无罫,全其优美高尚之天,不仅以今日青春之我,追杀今日白首之我,并宜以今日青春之我,豫杀来日白首之我,此固人生唯一之蕲向,青年唯一之责任也矣。拉凯尔曰:”长保青春,为人生无上之幸福,尔欲享兹幸福,当死于少年之中。“吾愿吾亲爱之青年,生于青春死于青春,生于少年死于少年也。德国史家孟孙氏,评骘锡札曰:”彼由青春之杯,饮人生之水,并泡沫而干之。“吾愿吾亲爱之青年,擎此夜光之杯,举人生之醍醐浆液,一饮而干也。人能如是,方为不役于物,物莫之伤。大浸稽天而不溺,大旱金石流土山焦而不热,是其尘垢粃糠,将犹陶铸尧、舜。自我之青春,何能以外界之变动而改易,历史上残骸枯骨之灰,又何能塞蔽青年之聪明也哉?市南宜僚见鲁侯,鲁侯有忧色,市南子乃示以去累除忧之道,有曰,”吾愿君去国捐俗,与道相辅而行。“君曰:”彼其道远而险,又有江山,我无舟车,奈何?“市南子曰:”君无形倨,无留居,以为舟车。“君曰:”彼其道幽远而无人,吾谁与为邻?吾无粮,我无食,安得而至焉?“市南子曰:”少君之费,寡君之欲,虽无粮而乃足,君其涉于江而浮于海,望之而不见其崖,愈往而不知其所穷,送君者将自崖而反,君自此远矣。“此其谓道,殆即达于青春之大道。",
                    "青年循蹈乎此,本其理性,加以努力,进前而勿顾后,背黑暗而向光明,为世界进文明,为人类造幸福,以青春之我,创建青春之家庭,青春之国家,青春之民族,青春之人类,青春之地球,青春之宇宙,资以乐其无涯之生。乘风破浪,迢迢乎远矣,复何无计留春望尘莫及之忧哉?吾文至此,已嫌冗赘,请诵漆园之语,以终斯篇。"
            };
            for (String s : pArr) {
                ofdDoc.add(new Paragraph(s, 5d).setFirstLineIndent(2));
            }
        }
        System.out.println("生成文档位置: " + path.toAbsolutePath());
    }
}

4.5  水印测试用例


import org.ofdrw.converter.ImageMaker;
import org.ofdrw.core.annotation.pageannot.AnnotType;
import org.ofdrw.core.basicType.ST_Box;
import org.ofdrw.font.FontName;
import org.ofdrw.layout.OFDDoc;
import org.ofdrw.layout.edit.Annotation;
import org.ofdrw.layout.element.canvas.FontSetting;
import org.ofdrw.reader.OFDReader;

import java.io.IOException;
import java.nio.file.Path;
import java.nio.file.Paths;

/**
 * 水印测试用例
 * 
 **/
public class WatermarkTest {

    /**
     * 水印处理
     */
    public void addWatermark() throws IOException {
        Path srcP = Paths.get("C:/Users/kong/Desktop/ofd", "2月乡厨发票(芳草地).ofd");
        Path outP = Paths.get("C:/Users/kong/Desktop/ofd/AddWatermarkAnnot.ofd");

        try (OFDReader reader = new OFDReader(srcP);
             OFDDoc ofdDoc = new OFDDoc(reader, outP)) {

            Double width = ofdDoc.getPageLayout().getWidth();
            Double height = ofdDoc.getPageLayout().getHeight();

            Annotation annotation = new Annotation(new ST_Box(0d, 0d, width, height), AnnotType.Watermark, ctx -> {
                FontSetting setting = new FontSetting(8, FontName.SimSun.font());

                ctx.setFillColor(170, 160, 165)
                        .setFont(setting)
                        .setGlobalAlpha(0.4);

                for (int i = 0; i <= 8; i++) {
                    for (int j = 0; j <= 8; j++) {
                        ctx.save();
                        ctx.translate(22.4 * i, j * 50);
                        ctx.rotate(45);
                        ctx.fillText("保密资料", 10, 10);
                        ctx.restore();
                    }
                }
            });

            ///给ofd文档所有页打上水印
            ImageMaker imageMaker = new ImageMaker(reader, 15);
            for (int i = 1; i <=imageMaker.pageSize(); i++) {
                ofdDoc.addAnnotation( i, annotation);
            }

        }
        System.out.println("生成文档位置:" + outP.toAbsolutePath().toString());
    }

}

5. ofd转其他文件


import org.ofdrw.converter.ConvertHelper;
import org.ofdrw.converter.GeneralConvertException;
import org.ofdrw.converter.ImageMaker;
import org.ofdrw.converter.SVGMaker;
import org.ofdrw.reader.OFDReader;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;

/**
 *
 * PDF转换概述: 通过对OFD的文档进行解析,使用 Apache Pdfbox生成并转换OFD中的元素为PDF内的元素实现PDF的转换。
 * 图片转换概述: 通过对OFD的文档进行解析,采用java.awt绘制图片,支持转换为PNG、JPEG图片格式。
 * SVG矢量图形转换概述: 使用Apachebatik-transcoder提供的图形绘制实现java.awtAPI绘制,最终生成SVG矢量图形。
 * HTML转换概述: 使用上述SVG矢量图形转换作为显示效果层A,再将OFD文档中的文字(仅)解析为SVG作为文字复制层B,B置于A层之上,
 * 文字颜色transparent,无需关心字体,在移动端同样正常显示。
 * 
 *
 */

public class OFDUtils {


    /**
     * 1.正常的ofd文件
     * 2.图片的ofd
     * 3.进过其他转换器转换而来的ofd
     */
    public static void ofdtoPdf(Path input, Path output) {
        /****************************************************
         * 转换成PDF    如图不是全屏图转成pdf后显示会乱
         */
//		  1. 文件输入路径
        Path src =input;// Paths.get("C:/Users/kong/Desktop/ofd/OFD/第三方ofd/60830858_578.ofd");
        // 2. 转换后文件输出位置
        Path dst = Paths.get(src.toAbsolutePath()+"_1.pdf");; // Paths.get("C:/Users/kong/Desktop/ofd/60830858_578.pdf");
        try {
            // 3. OFD转换PDF
            ConvertHelper.toPdf(src, dst);
            System.out.println("生成文档位置: " + dst.toAbsolutePath());
        } catch (GeneralConvertException e) {
            // GeneralConvertException 类型错误表明转换过程中发生异常
            e.printStackTrace();
        }

    }


    /**
     * 按页数转
     * @param input
     * @param output
     */
    public static void ofdtoPic(Path input, Path output) {
        /***********************************************************
         * 转换成图片
         */
//        // 1. 文件输入路径
        Path src =input; // Paths.get("C:/Users/kong/Desktop/ofd/2.ofd");

//        output = Paths.get(src.toAbsolutePath()+"_1.jpeg");
        // 2. 加载指定目录字体(非必须)
        // FontLoader.getInstance().scanFontDir(new File("src/test/resources/fonts"));
        // 3. 创建转换转换对象,设置 每毫米像素数量(Pixels per millimeter)
        try{

            OFDReader reader = new OFDReader(src);
            ImageMaker imageMaker = new ImageMaker(reader, 15);
            for (int i = 0; i < imageMaker.pageSize(); i++) {
                // 4. 指定页码转换图片
                BufferedImage image = imageMaker.makePage(i);
                Path dist = Paths.get(src.getParent().toString(), src.getFileName()+""+i+"-1.jpeg");
                // 5. 存储为指定格式图片
                ImageIO.write(image, "JPEG", dist.toFile());
            }
            System.out.println("ofdtoPic-ok");
        }catch(Exception e){
            e.printStackTrace();
        }finally {

        }

    }

    public static void ofdtoSvg(Path input, Path output) {

        /********************************************************
         * 转换成svg
         */
        // 1. 文件输入路径
        Path src =input; // Paths.get("C:/Users/kong/Desktop/ofd/2.ofd");
//         output = Paths.get(src.toAbsolutePath()+"_1.svg");
        // 2. 加载指定目录字体(非必须)
        // FontLoader.getInstance().scanFontDir(new File("src/test/resources/fonts"));
        // 3. 创建转换转换对象,设置 每毫米像素数量(Pixels per millimeter)
        try{
            OFDReader reader = new OFDReader(src);
            SVGMaker svgMaker = new SVGMaker(reader, 20d);
            for (int i = 0; i < svgMaker.pageSize(); i++) {
                // 4. 指定页码转换SVG,得到SVG(XML)
                String svg = svgMaker.makePage(i);
                Path dist = Paths.get(src.getParent().toString(), src.getFileName()+""+i+"-1.svg");
                // 5. 存储到文件。
                Files.write(dist, svg.getBytes());
            }

            System.out.println("ofdtoSvg-ok");
        }catch(Exception e)
        {
            e.printStackTrace();
        }
    }

    public static void ofdtoHtml(Path input, Path output) {

        /***************************************************************
         * 转换成html
         */
        try {
            // 1. 提供文档
            Path ofdIn =input; // Paths.get("C:/Users/kong/Desktop/ofd/1.ofd");
            Path htmlOut = Paths.get(ofdIn.toAbsolutePath()+"_1.html");
            // 2. [可选]配置字体,别名,扫描目录等
            // FontLoader.getInstance().addAliasMapping(null, "小标宋体", "方正小标宋简体", "方正小标宋简体")
            // FontLoader.getInstance().scanFontDir(new File("src/test/resources/fonts"));
            // 3. 配置参数(HTML页面宽度(px)),转换并存储HTML到文件。
            ConvertHelper.toHtml(ofdIn, htmlOut, 1000);

            System.out.println("ofdtoHtml-ok");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }


	public static void main(String[] args) throws IOException {
       /* Path ofdIn= Paths.get("C:/Users/kong/Desktop/ofd/OFD/1.ofd");

        OFDUtils.ofdtoPdf(ofdIn,Paths.get(""));
        OFDUtils.ofdtoHtml(ofdIn,Paths.get(""));
        OFDUtils.ofdtoPic(ofdIn,Paths.get(""));
        OFDUtils.ofdtoSvg(ofdIn,Paths.get(""));
*/
//        ofdU.vPageLayerTest();
//        ofdU.streamTestParagraphPageSplit();
//        ofdU.OFDRWCanvas();
//        ContentExtractorTest.getPageContent();
//        Path ofdIn= Paths.get("C:/Users/kong/Desktop/ofd/OFD/第三方ofd/60830858_578.ofd");

//        OFDUtils.ofdtoPic(ofdIn,Paths.get(""));
//        new WatermarkTest().addWatermark();//加水印

//        ContentExtractorTest.traverse();

        Path ofdIn= Paths.get("D:\\images\\2023\\05\\29\\rcav0p2M20230188664c3ca705000329\\20230529145734261005860540000001_0.ofd");

//        OFDUtils.ofdtoPdf(ofdIn,Paths.get(""));
//        Path ofdIn= Paths.get("C:\\Users\\kong\\Desktop\\ofd\\2.ofd");
        OFDUtils.ofdtoPic(ofdIn,Paths.get(""));

    }


}

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

  • 10
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
你可以使用第三方库来解析OFD(Open Financial Data)文件。一个常用的Java库是Apache PDFBox,它支持解析和处理PDF文件,而OFD文件可以通过将其转换为PDF格式来解析。 首先,你需要将OFD文件转换为PDF格式。这可以通过使用OFD转换工具来完成,例如OFD Reader(https://github.com/Trisia/ofdReader)。 一旦你将OFD文件转换为PDF格式,你就可以使用Apache PDFBox来解析和提取其中的内容。你可以使用PDFBox的文档对象模型(DOM)来访问文本、图像等元素。 下面是一个简单示例,演示如何使用Apache PDFBox解析PDF文件: ```java import org.apache.pdfbox.pdmodel.PDDocument; import org.apache.pdfbox.text.PDFTextStripper; public class OFDParser { public static void main(String[] args) { try { PDDocument document = PDDocument.load(new File("path/to/your/converted/pdf/file.pdf")); PDFTextStripper stripper = new PDFTextStripper(); String text = stripper.getText(document); System.out.println(text); document.close(); } catch (IOException e) { e.printStackTrace(); } } } ``` 这个示例将打开转换后的PDF文件并提取其中的文本内容。你可以根据需要进一步处理和解析这些内容。 请注意,OFD文件可能包含更复杂的结构和元素,如表格、图形等。你可能需要使用更高级的PDF处理库来处理这些元素,或者自行编写代码来解析OFD文件的结构。 希望这个示例能帮助到你开始解析OFD文件。如果你需要更详细的解析或其他功能,建议查阅相关文档或寻找更专业的OFD处理库。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值