java uses itextpdf to generate pdf and populate custom data

Posted by danscreations on Fri, 13 Mar 2020 03:31:50 +0100

There is a requirement in the project to generate invoice pdf or contract pdf for existing data. These PDFs have some features, that is, pdf has a fixed format, similar to a table, we just need to fill the table with data.Of course, signatures, QR codes and other requirements will also be involved.

Overall ideas:
1. Get the initial template of the pdf that needs to be generated, with the format but no data
2. Using the tool Adobe Acrobat, edit the pdf template and generate text fields in the corresponding areas, each with its own name
3. Using itextpdf to operate on pdf in java, the corresponding data is filled into pdf

1. Use Adobe Acrobat to manipulate pdf

(1) First assume we have a pdf template for the invoice (partial screenshot)

(2) Download the Adobe Acrobat tool and edit the pdf
I'm using Adobe Acrobat Pro DC here, open pdf and select Prepare Form in the toolbar

We can clear the default generated text field and right-click to generate the text field size according to our needs, here I generate a gfmc text field, in this text field property you can set the size of the font, the type of font; in the options you can set the text left alignment, in the play, right alignment, line wrapping, and so on.

2. Use itextpdf to manipulate pdf

When we have set up the required text fields for pdf, we need to do a data filling for pdf.The main method code shown here is not the logical code for the entire process.
1. Get the PdfReader object

PdfReader reader = new PdfReader(template);//Template is the relative path of the template pdf file

2. Get the PdfStamper object to read the template pdf and write to a new target file

File deskFile = new File(filePath);//filePath is the file that will be generated
PdfStamper stamp = new PdfStamper(reader, new FileOutputStream(deskFile));

3. Get the text field from the template file and write the data to the new file

AcroFields form = stamp.getAcroFields();
form.setField("gfmc", "This is the name of the buyer");

4. Custom fonts (on demand)
(1) Loading fonts
Where TARGET_COUR_FONT_PATH is the font file path

BaseFont courBf = BaseFont.createFont(TARGET_COUR_FONT_PATH, BaseFont.IDENTITY_H, BaseFont.EMBEDDED);

(2) Assigning values to text fields and setting fonts
Where chunkStr represents text content, size1 font size, size2 line spacing, and property is the text domain name

public static void setFieldAndFont(BaseFont bf, PdfStamper stamp, AcroFields form, String chunkStr, Integer size1, Integer size2, String property) {
        try {
            Font font = new Font(bf, size1,-1,new BaseColor(0,0,0));
            List<AcroFields.FieldPosition> list = form.getFieldPositions(property);

            int page = list.get(0).page;
            PdfContentByte pdfContentByte = stamp.getOverContent(page);
            ColumnText columnText = new ColumnText(pdfContentByte);
            Rectangle rectangle = list.get(0).position;
            columnText.setSimpleColumn(rectangle);
            Chunk chunk = null;
            chunk = new Chunk(chunkStr);
            Paragraph paragraph = new Paragraph(size2, chunk);
            columnText.addText(paragraph);
            paragraph.setFont(font);
            columnText.addElement(paragraph);
            columnText.go();
        } catch (DocumentException e) {
            e.printStackTrace();
        }
    }

5. Add QR code
com.google.zxing is used here

<dependency>
			<groupId>com.google.zxing</groupId>
			<artifactId>core</artifactId>
			<version>3.3.3</version>
		</dependency>
		<dependency>
			<groupId>com.google.zxing</groupId>
			<artifactId>javase</artifactId>
			<version>3.3.3</version>
		</dependency>
public static void invoiceEwm(PdfStamper stamp, String content) throws Exception {
        if(content == null || "".equals(content)){
            return;
        }
        BufferedImage image = createQrCodeBufferdImage(content, 70, 70);

        //PdfGState gs = new PdfGState();
        PdfContentByte waterMar = stamp.getOverContent(1);// Watermark Content
        //waterMar = stamp.getUnderContent(1); //Watermark below content
        // Set Picture Transparency to 0.2f
        //gs.setFillOpacity(0.2f);
        // Set the opacity of the stylus font to 0.4f
        //gs.setStrokeOpacity(0.4f);
        // Begin Watermark Processing
        waterMar.beginText();
        // Set Transparency
        //waterMar.setGState(gs);
        // Setting Watermark Font Parameters and Size
        //waterMar.setFontAndSize(BaseFont.createFont(BaseFont.HELVETICA, BaseFont.WINANSI, BaseFont.NOT_EMBEDDED), 60);
        // Set Watermark Alignment Watermark Content X Coordinate Y Coordinate Rotation Angle
        //waterMar.showTextAligned(Element.ALIGN_CENTER, ""Company internal files, please keep confidential!"", 500, 430, 45";
        // Set Watermark Color
        waterMar.setColorFill(BaseColor.GRAY);
        // Create Watermark Picture
        //com.itextpdf.text.Image itextimage = getImage(image, 99);
        com.itextpdf.text.Image itextimage = com.itextpdf.text.Image.getInstance(image, new Color(128, 128, 128));
        // Watermark Picture Location
        itextimage.setAbsolutePosition(150, 380);
        // Border Fixed 3
        //itextimage.scaleToFit(200, 200);
        // Set Rotation Radius
        //image.setRotation(30);//Rotation Radius
        // Set rotation angle
        //Image.setRotation Degrees(45);//rotation angle
        // Set equal scale
        itextimage.scalePercent(85);
        // custom size
        //itextimage.scaleAbsolute(100, 100);
        // Attachment with Watermark Picture
        waterMar.addImage(itextimage);
        // Complete Watermark Addition
        waterMar.endText();
        // stroke
        waterMar.stroke();
    }
    /**
     * Generate two-dimensional code
     * @author swj
     * @date   2019 June 11, 2001 4:39:16 p.m.
     * @param contents Contents of the two-dimensional code
     * @param width 2D Code Picture Width
     * @param height 2D Code Picture Height
     */
public static BufferedImage createQrCodeBufferdImage(String contents, int width, int height){
        Hashtable hints= new Hashtable();
        hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.L);
        hints.put(EncodeHintType.CHARACTER_SET, "utf-8");
        hints.put(EncodeHintType.MARGIN, 0);
        BufferedImage image = null;
        try {
            BitMatrix bitMatrix = new MultiFormatWriter().encode(
                    contents, BarcodeFormat.QR_CODE, width, height, hints);
            image = toBufferedImage(bitMatrix);
        } catch (WriterException e) {
            e.printStackTrace();
        }
        return image;
    }

6. Add a signature (seal)
Add pictures at specified locations

private static void invoiceDefaultSign(PdfStamper stamper, String filePath, int x, int y) throws Exception {

        Resource resource = new ClassPathResource(filePath);
        byte[] bytes = null;
        bytes = FileUtils.is2ByeteArray(resource.getInputStream());

        // Read pictures
        Image image = Image.getInstance(bytes);
        // Get the page for the action
        PdfContentByte under = stamper.getOverContent(1);
        // Scale pictures by field size
        image.scaleToFit(MAIN_SIGN_WIDTH, MAIN_SIGN_HEIGHT);
        // Add Picture
        image.setAbsolutePosition(x, y);
        under.addImage(image);

    }
/**
	 * Convert to Byte Array via InputStream
	 *
	 * @param is
	 * @return
	 * @throws IOException
	 */
	public static byte[] is2ByeteArray(InputStream is) throws IOException {
		ByteArrayOutputStream baos = new ByteArrayOutputStream();
		byte[] buff = new byte[100];
		int rc = 0;
		while((rc=is.read(buff, 0, 100))>0) {
			baos.write(buff, 0, rc);
		}

		return baos.toByteArray();
	}

7. Close Flow
When you're done, remember to close the stream at the end. It's easy, but it's important

finally {
            if (stamp != null) {
                stamp.close();
            }
            if (reader != null) {
                reader.close();
            }
        }

Write at the end

If the position of the text field of the pdf is required to be higher, it needs to be fine-tuned step by step or tested with patience.When it comes to data security, I don't upload some of the effects.If more than one pdf is generated, a merge operation of the pdf is required, and then the pdf can be uploaded to the company's fastdfs file server as required.

Five original articles were published. 0% praised. 23% visited
Private letter follow

Topics: Google Java