- Perl ›
- Form creation ›
- here
Drawing basic figures and creating tables - PDF::Create forms with API2
I will explain how to create a table with PDF::API2.
PDF::API2 has the ability to create straight lines, fillable circles, triangles, rectangles and even more polygons.
If you can draw straight lines, you can combine them to create a table. If you want to set the background color for the table, you can do it by drawing a fillable rectangle.
HTML tables can be used to create tables. Here, let's make it possible to express the following structure as a PDF table.
<table> <tr> <td> Heading 1 </td> <td> Heading 2 </td> <td> Heading 3 </td> </tr> <tr> <td> Item </td> <td> Item </td> <td> Item </td> </tr> <tr> <td> Item </td> <td> Item </td> <td> Item </td> </tr> </table>
Heading 1 | Heading 2 | Heading 3 |
Item | Item | Item |
Item | Item | Item |
Draw basic shapes
First of all, let's draw a basic shape with PDF::API2 as a basis for creating a table.
Generate content object for graphics
First of all, create a content object for the graphic. You can create a content object for graphics by calling the gfx method from the page object. This is a PDF::API2::Content object.
# Generate PDF object my $pdf = PDF::API2->new; # Create page my $page = $pdf->page; # Generate content objects for graphics my $gfx = $page->gfx;
Draw a line
As the most basic drawing, let's draw a line with PDF::API2.
The move method creates a new path and moves you to the starting point. Use the line method to move the path to the end point.
No lines are actually drawn yet. To actually draw the line, call the stroke method.
# Setting the start point of the line my $start_x = 100; my $start_y = 100; $gfx->move($start_x, $start_y); # Set the end point of the line my $end_x = 300; my $end_y = 300; $gfx->line($end_x, $end_y); # Draw a line $gfx->stroke;
When drawing figures in PDF::API2, remember the feeling of connecting paths and drawing.
Set line thickness
The line thickness can be set with the linewidth method. Call it before you stroke.
# Line thickness setting $gfx->linewidth(3);
The line width is the same for the settings when drawing circles and polygons.
Set line color
The line color can be set with the strokecolor method. Call it before you stroke. The color can be specified by color name, RGB, or CMYK. Each color can have a 1-byte, 2-byte, 3-byte, or 4-byte value. For example, cyan can be set as%F000 or%FFFF000000000000.
# Set the line color (color name) $gfx->strokecolor('red'); # Set line color (RGB) $gfx->strokecolor('# 0123ab'); # Set line color (CMYK) $gfx->strokecolor('%FF000000');
The line color is the same for the settings when drawing circles and polygons.
The color format is the same for the fill color settings.
Draw a triangle surrounded by a line
As an application of drawing a line, let's draw a triangle surrounded by a line. The line method connects the points and finally returns to the starting point.
use strict; use warnings; use utf8; use PDF::API2; # Generate PDF object my $pdf = PDF::API2->new; my $page = $pdf->page; my $gfx = $page->gfx; # Point P1 my $x1 = 100; my $y1 = 100; $gfx->move($x1, $y1); # Point P2 my $x2 = 300; my $y2 = 300; $gfx->line($x2, $y2); # Point P3 my $x3 = 500; my $y3 = 100; $gfx->line($x3, $y3); # Return to point P1 $gfx->line($x1, $y1); # Draw a line $gfx->stroke; my $pdf_file = 'render_tri.pdf'; $pdf->saveas($pdf_file);
You can use the poly method to set points to move and pass multiple points to draw a continuous line.
use strict; use warnings; use utf8; use PDF::API2; # Generate PDF object my $pdf = PDF::API2->new; my $page = $pdf->page; my $gfx = $page->gfx; # Point P1 my ($x1, $y1) = (100, 100); # Point P2 my ($x2, $y2) = (300, 300); # Point P3 my ($x3, $y3) = (500, 100); # Draw triangles at once with poly method $gfx->poly($x1, $y1, $x2, $y2, $x3, $y3, $x1, $y1); # Draw a line $gfx->stroke; my $pdf_file = 'render_tri.pdf'; $pdf->saveas($pdf_file);
Fill
You can fill it by enclosing it in a path. Use the fill method to fill. The default fill color is black. Note that fill must be called before the stroke.
# Fill (before stroke) $gfx->fill; # Draw a line $gfx->stroke;
There is also a fillstroke method that fills and draws lines at the same time.
# Fill and draw a line $gfx->fillstroke;
Set the fill color
The fill color can be set with the fillcolor method. Call it before filling. The color can be specified by color name, RGB, or CMYK. Each color can have a 1-byte, 2-byte, 3-byte, or 4-byte value. For example, cyan can be set as%F000 or%FFFF000000000000.
# Set the fill color (color name) $gfx->fillcolor('red'); # Set fill color (RGB) $gfx->fillcolor('# 0123ab'); # Set fill color (CMYK) $gfx->fillcolor('%FF000000');
Draw a rectangle
PDF::API2 has a convenient method for drawing rectangles. All shapes can be created by connecting lines using the above method, but since there are many steps to connect lines, a method for drawing basic shapes such as rectangles is prepared.
Let's create a rectangle and fill the background with a light gray color. There are rect method and rectxy method to draw a rectangle, but let's use rectxy which can draw a rectangle just by specifying the start point and the point opposite the diagonal line.
use strict; use warnings; use utf8; use PDF::API2; # Generate PDF object my $pdf = PDF::API2->new; # Create page my $page = $pdf->page; # Generate content objects for graphics my $gfx = $page->gfx; # Point P1 my $x1 = 100; my $y1 = 100; # Diagonal point opposite P3 my $x3 = 300; my $y3 = 300; # Draw a rectangle $gfx->rectxy($x1, $y1, $x3, $y3); # Make the line color a little lighter than black $gfx->strokecolor('# 333'); # Make the background color very light gray $gfx->fillcolor('# eee'); # Fill the rectangle and draw a line $gfx->fillstroke; my $pdf_file = 'basic_rect.pdf'; $pdf->saveas($pdf_file);
This is an example that can draw a rectangle that can be executed as it is.
Write other basic figures
I will introduce which method to use when you want to write other basic figures.
Write a circle
If you want to draw a circle, use the circle method. It can be used for bullet points in the list.
Draw an ellipse
If you want to draw an ellipse, use the ellipse method.
Write a fan shape
If you want to draw a sector, use the pie method.
Draw an arc
If you want to draw an arc, use the arc or bogen method. The bogen method can be used for rounded corners because you can specify the start and end points of the arc.
Draw an elliptical arc
If you want to draw an elliptical arc, use the bogen method.
Write a curve (Peget curve)
To draw a curve (Peget curve), use the curve method. You can draw a curve by the Peje curve algorithm.
Write a curve (spline curve)
To draw a curve (spline curve), use the spline method. You can draw a curve that connects points smoothly.
Draw a polygon
Use the poly method to draw a polygon. You can draw triangles, pentagons, hexagons, etc.
Rotate the shape
Use the rotate method to rotate the shape.
Enlarge/reduce the figure
Use the scale method to scale the shape.
To draw a horizontal line
There is a hline method that allows you to easily draw a horizontal line.
To draw a vertical line
There is a vline method that allows you to easily draw vertical lines.
To draw a dashed line
To draw a wavy line, use the linedash method.
Create a table
Now let's create a table.
The idea of the table is that there is a frame on the outermost side. There is also a frame for each item. If you can overlap the item frame and the outer frame, the table is complete. It seems that you can draw by combining the rectangles and overlapping the outside.
However, a problem with this method was discovered. If you draw twice at the same position, the lines will become darker.
So, let's create a table by simply drawing lines vertically and horizontally.
use PDF::API2; # Generate PDF object my $pdf = PDF::API2->new; # Default global setting for paper size (to get paper size) $pdf->mediabox(undef); # Page height and width my @page_size_infos = $pdf->mediabox; my $page_width = $page_size_infos[2]; my $page_height = $page_size_infos[3]; # Item height my $item_height = 25; # Number of rows my $rows_count = 20; # Width of each item my $name_width = 230; my $unit_price_width = 80; my $count_width = 80; my $price_width = 80; my $table_width = $name_width + $unit_price_width + $count_width + $price_width; # Table height my $table_height = $item_height * $rows_count; # Starting point of the table # Table outer frame my $table_start_x = 50; my $table_start_y = $page_height - 50; my $table_other_side_x = $table_start_x + $table_width; my $table_other_side_y = $table_start_y-$table_height; # Create page my $page = $pdf->page; # Generate content objects for graphics my $gfx = $page->gfx; # Draw the upper line $gfx->move($table_start_x, $table_start_y); $gfx->line($table_start_x + $table_width, $table_start_y); # Draw the line on the left $gfx->move($table_start_x, $table_start_y); $gfx->line($table_start_x, $table_start_y-$table_height); my $cur_x = $table_start_x; my $cur_y = $table_start_y; # Drawing the frame of each item for (my $column = 0; $column < $rows_count; $column ++) { # Name frame (right and bottom) $gfx->move($cur_x + $name_width, $cur_y); $gfx->line($cur_x + $name_width, $cur_y-$item_height); $gfx->move($cur_x, $cur_y-$item_height); $gfx->line($cur_x + $name_width, $cur_y-$item_height); $cur_x += $name_width; # Unit price frame (right and bottom) $gfx->move($cur_x + $unit_price_width, $cur_y); $gfx->line($cur_x + $unit_price_width, $cur_y-$item_height); $gfx->move($cur_x, $cur_y-$item_height); $gfx->line($cur_x + $unit_price_width, $cur_y-$item_height); $cur_x += $unit_price_width; # Quantity frame (right and bottom) $gfx->move($cur_x + $count_width, $cur_y); $gfx->line($cur_x + $count_width, $cur_y-$item_height); $gfx->move($cur_x, $cur_y-$item_height); $gfx->line($cur_x + $count_width, $cur_y-$item_height); $cur_x += $count_width; # Price frame (right and bottom) $gfx->move($cur_x + $price_width, $cur_y); $gfx->line($cur_x + $price_width, $cur_y-$item_height); $gfx->move($cur_x, $cur_y-$item_height); $gfx->line($cur_x + $price_width, $cur_y-$item_height); $cur_x += $price_width; # To the next line $cur_x = $table_start_x; $cur_y-= $item_height; } # Make the line color a little lighter than black $gfx->strokecolor('# 333'); # Fill the rectangle and draw a line $gfx->stroke; my $pdf_file = 'table.pdf'; $pdf->saveas($pdf_file);
You have completed a table with no information.
Example table with headings and items
Finally, let's create an example table with headings and items.
The following table will be exported to PDF.
Name | Unit | Count | Price |
---|---|---|---|
Book1 | 1000 | 3 | 3000 |
Book2 | 2000 | 6 | 12000 |
Book3 | 1500 | 5 | 7500 |
use strict; use warnings; use utf8; use PDF::API2; # Generate PDF object my $pdf = PDF::API2->new; # Default global setting for paper size (to get paper size) $pdf->mediabox(undef); # Page height and width my @page_size_infos = $pdf->mediabox; my $page_width = $page_size_infos[2]; my $page_height = $page_size_infos[3]; # Item height my $item_height = 25; # Number of rows my $rows_count = 20; # Width of each item my $name_width = 230; my $unit_price_width = 80; my $count_width = 80; my $price_width = 80; my $table_width = $name_width + $unit_price_width + $count_width + $price_width; # Table height my $table_height = $item_height * $rows_count; # Starting point of the table # Table outer frame my $table_start_x = 50; my $table_start_y = $page_height - 50; my $table_other_side_x = $table_start_x + $table_width; my $table_other_side_y = $table_start_y-$table_height; # Create page my $page = $pdf->page; # Generate content objects for graphics my $gfx = $page->gfx; # Generate content object for text my $text = $page->text; my $font = $pdf->corefont('Helvetica'); my $font_bold = $pdf->corefont('Helvetica-Bold'); my $font_size = 11; $text->font($font, $font_size); my $text_height = $font_size; my $books = [ { name =>'Book1', unit_price => 1000, count => 3, }, { name =>'Book2', unit_price => 2000, count => 6, }, { name =>'Book3', unit_price => 1500, count => 5, } ];; my $books_length = @$books; # Draw the upper line $gfx->move($table_start_x, $table_start_y); $gfx->line($table_start_x + $table_width, $table_start_y); # Draw the line on the left $gfx->move($table_start_x, $table_start_y); $gfx->line($table_start_x, $table_start_y-$table_height); my $cur_x = $table_start_x; my $cur_y = $table_start_y; my $item_padding_top = 17; my $item_padding_left = 5; # Drawing the frame of each item for (my $column = 0; $column < $rows_count; $column ++) { my $book_index = $column - 1; # Name frame (right and bottom) # Heading $text->translate($cur_x + $item_padding_left, $cur_y-$item_padding_top); if ($column == 0) { $text->font($font_bold, $font_size); $text->text('Name'); } # Item else { $text->font($font, $font_size); if ($book_index < $books_length) { $text->text($books->[$book_index]{name}); } } $gfx->move($cur_x + $name_width, $cur_y); $gfx->line($cur_x + $name_width, $cur_y-$item_height); $gfx->move($cur_x, $cur_y-$item_height); $gfx->line($cur_x + $name_width, $cur_y-$item_height); $cur_x += $name_width; # Unit price frame (right and bottom) $text->translate($cur_x + $item_padding_left, $cur_y-$item_padding_top); if ($column == 0) { $text->font($font_bold, $font_size); $text->text('Unit'); } # Item else { $text->font($font, $font_size); if ($book_index < $books_length) { $text->text($books->[$book_index]{unit_price}); } } $gfx->move($cur_x + $unit_price_width, $cur_y); $gfx->line($cur_x + $unit_price_width, $cur_y-$item_height); $gfx->move($cur_x, $cur_y-$item_height); $gfx->line($cur_x + $unit_price_width, $cur_y-$item_height); $cur_x += $unit_price_width; # Quantity frame (right and bottom) # Heading $text->translate($cur_x + $item_padding_left, $cur_y-$item_padding_top); if ($column == 0) { $text->font($font_bold, $font_size); $text->text('Count'); } # Item else { $text->font($font, $font_size); if ($book_index < $books_length) { $text->text($books->[$book_index]{count}); } } $gfx->move($cur_x + $count_width, $cur_y); $gfx->line($cur_x + $count_width, $cur_y-$item_height); $gfx->move($cur_x, $cur_y-$item_height); $gfx->line($cur_x + $count_width, $cur_y-$item_height); $cur_x += $count_width; # Price frame (right and bottom) # Heading $text->translate($cur_x + $item_padding_left, $cur_y-$item_padding_top); if ($column == 0) { $text->font($font_bold, $font_size); $text->text('Pirce'); } # Item else { $text->font($font, $font_size); if ($book_index < $books_length) { $text->text($books->[$book_index]{unit_price} * $books->[$book_index]{count}); } } $gfx->move($cur_x + $price_width, $cur_y); $gfx->line($cur_x + $price_width, $cur_y-$item_height); $gfx->move($cur_x, $cur_y-$item_height); $gfx->line($cur_x + $price_width, $cur_y-$item_height); $cur_x += $price_width; # To the next line $cur_x = $table_start_x; $cur_y-= $item_height; } # Make the line color a little lighter than black $gfx->strokecolor('# 333'); # Fill the rectangle and draw a line $gfx->stroke; my $pdf_file = 'table_items.pdf'; $pdf->saveas($pdf_file);