使用Itext操作PDF,修改文本内容及指定位置插入图片

参考博客:修改文本的
参考博客:插入图片的

这里基于修改文本的博客编写的,主要解决了几个问题:
1、文件乱码
2、设置区域背景色
3、设置文字字体颜色
4、插入图片空指针
5、指定位置插入偏移
等等问题

准备工作
1、创建一个或者自己找一个pdf。使用编辑器,编辑PDF(你也可以使用word,然后转PDF),在你期望的位置打上标记,比如我的是:${userName} 这个标记后面会被替换成文本,也是插入图片的相对位置
2、准备一个图片。 再想好操作完PDF后要输出PDF的路径

添加依赖

pom文件添加:

       <dependency>
            <groupId>com.itextpdf</groupId>
            <artifactId>itextpdf</artifactId>
            <version>5.4.3</version>
        </dependency>

        <dependency>
            <groupId>com.itextpdf</groupId>
            <artifactId>itext-asian</artifactId>
            <version>5.2.0</version>
        </dependency>

工具类

我命名为:ItextPDFUtil 。下面代码可直接粘贴


    public static final float defaultHeight = 16;
    public static final float fixHeight = 10;




    /**
     * @description: 查找插入签名图片的最终位置,因为是插入签名图片,所以之前的关键字应只会出现一次
     * 这里直接使用了第一次查找到关键字的位置,并返回该关键字之后的坐标位置
     * @return: float[0]:页码,float[1]:最后一个字的x坐标,float[2]:最后一个字的y坐标
     */
    public static float[] getAddImagePositionXY(String pdfName, String keyword) throws IOException {
        float[] temp = new float[3];
        List<float[]> positions = findKeywordPostions(pdfName, keyword);
        temp[0] = positions.get(0)[0];
        temp[1] = positions.get(0)[1] + positions.get(0)[3];
        temp[2] = positions.get(0)[2] - (positions.get(0)[3] / 2);

        return temp;
    }

    /**
     * findKeywordPostions
     *  返回查找到关键字的首个文字的左上角坐标值
     *
     * @param pdfName
     * @param keyword
     * @return List<float [ ]> : float[0]:pageNum float[1]:x float[2]:y
     * @throws IOException
     */
    public static List<float[]> findKeywordPostions(String pdfName, String keyword) throws IOException {
        File pdfFile = new File(pdfName);
        byte[] pdfData = new byte[(int) pdfFile.length()];
        FileInputStream inputStream = new FileInputStream(pdfFile);
        //从输入流中读取pdfData.length个字节到字节数组中,返回读入缓冲区的总字节数,若到达文件末尾,则返回-1
        inputStream.read(pdfData);
        inputStream.close();

        List<float[]> result = new ArrayList<>();
        List<PdfPageContentPositions> pdfPageContentPositions = getPdfContentPostionsList(pdfData);


        for (PdfPageContentPositions pdfPageContentPosition : pdfPageContentPositions) {
            List<float[]> charPositions = findPositions(keyword, pdfPageContentPosition);
            if (charPositions == null || charPositions.size() < 1) {
                continue;
            }
            result.addAll(charPositions);
        }
        return result;
    }



    /**
     * findKeywordPostions
     *
     * @param pdfData 通过IO流 PDF文件转化的byte数组
     * @param keyword 关键字
     * @return List<float [ ]> : float[0]:pageNum float[1]:x float[2]:y
     * @throws IOException
     */
    public static List<float[]> findKeywordPostions(byte[] pdfData, String keyword) throws IOException {
        List<float[]> result = new ArrayList<float[]>();
        List<PdfPageContentPositions> pdfPageContentPositions = getPdfContentPostionsList(pdfData);


        for (PdfPageContentPositions pdfPageContentPosition : pdfPageContentPositions) {
            List<float[]> charPositions = findPositions(keyword, pdfPageContentPosition);
            if (charPositions == null || charPositions.size() < 1) {
                continue;
            }
            result.addAll(charPositions);
        }
        return result;
    }


    private static List<PdfPageContentPositions> getPdfContentPostionsList(byte[] pdfData) throws IOException {
        PdfReader reader = new PdfReader(pdfData);

        List<PdfPageContentPositions> result = new ArrayList<PdfPageContentPositions>();

        int pages = reader.getNumberOfPages();
        for (int pageNum = 1; pageNum <= pages; pageNum++) {
            float width = reader.getPageSize(pageNum).getWidth();
            float height = reader.getPageSize(pageNum).getHeight();


            PdfRenderListener pdfRenderListener = new PdfRenderListener(pageNum, width, height);


            //解析pdf,定位位置
            PdfContentStreamProcessor processor = new PdfContentStreamProcessor(pdfRenderListener);
            PdfDictionary pageDic = reader.getPageN(pageNum);
            PdfDictionary resourcesDic = pageDic.getAsDict(PdfName.RESOURCES);
            try {
                processor.processContent(ContentByteUtils.getContentBytesForPage(reader, pageNum), resourcesDic);
            } catch (IOException e) {
                reader.close();
                throw e;
            }


            String content = pdfRenderListener.getContent();
            List<CharPosition> charPositions = pdfRenderListener.getcharPositions();


            List<float[]> positionsList = new ArrayList<float[]>();
            for (CharPosition charPosition : charPositions) {
                float[] positions = new float[]{charPosition.getPageNum(), charPosition.getX(), charPosition.getY(), charPosition.getWidth(), charPosition.getHeight()};
                positionsList.add(positions);
            }


            PdfPageContentPositions pdfPageContentPositions = new PdfPageContentPositions();
            pdfPageContentPositions.setContent(content);
            pdfPageContentPositions.setPostions(positionsList);


            result.add(pdfPageContentPositions);
        }
        reader.close();
        return result;
    }


    private static List<float[]> findPositions(String keyword, PdfPageContentPositions pdfPageContentPositions) {


        List<float[]> result = new ArrayList<float[]>();


        String content = pdfPageContentPositions.getContent();
        List<float[]> charPositions = pdfPageContentPositions.getPositions();


        for (int pos = 0; pos < content.length(); ) {
            int positionIndex = content.indexOf(keyword, pos);
            if (positionIndex == -1) {
                break;
            }
            float[] postions = charPositions.get(positionIndex);
            //此处较为关键通过第一个关键字计算出整个关键字的宽度
            for (int i = 1; i < keyword.length(); i++) {
                float[] postionsNew = charPositions.get(positionIndex + i);
                postions[3] = postions[3] + postionsNew[3];
            }
            result.add(postions);
            pos = positionIndex + 1;
        }
        return result;
    }


    private static class PdfPageContentPositions {
        private String content;
        private List<float[]> positions;


        public String getContent() {
            return content;
        }


        public void setContent(String content) {
            this.content = content;
        }


        public List<float[]> getPositions() {
            return positions;
        }


        public void setPostions(List<float[]> positions) {
            this.positions = positions;
        }
    }


    private static class PdfRenderListener implements RenderListener {
        private int pageNum;
        private float pageWidth;
        private float pageHeight;
        private StringBuilder contentBuilder = new StringBuilder();
        private List<CharPosition> charPositions = new ArrayList<CharPosition>();


        public PdfRenderListener(int pageNum, float pageWidth, float pageHeight) {
            this.pageNum = pageNum;
            this.pageWidth = pageWidth;
            this.pageHeight = pageHeight;
        }


        public void beginTextBlock() {
        }


        public void renderText(TextRenderInfo renderInfo) {
            List<TextRenderInfo> characterRenderInfos = renderInfo.getCharacterRenderInfos();
            for (TextRenderInfo textRenderInfo : characterRenderInfos) {
                String word = textRenderInfo.getText();
                if (word.length() > 1) {
                    word = word.substring(word.length() - 1, word.length());
                }
                Rectangle2D.Float rectangle = textRenderInfo.getAscentLine().getBoundingRectange();

                float x = (float) rectangle.getX();
                float y = (float) rectangle.getY();
//                float x = (float)rectangle.getCenterX();
//                float y = (float)rectangle.getCenterY();
//                double x = rectangle.getMinX();
//                double y = rectangle.getMaxY();


                //这两个是关键字在所在页面的XY轴的百分比
                float xPercent = Math.round(x / pageWidth * 10000) / 10000f;
                float yPercent = Math.round((1 - y / pageHeight) * 10000) / 10000f;


//                CharPosition charPosition = new CharPosition(pageNum, xPercent, yPercent);
                CharPosition charPosition = new CharPosition(pageNum, x, y - fixHeight, (float) rectangle.getWidth(), (float) (rectangle.getHeight() == 0 ? defaultHeight : rectangle.getHeight()));
                charPositions.add(charPosition);
                contentBuilder.append(word);
            }
        }


        public void endTextBlock() {
        }


        public void renderImage(ImageRenderInfo renderInfo) {
        }


        public String getContent() {
            return contentBuilder.toString();
        }


        public List<CharPosition> getcharPositions() {
            return charPositions;
        }
    }


    private static class CharPosition {
        private int pageNum = 0;
        private float x = 0;
        private float y = 0;
        private float width;
        private float height;


        public CharPosition(int pageNum, float x, float y, float width, float height) {
            this.pageNum = pageNum;
            this.x = x;
            this.y = y;
            this.width = width;
            this.height = height;
        }


        public int getPageNum() {
            return pageNum;
        }


        public float getX() {
            return x;
        }


        public float getY() {
            return y;
        }

        public float getWidth() {
            return width;
        }

        public float getHeight() {
            return height;
        }

        @Override
        public String toString() {
            return "CharPosition{" +
                    "pageNum=" + pageNum +
                    ", x=" + x +
                    ", y=" + y +
                    ", width=" + width +
                    ", height=" + height +
                    '}';
        }
    }

调用的示例代码

改一下main方法的命名就可以直接测试了

public class ItextPDFUtilDemo {
    //输入的模版路径
    public static String inputFilePath = "C:\\Users\\Administrator\\Desktop\\TEST.pdf";
    //插入的文件路径
    public static String imgFilePath = "C:\\Users\\Administrator\\Desktop\\test图.png";
    //输出路径
    public static String out = "C:\\Users\\Administrator\\Desktop\\3.pdf";
    public static String keyword = "${userName}";//测试标记

   //插入图片的例子
    public static void main(String[] args) throws IOException, DocumentException {
        //查找位置
        float[] position= ItextPDFUtil.getAddImagePositionXY(inputFilePath,keyword);
        //Read file using PdfReader
        PdfReader pdfReader = new PdfReader(inputFilePath);
        System.out.println("x:"+position[1]+" y:"+position[2]);

        //Modify file using PdfReader
        PdfStamper pdfStamper = new PdfStamper(pdfReader, new FileOutputStream(out));

        Image image = Image.getInstance(imgFilePath);
        //Fixed Positioning
//        image.scaleToFit(100, 50);
        image.scaleAbsolute(100, 50);
        //Scale to new height and new width of image
        image.setAbsolutePosition(position[1], position[2]);

        System.out.println("pages:"+pdfReader.getNumberOfPages());

        PdfContentByte content = pdfStamper.getUnderContent((int) position[0]);
        content.addImage(image);
        pdfStamper.close();

    }

    //修改文字的示例
    public static void main1(String[] args) {
        //1.给定文件
        File pdfFile = new File(inputFilePath);
        File imgFile = new File(imgFilePath);

        //2.定义一个byte数组,长度为文件的长度
        byte[] pdfData = new byte[(int) pdfFile.length()];

        //3.IO流读取文件内容到byte数组
        FileInputStream inputStream = null;
        try {
            inputStream = new FileInputStream(pdfFile);
            inputStream.read(pdfData);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (inputStream != null) {
                try {
                    inputStream.close();
                } catch (IOException e) {
                }
            }
        }

        //4.指定关键字


        String replace = " 王文博 先生";

        //5.调用方法,给定关键字和文件
        List<float[]> positions = null;
        try {
            positions = ItextPDFUtil.findKeywordPostions(pdfData, keyword);
        } catch (IOException e) {
            e.printStackTrace();
        }

        PdfReader pdfReader = null;
        PdfStamper stamper = null;
        try {
            pdfReader = new PdfReader(pdfData);
            stamper = new PdfStamper(pdfReader, new FileOutputStream(out));

            if (positions != null) {
                for (int i = 0; i < positions.size(); i++) {
                    float[] position = positions.get(i);

                    PdfContentByte canvas = stamper.getOverContent((int) position[0]);
                    //修改背景色
                    canvas.saveState();
                    BaseColor baseColor = new BaseColor(23,71,158);
//                    canvas.setColorFill(BaseColor.WHITE);
                    canvas.setColorFill(baseColor);
                    // canvas.setColorFill(BaseColor.BLUE);
                    // 以左下点为原点,x轴的值,y轴的值,总宽度,总高度:
//                     canvas.rectangle(mode.getX() - 1, mode.getY(),
//                     mode.getWidth() + 2, mode.getHeight());
                    canvas.rectangle(position[1]-1, position[2]-1, position[3]+1, position[4]+4);

                   /* PdfGState gs = new PdfGState();
                    gs.setFillOpacity(0.3f);// 设置透明度为0.8
                    canvas.setGState(gs);*/

                    canvas.fill();
                    canvas.restoreState();
                    //替换关键字
                   canvas.beginText();

                    BaseFont bf = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED);
                    canvas.setFontAndSize(bf, 13);
                    canvas.setTextMatrix(position[1]+3, position[2]);/*修正背景与文本的相对位置*/
                    //下面两行代码再次设置,设设置的字体的颜色
                    BaseColor baseColor1 = new BaseColor(255,255,255);
                    canvas.setColorFill(baseColor1);

                    canvas.showText(replace);
                    canvas.endText();
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        } catch (DocumentException e) {
            e.printStackTrace();
        } finally {
            if (stamper != null)
                try {
                    stamper.close();
                } catch (DocumentException e) {
                    e.printStackTrace();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            if (pdfReader != null) {
                pdfReader.close();
            }
        }

        //6.返回值类型是  List<float[]> 每个list元素代表一个匹配的位置,分别为 float[0]所在页码  float[1]所在x轴 float[2]所在y轴 float[3]关键字宽度 floatt[4]关键字高度
        System.out.println("total:" + positions.size());
        if (positions != null && positions.size() > 0)

        {
            for (float[] position : positions) {
                System.out.print("pageNum: " + (int) position[0]);
                System.out.print("\tx: " + position[1]);
                System.out.println("\ty: " + position[2]);
                System.out.println("\tw: " + position[3]);
                System.out.println("\th: " + position[4]);
            }
        }
    }

}

你可能感兴趣的:(javaweb,pdf,itext)