Creating PDF documents using jsPDF

introduce

In the last article Use the PDF.js library to display in PDF files, We showed how to display PDF files on an HTML canvas. In this article, we will show how to create PDF files from scratch. We will use jsPDF The library for this purpose. You can only GitHub repository Download the latest library version or download it from Official website .   Unfortunately, the library is poorly documented, so we'll describe the most important API s.

precondition

We must download the latest version of the library and include it at the end of the HEAD or BODY section.

<head>
    <script src="js/jspdf.js"></script>
</head>
<body>
    <!-- Your code goes here -->
    
    <script src="js/jspdf.js"></script>
    <script src="js/main.js"></script>
</body>

After that, we can start using the jsPDF library.

Example application

We will use the sample application included with this article to describe the process of generating PDF documents. We will use examples and discuss all the methods used.

The sample application contains only a few buttons, and clicking each button generates a different PDF file. We created some auxiliary methods to handle the process of responding to user actions and saving files on the device. Let's check.

First, we attach one for each button   saveExample function. This function is called when the button is clicked. This function takes the example number as the unique parameter.

var examples = document.querySelectorAll('button');
Array.prototype.forEach.call(examples, function(example) {
    example.addEventListener('click', function() {
        saveExample(parseInt(example.dataset.example, 10));
    });
});

Inside the function, we check that the example number has the correct value and ask the user to name the file.

var saveExample = function(example) {
    if (example < 1 || example > 5) return;

    var fileName = prompt('How to name the example PDF file?');
    if (!fileName || fileName.length === 0) return;

    if (fileName.substr(-4, 4).toLowerCase() !== '.pdf') {
        fileName += '.pdf';
    }

    tizen.filesystem.resolve('documents', function(dir) {
        var file = dir.createFile(fileName);
        file.openStream('w', function(stream) {
            getExampleOutput(example, function(output) {
                var chunk = 16384;
                for (var beg = 0; beg < output.length; beg += chunk) {
                    stream.writeBytes(Array.apply(null, output.subarray(beg, beg + chunk)));
                }
                stream.close();
            });
        }, errorHandler);
    }, errorHandler);
};

If the user forgets to pass the file name or clicks cancel, we stop the function. If the file name does not contain  . pdf suffix, we will add it. Next, we use the Tizen file system API to access   Document directory, create a file, and populate it with data. To use the file system API, you must add Tizen Privilege | Tizen and Tizen Privilege | Tizen jurisdiction.

We use the tizen.filesystem.resolve method to resolve   directory  , And pass the document string as the first parameter  . The second parameter is a callback function, which will be executed when the process of parsing the directory is completed. As the first parameter of the callback function, we get a pointer to the document folder   Directory object  . Now we can create a file using the dir.createFile() method  . The only parameter we need to pass in is the file name. It returns an object pointing to the file just created.

Now we have to fill our file with data. We use file.openStream to open a stream for this  . The stream will be used to write data, so the first parameter is   "w" string. The second parameter is a callback function that will be executed after the stream is opened. The only argument to the callback function is   Stream object. Now we can save some data using the write method of the stream object  . When we finish saving the data, we must close the stream using the stream.close() method  .

Now only one element is missing. How to get PDF file data?

var getExampleOutput = function(example, callback) {
    var pdfDoc = new jsPDF();

    switch (example) {
        case 1:
            callback(new Uint8Array(pdfDoc.output('arraybuffer')));
            break;
        case 2:
            break;
        case 3:
            break;
        case 4:
            break;
        case 5:
            break;
    }
};

As you can see, we use   getExampleOutput function to get the data of PDF file. We pass an example number as the first argument. The getExampleOutput function is that all our work with generating PDF files has been completed. Now, it's worth mentioning that PDF objects created using the jsPDF library have one that doesn't work in Tizen   Save the method because it uses the A tag that has not been implemented in Tizen   Download properties  . Therefore, we must get A pure PDF file data (from ArrayBuffer to uint8 array view) and save it ourselves. To get the output of ArrayBuffer, we pass the "ArrayBuffer" string as the first parameter   pdfDoc.output method. Later, we wrap the ArrayBuffer with the uint8 array view. We must create this view to interpret the buffer as A single byte.

Setting the PDF file data to Uint8Array, we traverse the buffer and write each block to the stream. We must convert the block to a simple array because it is the only format accepted by the writeBytes method of the stream object.

jsPDF library API

create documents

First, let's discuss how to create a new document. It's as simple as executing this code.

var doc = new jsPDF(orientation, unit, format, compress);

Constructors can accept multiple parameters.

  • Direction - the default value for direction is "portal". If we want a different page orientation, we can set it to "landscape".
  • unit  - We can tell jsPDF which unit we want to work in. Use one of the following options: pt (point), mm (default), cm, in.
  • Format - this is the default page format. It can be "a3", "a4" (default), "a5", "letter", "legal".

We can use the following code to add a new page.

doc.addPage(width, height);

As parameters, we pass the page, width, and height in units defined in the document constructor. Adding a page will move us to this page, so any action will be performed on that page. If we want to go to another page, we can use   setPage function.

doc.setPage(pageNumber);

You can also use this code to get the actual page number.

doc.internal.getNumberOfPages();

The first example in the sample application demonstrates the usage of the above functions. You can run the application to check it and investigate the application code attached to the article.

Processing text

First, the most important thing is to display the text. We use the method with three parameters   doc.text function. The first two are the X and Y positions of the text in the units defined in the document constructor. Note that the Y position is the position of the text baseline, so printing something with the Y position set to 0 actually prints it on the top edge of the document. The third parameter is the text to display.

doc.text(10, 10, "Hello world!");

The second thing is the font name used to draw text. We can choose one of the following: courier, helvetica, time. We change the font family and font style by running the doc.setFont function  .

doc.setFont("courier", "italic");

By execution   doc.getFontList function, we can find the available fonts and font styles that can be set for a given font.

doc.getFontList();
/*
{
    "helvetica": ["normal", "bold", "italic", "bolditalic"],
    "Helvetica": ["", "Bold", "Oblique", "BoldOblique"],
    "courier": ["normal", "bold", "italic", "bolditalic"],
    "Courier": ["", "Bold", "Oblique", "BoldOblique"],
    "times": ["normal", "bold", "italic", "bolditalic"],
    "Times": ["Roman", "Bold", "Italic", "BoldItalic"]
}
*/

Due to doc.setFontStyle or   doc.setFontType function, we can also change the font style separately  , This is the alias of the first.

doc.setFontType("bolditalic");
// is the same as calling
doc.setFontStyle("bolditalic");

Next is the font size. It's as simple as calling a document  . setFontSize function.

doc.setFontSize(40);

The last thing is the text color. We use the doc.setTextColor function to change the text color   And pass three parameters, namely RGB (red, green and blue) color value.

doc.setTextColor(255, 0, 0);

Sample documents showing different text displays are located under example 2 in the sample application attached to the article.

Process image

The only function of the image is   doc.addImage. It takes the image as the first parameter, the image format / type as the second parameter, and the X and Y positions of the image as the third and fourth parameters. We can also choose to pass the new image size as the fifth and sixth parameters.

var img = new Image();
img.addEventListener('load', function() {
    var doc = new jsPDF();
    doc.addImage(img, 'png', 10, 50);
});
img.src = 'images/tizen.png';

In the above example, we passed an Image HTML DOM element as the first parameter of the addImage function  , But it can also be a base64 encoded image string. Currently, the only supported image formats are jpeg/jpg and png.

work with graphics

First, we must set the fill and stroke color of the drawn shape. We use doc.setFillColor and   doc.setDrawColor to complete it  , Pass RGB color values as parameters.

doc.setFillColor(100, 100, 240);
doc.setDrawColor(100, 100, 0);

We can also set the stroke width. The stroke width unit is the same as defined in the document constructor.

doc.setLineWidth(1);

Each shape drawing function takes the center point coordinates (triangles are the only exception) as the two first parameters. They also use the last parameter drawing style. Can be "S"  ,  "F"  ,  "DF"  ,  "FD" string, meaning: "stroke", "fill", "stroke and fill", "fill and stroke". The last two are of course different in the order of drawing operations.

We can draw an ellipse by passing two radii

// Empty ellipse
doc.ellipse(50, 50, 10, 5);
// Filled ellipse
doc.ellipse(100, 50, 10, 5, 'F');
// Filled circle with borders

... or a circle, passing only one radius

doc.circle(150, 50, 5, 'FD');

... or rectangle by passing its width and height

// Empty square
doc.rect(50, 100, 10, 10);
// Filled square
doc.rect(100, 100, 10, 10, 'F');
// Filled square with borders
doc.rect(150, 100, 10, 10, 'FD');

... a rounded rectangle by its width, height, and border radius

// Filled sqaure with rounded corners
doc.roundedRect(50, 150, 10, 10, 3, 3, 'FD');

... and a triangle by passing each angular coordinate.

// Filled triangle with borders
doc.triangle(50, 200, 60, 200, 55, 210, 'FD');

We can also draw a line through two-point coordinates.

// Line
doc.line(50, 250, 100, 250);

generalization

In this article, we describe the process of creating PDF documents using the jsPDF library. This is a simple and powerful tool, which is still under development, so it is expected that new powerful functions will appear soon.

Tags: PHP Python

Posted on Sun, 28 Nov 2021 14:30:44 -0500 by Qense