itext7 study notes-Chapter 2

Some basic operations

    The content of the first chapter is to introduce some basic content, and the content of this chapter is some more low-level things. The following chapters will involve operating the content of the existing pdf , I hope everyone will wait patiently.

    When we talk about low-level content in iText documents, we will refer to those PDF syntaxes written into the official PDF documents. A series of operations defined by PDF are corresponding in iText, such as moperation corresponding moveTo()method, loperation corresponding lineTo()method, Soperation corresponding stroke()method and so on. Through these methods, we can draw paths and shapes.

    Let's look at this simple example:

-406 0 m
406 0 l
S

    The meaning of this grammar in pdf is:

  1. Move to coordinates (-406,0)
  2. Then draw a line from (-406,0) to (406,0) to form a path
  3. Finally draw this line, stroke() corresponds to drawing the path

    This paragraph corresponds to the operation in iText like this:

canvas.moveTo(-406, 0)
            .lineTo(406, 0)
            .stroke();

    It looks simple at first glance, but canvaswhat is this object? Let us find the answer through a few examples.

Draw coordinate system in pdf

Draw lines on the canvas

    Suppose we want to create the pdf as shown in Figure 1:

itext-2-1

Figure 1. Draw an X and Y axis

    This example draws the X and Y coordinate systems on the pdf. Let us explain the process step by step:

PdfDocument pdf = new PdfDocument(new PdfWriter(dest));
PageSize ps = PageSize.A4.rotate();
PdfPage page = pdf.addNewPage(ps);
PdfCanvas canvas = new PdfCanvas(page);
// Draw the axes画出坐标系
pdf.close();
  • We no longer use Documentthis object
  • As mentioned in the previous chapter, we created the PdfWriterand PdfDocumentobject.
  • We did not create the same page size as before the default Documentobject, but creates particular PageSizeofPdfPage
  • The page is A4 size, after rotating it becomes landscape
  • After creation PdfPage, we use it to createPdfCanvas
  • In PdfCanvasa series of operations to complete the painting of our coordinate system
  • Finally, we want to add what we have drawn to the page, just close the PdfDocumentobject

In the previous chapters, we used the document.close()close Documentobject, this operation actually closed the PdfDocumentobject secretly . Now there are no more Documentobjects here , so we have to close it manuallyPdfDocument

    In PDF, all measurements are done in user units. By default, one user unit corresponds to one point. This means that there are 72 user units in one inch. In the PDF, the X axis points to the right and the Y axis points up. If you use PageSizeobjects to create the page size, the origin of the coordinate system is at the lower left corner of the page. All coordinates we use as operands of operators (such as m or l operations) use this coordinate system. We can change the coordinate system by changing the current transformation matrix.

Coordinate system and change matrix

    If you have taken geometry related courses, then you should know that we can act on objects through a change matrix, which can be translated, rotated, zoomed, etc. Suppose we want to move the coordinate system so that the origin of the coordinate system is in the middle of the page. In this case, concatMatrix()the parameters we need to use method are:

canvas.concatMatrix(1, 0, 0, 1, ps.getWidth() / 2, ps.getHeight() / 2);

    concatMatrix()The parameter of the method is a 3*3 transformation matrix:

a   b   0
c   d   0
e   f   1

    Here, the third row of this matrix is ​​a fixed value: (0,0,1). The reason for this is because we are operating in two dimensions. However a, the values ​​of b, cand dcan be used here to rotate, scale and translate the coordinate system. Of course, we do not need to be specified x-axis horizontal, y-axis perpendicular to the vertical, but we the sake of simplicity, we'll just requirement, and thus the provisions of a, b, cand dthe value of 1, 0, 0and 1. eAnd fdefine the translation distance, here we translate the size into ps1/2 of the written test height and width

The graphics state

    The previous section mentioned that the change matrix is ​​one Pageof the image states, as well as states such as line width, line color, and fill color. In the following chapters, we will explore some other image states in more depth. Here we only need to know: the default line width is 1 user unit and the default line color is black. The following code is the process of drawing the above picture:

//1.Draw X axis
canvas.moveTo(-(ps.getWidth() / 2 - 15), 0)
        .lineTo(ps.getWidth() / 2 - 15, 0)
        .stroke();
//2.Draw X axis arrow
canvas.setLineJoinStyle(PdfCanvasConstants.LineJoinStyle.ROUND)
        .moveTo(ps.getWidth() / 2 - 25, -10)
        .lineTo(ps.getWidth() / 2 - 15, 0)
        .lineTo(ps.getWidth() / 2 - 25, 10).stroke()
        .setLineJoinStyle(PdfCanvasConstants.LineJoinStyle.MITER);
//3.Draw Y axis
canvas.moveTo(0, -(ps.getHeight() / 2 - 15))
        .lineTo(0, ps.getHeight() / 2 - 15)
        .stroke();
//4.Draw Y axis arrow
canvas.saveState()
        .setLineJoinStyle(PdfCanvasConstants.LineJoinStyle.ROUND)
        .moveTo(-10, ps.getHeight() / 2 - 25)
        .lineTo(0, ps.getHeight() / 2 - 15)
        .lineTo(10, ps.getHeight() / 2 - 25).stroke()
        .restoreState();
//5.Draw X serif
for (int i = -((int) ps.getWidth() / 2 - 61);
    i < ((int) ps.getWidth() / 2 - 60); i += 40) {
    canvas.moveTo(i, 5).lineTo(i, -5);
}
//6.Draw Y serif
for (int j = -((int) ps.getHeight() / 2 - 57);
    j < ((int) ps.getHeight() / 2 - 56); j += 40) {
    canvas.moveTo(5, j).lineTo(-5, j);
}
canvas.stroke();

    This code can be divided into the following parts:

  • You should be familiar with the code of 1 and 3, which is to draw the x and y axis
  • The second paragraph of code is an arrow, that is, two lines are connected together. There are many styles of intersection: 1) Miter, two lines meet at one point 2) Miter, the corner is mitered 3) Round, the corner is round We construct the path by calling the function once moveToand twice lineTo, and finally we Reset the style of the intersection to the default value, so that it will not affect some operations later, but this is not the best way to restore the previous image state
  • The 4th code shows us a better way of operation if we want to change the image state: 1) We use saveState()methods to save the current image state 2) Then change the image state, draw lines or other arbitrary shapes 3) Finally we use the restoreState()method To restore the original image state, all saveState()subsequent operations that change the image state will be undone. This will be very effective when you perform many operations that change the image state.
  • In the 5th and 6th code, we draw a separator for each 40 user units. It is worth noting that we did not call the stroke()function immediately , but after all the paths are drawn, we call the function to draw.

    Of course, there is more than one way to draw lines and shapes on the canvas. Considering the speed of pdf generation, the size of the generated file, and the speed of rendering in the view, it is difficult for us to discuss whether the above method is good or bad. It will be discussed in later chapters.

Note here that saveState()and restoreState()must appear in pairs, and restoreState()not beforesavaState()

Add grid lines

    Now we are based on the previous picture, change the width of the line, add a dashed line, and add grid lines of different colors to form the following Figure 2:

Figure 2. Draw the grid

    In this example, we first define a series of Colorobjects:

Color grayColor = new DeviceCmyk(0.f, 0.f, 0.f, 0.875f);
Color greenColor = new DeviceCmyk(1.f, 0.f, 1.f, 0.176f);
Color blueColor = new DeviceCmyk(1.f, 0.156f, 0.f, 0.118f);

    In the official PDF document (ISO-32000), a lot of color spaces are defined. Different color spaces correspond to different in iText class. The most commonly used color space is DeviceGray(gray space, only one brightness parameter), DeviceRgb(RGB Space is determined by red, green and blue) and DeviceCmyk(printing four-color space, consisting of cyan, magenta, yellow and black). In this example, we are using DeviceCmykspace.

Note that we are not using java.awt.Colorcustom colors, but Colorclasses from iText , which can be found in the com.itextpdf.kernel.colorpackage.

    If we want to draw blue grid lines, we can use the following code:

canvas.setLineWidth(0.5f).setStrokeColor(blueColor);
for (int i = -((int) ps.getHeight() / 2 - 57);
    i < ((int) ps.getHeight() / 2 - 56); i += 40) {
    canvas.moveTo(-(ps.getWidth() / 2 - 15), i)
            .lineTo(ps.getWidth() / 2 - 15, i);
}
for (int j = -((int) ps.getWidth() / 2 - 61);
    j < ((int) ps.getWidth() / 2 - 60); j += 40) {
    canvas.moveTo(j, -(ps.getHeight() / 2 - 15))
            .lineTo(j, ps.getHeight() / 2 - 15);
}
canvas.stroke();

    At the beginning, we set the width of the line to 0.5 user units, the next step is to draw the route, and finally call the stroke()function.
    When drawing coordinates, we only use the previous method to draw, but before drawing, we change the line width and brush color.

canvas.setLineWidth(3).setStrokeColor(grayColor);

    After drawing the coordinate system, we use 2 user widths to draw the dotted line:

canvas.setLineWidth(2).setStrokeColor(greenColor)
        .setLineDash(10, 10, 8)
        .moveTo(-(ps.getWidth() / 2 - 15), -(ps.getHeight() / 2 - 15))
        .lineTo(ps.getWidth() / 2 - 15, ps.getHeight() / 2 - 15).stroke();

    There can be many variables to define a dashed line (line dash), but in this example, we only need three variables. The length of the dash is 10 user units, and the gap between the solid lines is 10 user units. , The phase (phase) is 8 user units (phase is the beginning of the solid line defined in the solid line module? This translation is not particularly clear. Original: the phase is 8 user units —the phase defines the distance in the dash pattern to start the dash.)

We can try PdfCanvasother methods in, for example, curveTo()functions are used to draw curves, rectangle()methods are used to draw rectangles, and there are some other methods. In addition to using strokemethods to draw lines, we can also use fill()methods to fill paths. PdfCanvasThe class provides far more methods than the Java version of the PDF manipulator, and also provides methods to construct paths that are not in PDF, such as ellipse and circle

    In the next section, we will discuss the part of the image state that can change the absolute position of the text.

Text status

    Figure 3 below shows the beginning text of the Star Wars 5 Empire Strikes Back:

itext2-3

Figure 3. Add text in absolute position

    If you want to create such a pdf, the best way is to create Paragraphobjects with different alignments , center the subject and align the content to the left, and then add the Paragraphobjects to Documentit. In the advanced api (high-level approach), continuous text is divided into many segments. When the text length exceeds the page width, a line break will be introduced, and when the text content exceeds the page height, the page will be changed.
    Of course we have a simpler way, using a low-level approach, we just need to break the text into several pieces:

List<String> text = new ArrayList();
text.add("         Episode V         ");
text.add("  THE EMPIRE STRIKES BACK  ");
text.add("It is a dark time for the");
text.add("Rebellion. Although the Death");
text.add("Star has been destroyed,");
text.add("Imperial troops have driven the");
text.add("Rebel forces from their hidden");
text.add("base and pursued them across");
text.add("the galaxy.");
text.add("Evading the dreaded Imperial");
text.add("Starfleet, a group of freedom");
text.add("fighters led by Luke Skywalker");
text.add("has established a new secret");
text.add("base on the remote ice world");
text.add("of Hoth...");

    For the sake of simplicity, we put the original coordinate system in the lower left corner to the upper left corner, and then we use beginText()methods to create text objects and change the state of the text:

canvas.concatMatrix(1, 0, 0, 1, 0, ps.getHeight());
canvas.beginText()
    .setFontAndSize(PdfFontFactory.createFont(FontConstants.COURIER_BOLD), 14)
    .setLeading(14 * 1.2f)
    .moveText(70, -40);
  • We change the text status to monospace bold and change the font size to 14, so that the fonts in the future will be in this format
  • The spacing is 1.2 times the font size
  • Finally, we move 70 user units to the right and 40 user units down, which is (70,-40) and start displaying text

    Immediately after that, we traverse the strings in the text array one by one, each string starts on another line, keeping the above spacing, and finally the endText()method ends.

for (String s : text) {
    //Add text and move to the next line
    canvas.newlineShowText(s);
}
canvas.endText();

Note: Our use newlineShowText()must be between beginText()and endText(), and the order between beginText()—" endText()cannot be disrupted

Cool text

    First look at the effect of Figure 4 below:

itext-2-4

Figure 4. Adding skewed and colored text in absolute position

    Isn’t it cool? It's actually very simple, let's go step by step:

canvas.rectangle(0, 0, ps.getWidth(), ps.getHeight())
        .setColor(Color.BLACK, true)
        .fill();

    We first create a rectangle, the coordinates of the bottom left corner of the rectangle are (0,0), the width and height are the width and height of the page, and then we set the fill color to black, of course we can use setFillColor(Color.BLACK)to set the fill color, but here we use A more general setColor()approach. setColor()The second parameter is whether to change the fill color, and finally we fill the rectangle and it is OK, and then the text part:

canvas.concatMatrix(1, 0, 0, 1, 0, ps.getHeight());
Color yellowColor = new DeviceCmyk(0.f, 0.0537f, 0.769f, 0.051f);
float lineHeight = 5;
float yOffset = -40;
canvas.beginText()
    .setFontAndSize(PdfFontFactory.createFont(FontConstants.COURIER_BOLD), 1)
    .setColor(yellowColor, true);
for (int j = 0; j < text.size(); j++) {
    String line = text.get(j);
    float xOffset = ps.getWidth() / 2 - 45 - 8 * j;
    float fontSizeCoeff = 6 + j;
    float lineSpacing = (lineHeight + j) * j / 1.5f;
    int stringWidth = line.length();
    for (int i = 0; i < stringWidth; i++) {
        float angle = (maxStringWidth / 2 - i) / 2f;
        float charXOffset = (4 + (float) j / 2) * i;
        canvas.setTextMatrix(fontSizeCoeff, 0,
                angle, fontSizeCoeff / 1.5f,
                xOffset + charXOffset, yOffset - lineSpacing)
            .showText(String.valueOf(line.charAt(i)));
    }
}
canvas.endText();

    As before, we put the coordinate system in the upper left corner again, and defined the yellow color using Cmyk space, defined the line spacing and the starting position of the y-axis, and then started adding text, we used monospace bold and defined the font size for the user unit 1, although only one user unit, but we will later amplified by matrix text as text, which we do not use the setLeading()set line spacing, because we are not using newlineShowText()the method. We set the text color, and then display the text one by one instead of drawing the entire line before.

The image of each character is defined as a drawn path in the font. By default, the path of these characters is filled. This is why we can change the font color by setting the color of fill.

    We start to loop the text, reading each line into a String. We need a series of mathematical variables to define the different elements of the text matrix that will be used to locate each glyph: We define a xOffsetvariable for each line to determine the start of the text in the current line At the beginning, the font size is defined as 1 user unit, but we fontSizeCoeffmultiply it by one , which depends on the index of the line in the text array. Colleagues, we will also define yOffset to determine the starting position of each line.
    Count the number of characters in each line, and then loop through all the characters. We define an angle variable according to the position of the character in the line, and the charOffset variable depends on the index of the line and the position of the character.
    Finally, the transformation matrix of the text is set, aand dthe zoom ratio cis defined . The parameters define the degree of inclination. Then the coordinates of the characters are calculated to define eand fparameters. After the position of each character is determined, the showText()function is used to display the characters. This method does not start a new line to display the characters, we start a new line by looping, and finally use it endext()to close the text object

This example is very complicated, but we can see from this example that we can create any content, as long as it can be done in PDF, so can iText. But rest assured, future examples will be easier to understand

to sum up

    In this chapter, we have been trying various operations in PDF and corresponding operations in iText. We have learned a concept called graphics state, which has the current transformation matrix, line width, color and other attributes. The text state is a subset of the graphic state that covers all the attributes related to the text, such as the text matrix, the font and size of the text, and many other attributes that we have not discussed yet. We will cover it in detail in another tutorial. You may be wondering why developers need to access low-level APIs instead of using the many high-level features of iText. This question will be answered in the next chapter.

Guess you like

Origin blog.csdn.net/u012397189/article/details/76726576
Recommended