The Portable Document Format has been one the major innovations in the fields of desktop publishing and office automations.

It’s widely used in web publishing too, but unfortunately very often in wrong ways – like using it to replace contents that should have been built with HTML. This causes many problems regarding usability, accessibility, SEO and so on.

However, there are some cases in which PDF files are required: when a document needs to be archived and must be used outside the web (for example an invoice) or when you need a deep control on printing.

It was just the need to control printing that brought me to research a way to easily generate a PDF.

The purpose of this article is not to simply explain how a PDF can be created (there are many easy way to do this), but also to focus on the circumstances where a PDF file can solve a problem, and how a simple tool like jsPDF can help with this.

Dealing with Printing

Anyone who has dealt with CSS printing rules knows how difficult it is to achieve a decent level of cross-browser compatibility (take a look, for example, at thePage-break support table at Can I Use). Therefore, when I need to build something that must be printed, I always try to avoid CSS, and the simplest solution is to use PDF.

I’m not talking here about the simple conversion of HTML to PDF. (I’ve tried several tools of that type, but none of them has fully satisfied me.) My goal is to have complete control over the positioning and size of elements, page breaks and so on.

In the past I’ve often used FPDF, a PHP tool that can easily give you such controls and that can be easily expanded with many plugins.

Unfortunately, the library seems to be abandoned (its last version dates back to 2011) (Update: actually, the latest version appears to be from December 2015), but thanks to some JavaScript libraries, we now have the ability to build PDF files directly in the clients (thus making their generation faster).

When I started my project, some months ago, I searched for a JS library, and finally I found two candidates: jsPDF and pdfmake. pdfmake seems to be well documented and very easy to use, but since it was a beta version, I decided for jsPDF.

PDF Building with jsPDF

The jsPDF documentation is fairly minimal, consisting of a single page along with some demos, and a little more information in the source file (or in its jsDoc pages), so keep in mind that using it for complex projects can be a little hard in the beginning.

Anyway, jsPDF is very easy for basic PDF files generation. Take a look to a simple “Hello World” example:

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Hello world</title>
</head>
<body>
<h1>Hello world</h1>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jspdf/1.0.272/jspdf.debug.js"></script>
<script type="text/javascript">
var pdf = new jsPDF();
pdf.text(30, 30, 'Hello world!');
pdf.save('hello_world.pdf');
</script>
</body>
</html>

This HTML page generates a one-page PDF file and saves it on your computer. First you have to link to the jsPDF library (in this case, from cdnjs.com), then a jsPDF instance is created, a line of text is added, and the result is saved as hello_world.pdf.

Note that I’ve used the 1.0.272 version, and that it’s not the latest: at the time of writing this, the most recent version is the 1.1.135, but it has many issues, so I am still using the previous one.

You can see how extremely simple it is to build a basic PDF file (you can find more examples at the jsPDF site).

Let’s try to build something harder.

The Flyer Project

The user interface allows the user to insert some basic data (a title, an abstract and a price). Optionally, an image can be added, otherwise a grey-boxed Special Offer title is displayed.

Other data (the agency name and its website URL and logo) are embedded in the application code.

The PDF can be previewed in a iframe (except Explorer or Edge) or directly downloaded.

When the Update preview or the Download buttons are clicked, the PDF is generated using jsPDF and passed to the iframe as a data URI string or saved to disk, as in the above example.

The PDF generation first creates a new instance a jsPDF object with these options: portrait orientation (p), millimeters units (mm), ‘A4’ format.

var pdf = new jsPDF('p', 'mm', 'a4');

Images are added using the addImage function. Note that every object placed in the PDF page must be exactly positioned. You have to take care of the coordinates of each object using the units declared.

// pdf.addImage(base64_source, image format, X, Y, width, height)
pdf.addImage(agency_logo.src, 'PNG', logo_sizes.centered_x, _y, logo_sizes.w, logo_sizes.h);

Images must be Base64 encoded: the agency logo is embedded in the script in this format, while the image loaded by the user is encoded using the readAsDataURL method in the$('#flyer-image').change listener.

The title is added using the textAlign function. Note that this function is not part of the jsPDF core, but, as suggested by the author in his examples, the library can be easily expanded using its API. You can find the textAlign() function at the top of flyer builder script:

pdf.textAlign(flyer_title, {align: "center"}, 0, _y);

This function calculates the X coordinate of the the text string to make it centered, and then calls the native text() method:

pdf.text(text string, X, Y);

To change text properties, you can use the setFontSize()setFont()setTextColor() andsetFontType() methods.

To set a 20pt Times Bold red string, for example, you need to type this:

pdf.setFontSize(20);
pdf.setFont("times");
pdf.setFontType("bold");
pdf.setTextColor(255, 0, 0);
pdf.text(10,10, 'This is a 20pt Times Bold red string');

The Special offer grey box and the price circle use two similar methods: roundedRect() andcircle(). Both of them require top-left coordinates, size values (the width and height in the first case and the radius in the second one):

pdf.roundedRect( X, Y, width, height, radius along X axis, radius along Y axis, style);
pdf.circle( X, Y, radius, style);

The style parameters refers to the fill and stroke properties of the object. Valid styles are: S [default] for stroke, F for fill, and DF (or FD) for fill and stroke.

Fill and stroke properties must be set in advance using setFillColor and setDrawColor, which require a RGB value and setLineWidth that requires the line width value in the unit declared at inception of PDF document.

The complete code is available in the CodePen demo:

HTML

<div class="container-fluid flyer-builder">
<h1>Flyer Builder</h1>
<p><em>Forked from <a target="_blank" href="http://codepen.io/massimo-cassandro/pen/qOrJNx">this original Pen by Massimo Cassandro</a>, for his SitePoint article on <a target="_blank" href="http://sitepoint.com/generating-pdfs-from-web-pages-on-the-fly-with-jspdf">Generating PDFs from Web Pages on the Fly with jsPDF</a>. The preview doesn't work with Chrome or Safari in this demo since it has been loaded in a iframe. Use Firefox or try at <a href="http://www.primominuto.net/articoli/pdf_flyer/flyer.html">www.primominuto.net/articoli/pdf_flyer/flyer.html</a></em></p> <div class="row">
<div class="col-sm-6 loc_form"> <div class="form-group">
<label for="flyer-image" class="control-label">Image</label>
<input id="flyer-image" type="file" tabindex="1">
</div> <div class="row">
<div class="col-sm-7">
<div class="form-group">
<label for="flyer-title" class="control-label">Title</label>
<input required class="form-control" id="flyer-title" placeholder="Main title" value="Really incredible!!" maxlength="255" type="text" tabindex="2">
</div>
</div>
<div class="col-sm-3">
<div class="form-group">
<label for="flyer-title-size" class="control-label">Size (pt)</label>
<input required class="form-control" id="flyer-title-size" value="60" min="1" step="1" type="number" tabindex="3" title="Title size: tune it to fit the available space">
</div>
</div>
<div class="col-sm-2">
<div class="form-group">
<label for="flyer-title-color" class="control-label">Color</label>
<input required class="form-control" id="flyer-title-color" value="#0080FF" type="color" tabindex="4" title="Title color">
</div>
</div>
</div> <div class="form-group">
<label class="control-label" for="flyer-description">Description</label>
<textarea class="form-control" id="flyer-description" placeholder="Insert a short description taking care of the available space">Lorem ipsum dolor sit amet, consectetur adipisicing elit. Nemo, nihil officia neque ad expedita consequatur quae! Voluptate, incidunt, earum, sit, eveniet harum ratione expedita quibusdam possimus sed laboriosam dolore ut recusandae eos. Ipsa,natus pariatur iste dolorum optio nostrum consectetur!</textarea>
</div> <div class="row">
<div class="col-sm-4">
<div class="form-group">
<label for="flyer-price" class="control-label">Price</label>
<input required class="form-control" id="flyer-price" placeholder="Enter price (w/o decimals)" value="100" type="number" tabindex="5" step="any" min="0">
</div>
</div>
<div class="col-sm-3">
<div class="form-group">
<label for="flyer-price-currency" class="control-label">Currency</label>
<select required class="form-control" id="flyer-price-currency" tabindex="6">
<option value="&euro;">&euro;</option>
<option value="$">$</option>
<option value="&pound;">&pound;</option>
</select>
</div>
</div>
<div class="col-sm-2">
<div class="form-group">
<label for="flyer-price-color" class="control-label">Color</label>
<input required class="form-control" id="flyer-price-color" value="#cc0000" type="color" tabindex="8" title="Price color">
</div>
</div>
</div>
<hr>
<div class="row">
<div class="col-sm-6">
<div class="form-group">
<button id="flyer_preview_btn" type="button" class="btn btn-primary btn-block" tabindex="9">Update preview</button>
</div>
</div>
<div class="col-sm-6">
<div class="form-group text-right">
<button id="flyer_download_btn" type="button" class="btn btn-default btn-xs btn-block" tabindex="10">Download</button>
</div>
</div>
</div> </div> <div class="col-sm-6">
<iframe id="pdf_preview" type="application/pdf" src=""></iframe>
</div> </div>
</div>

css

.flyer-builder {
position: relative;
height: 100%; & iframe,
.no_iframe {
width:100%;
height:400px;
border:1px solid #666;
background-color: #ddd;
} & .no_iframe {
& > div {
//margin:0 .3em;
width:80%;
position: absolute;
top:50%;
left:50%;
transform: translate(-50%, -50%);
font-weight: normal;
}
} @media all and (min-width:768px) {
& .btn.btn-block {
display: inline;
width: auto;
}
}
}

js

(function() {
"use strict"; /*
Refs:
http://mrrio.github.io/jsPDF/
https://github.com/MrRio/jsPDF
https://mrrio.github.io/jsPDF/doc/symbols/jsPDF.html
*/ // some variables
var agency_logo = {
src: 'data:image/png;base64,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',
w: 800,
h: 285
},
agency_name = 'Travel & Holidays',
agency_site_url = 'www.travelandholidays.com',
footer = agency_name + ' - ' + agency_site_url, page_size = 'a4',
page_width = 210, // mm
page_margin = 10, // mm
content_width = page_width - (page_margin * 2), // available width for the content _y, _x, // drawing coord
color_array, _string, lineHeight, y_correction, // some variables vspace = 10 // standard vertical space between elements ; // some variables
var can_display_preview = true, // if true a preview of the PDF can be displayed in the iframe,
// this value is set to false if the browser can't display the preview
preview_container = $('#pdf_preview'),
update_preview_button = $('#flyer_preview_btn'),
download_button = $('#flyer_download_btn'); // preview can be displayed?
if (navigator.msSaveBlob) { // older IE
update_preview_button.prop('disabled', true);
can_display_preview = false;
preview_container.replaceWith(
'<div class="no_iframe">' +
'<div>' +
"The preview can't be displayed" +
'</div>' +
'</div>'
);
} // utilities
var hex2rgb = function(hex_string) {
if (/^#/.test(hex_string)) {
hex_string = hex_string.substr(1);
}
if (hex_string.length === 3) {
hex_string = hex_string.replace(/\w/, function(match) {
return String(match) + String(match);
});
} return {
red: parseInt(hex_string.substr(0, 2), 16),
green: parseInt(hex_string.substr(2, 2), 16),
blue: parseInt(hex_string.substr(4, 2), 16)
};
}, px2mm = function(pixel) {
// px to inches
var inches = pixel / 72;
return inches * 25.4;
}, mm2px = function(millimeters) {
// mm to inches
var inches = millimeters / 25.4;
return inches * 72;
}, // function to calculate and check img sizes
imgSizes = function(img_w, img_h, img_mm_w) {
/*
img_w and img_h represent the original image size, in pixel
img_mm_w is the desidered rendered image size, in millimeters */ if (img_mm_w > content_width) { // this should be never used...
img_mm_w = content_width;
} if (mm2px(img_mm_w) > img_w) {
throw 'The `img_mm_w` parameter is too big';
} var img_mm_h = Math.round((px2mm(img_h) * img_mm_w) / px2mm(img_w)); return {
w: img_mm_w,
h: img_mm_h,
centered_x: (page_width - img_mm_w) / 2
};
}; try { // image reading
// More info at https://developer.mozilla.org/en-US/docs/Web/API/FileReader/readAsDataURL
// for more examples about file api
// take a look at https://scotch.io/tutorials/use-the-html5-file-api-to-work-with-files-locally-in-the-browser var flyer_img = $('#flyer-image'),
img_data = null; $('#flyer-image').change(function() { // temporary disabling buttons while parsing image
update_preview_button.prop('disabled', true);
download_button.prop('disabled', true); /*
getting the file flyer_img[0] : transforms the jQuery reference to a DOM object
files[0] : refers to the file the the user has chosen use `console.log(user_file);` to show some info about the file */ var user_file = flyer_img[0].files[0]; img_data = {
type: user_file.type === 'image/jpeg' ? 'JPEG' : 'PNG' // maybe you should add some controls to prevent loading of other file types
}; var reader = new FileReader();
reader.onload = function(event) {
img_data.src = event.target.result; // we need this to get img dimensions
var user_img = new Image();
user_img.onload = function() {
img_data.w = user_img.width;
img_data.h = user_img.height; // restoring buttons
download_button.prop('disabled', false);
if (can_display_preview) {
update_preview_button.prop('disabled', false);
}
};
user_img.src = img_data.src;
}; //when the file is read it triggers the onload event above.
reader.readAsDataURL(user_file);
}); //!pdf builder
var createPDF = function(update_preview) {
/*
update_preview:
==> true: shows pdf online
==> false: downloads the pdf
*/ _y = page_margin; // vertical starting point // form data
var flyer_title = $('#flyer-title').val(),
flyer_title_size = $('#flyer-title-size').val(),
flyer_title_color = $('#flyer-title-color').val(),
flyer_description = $('#flyer-description').val(),
flyer_price = $('#flyer-price').val(),
flyer_price_currency = $('#flyer-price-currency').val(),
flyer_price_color = $('#flyer-price-color').val(); var pdf = new jsPDF('p', 'mm', page_size),
text_baseline, // some colors:
light_grey = 237,
grey = 128,
black = 0,
white = 255; // Optional - set properties of the document
pdf.setProperties({
title: flyer_title,
subject: footer,
author: 'me',
creator: 'Flyer Builder & jsPDF'
}); // !logo
var logo_sizes = imgSizes(agency_logo.w, agency_logo.h, 60);
pdf.addImage(agency_logo.src, 'PNG', logo_sizes.centered_x, _y, logo_sizes.w, logo_sizes.h); // fonts initializing
pdf.setFont("helvetica");
pdf.setFontType("bold"); // !main title
color_array = hex2rgb(flyer_title_color);
pdf.setTextColor(color_array.red, color_array.green, color_array.blue); pdf.setFontSize(flyer_title_size); lineHeight = px2mm(pdf.getLineHeight(flyer_title)); _y += (logo_sizes.h + vspace + lineHeight); pdf.textAlign(flyer_title, {
align: "center"
}, 0, _y); _y += vspace; // !user image
if (img_data) {
var img_sizes = imgSizes(img_data.w, img_data.h, content_width);
pdf.addImage(img_data.src, img_data.type, img_sizes.centered_x, _y, img_sizes.w, img_sizes.h);
_y += img_sizes.h; } else {
// if we haven't an image, a grey box with a text is added var box_height = 80; pdf.setFillColor(light_grey);
pdf.roundedRect(page_margin, _y, content_width, box_height, 5, 5, 'F');
pdf.setFontSize(60);
pdf.setTextColor(white);
_string = 'SPECIAL OFFER';
lineHeight = px2mm(pdf.getLineHeight(_string)); // y_correction: value to be added to y coord of the grey box to have text vertically centered
// it is empirically calculated adding 1/3 of text line height to half box height
y_correction = box_height / 2 + lineHeight / 3; pdf.textAlign(_string, {
align: "center"
}, 0, _y + y_correction); _y += box_height;
} // !price
// first: creating a circle that overlaps the bottom side of the image
var circle_radius = 30;
color_array = hex2rgb(flyer_price_color);
pdf.setFillColor(color_array.red, color_array.green, color_array.blue); // _x and _y refer to center of the circle
_x = content_width - circle_radius; // circle ends at `page_margin` millimeters from the image right side pdf.circle(_x, _y, circle_radius, 'F'); // circle overlaps image for 1/2 of its height pdf.setFontSize(60);
pdf.setFont("times");
pdf.setFontType("bold"); _string = flyer_price_currency + parseInt(flyer_price); // decimals are removed lineHeight = px2mm(pdf.getLineHeight(_string));
y_correction = lineHeight / 3; pdf.setTextColor(white);
pdf.textAlign(_string, {
align: "centerAtX"
}, _x, _y + y_correction); // !description
if (flyer_description) {
pdf.setFontSize(20);
pdf.setFont("helvetica");
pdf.setFontType("italic");
pdf.setTextColor(grey); var lineWidth = content_width - (circle_radius * 2) - (page_margin * 2);
_y += page_margin; var line_height = 12; // mm var description_lines = pdf.splitTextToSize(flyer_description, lineWidth);
//pdf.text(page_margin, _y, description_lines); // doesn't allows to change line spacing for (var i = 0; i < description_lines.length; i++) {
pdf.text(page_margin, _y, description_lines[i]);
_y += line_height;
} } // !footer
_y = 287;
pdf.setFontSize(9);
pdf.setFontType("normal");
pdf.setTextColor(black);
pdf.textAlign(footer, {
align: "center"
}, 0, _y); // ****************************
// output
if (update_preview) {
preview_container.attr('src', pdf.output('datauristring'));
} else {
pdf.save('flyer ' + flyer_title + '.pdf');
} }; // end createPDF // !buttons
update_preview_button.click(function() {
createPDF(true);
}); $('#flyer_download_btn').click(function() {
createPDF(false);
}); } catch (e) {
console.log(e);
} })();

Conclusion

This basic example shows how it’s possible to build a very basic flyer with jsPDF.

Its use could be easy, but the lack of a complete documentation makes every step really complicated.

I’m still looking around for other solutions, keeping my eye on others like pdfmake. But ultimately, I think the only really definitive solution can be better browser support for printing CSS rules!

Have you used jsPDF or something similar? What was your experience? Let me know in the comments.

转:Generating PDFs from Web Pages on the Fly with jsPDF的更多相关文章

  1. 如何在ASP.NET Web站点中统一页面布局[Creating a Consistent Layout in ASP.NET Web Pages(Razor) Sites]

    如何在ASP.NET Web站点中统一页面布局[Creating a Consistent Layout in ASP.NET Web Pages(Razor) Sites] 一.布局页面介绍[Abo ...

  2. Displaying Data in a Chart with ASP.NET Web Pages (Razor)

    This article explains how to use a chart to display data in an ASP.NET Web Pages (Razor) website by ...

  3. Web Pages - Efficient Paging Without The WebGrid

    Web Pages - Efficient Paging Without The WebGrid If you want to display your data over a number of p ...

  4. Web Pages razor 学习

    1. Web Pages razor Web Pages 是三种 ASP.NET 编程模型中的一种,用于创建 ASP.NET 网站和 web 应用程序. 其他两种编程模型是 Web Forms 和 M ...

  5. ASP.NET MVC3 系列教程 – Web Pages 1.0

    http://www.cnblogs.com/highend/archive/2011/04/14/aspnet_mvc3_web_pages.html I:Web Pages 1.0中以“_”开头的 ...

  6. Web网页中动态数据区域的识别与抽取 Dynamical Data Regions Identification and Extraction in Web Pages

    Web网页中动态数据区域的识别与抽取 Dynamical Data Regions Identification and Extraction in Web Pages Web网页中动态数据区域的识别 ...

  7. 五张图概括 什么是 ASP 、 ASP.NET (Web Pages,Web Forms ,MVC )

    当你看懂下面这五张图,我相信你对于学习.NET Web开发路线将不陌生!                                               来源: http://www.w3 ...

  8. 安卓,网页控件,显示网页 Android, web controls, display web pages

    安卓,网页控件,显示网页Android, web controls, display web pages 作者:韩梦飞沙 Author:han_meng_fei_sha 邮箱:313134555@qq ...

  9. ASP.NET —— Web Pages

    为简单起见,新建一个空的web工程,再新建一个MVC的视图(.cshtml),因为WP是单页面模型,所以以后就在这个页面中进行试验. Razor语法简介: 变量可用var或者其确切类型声明. 遍历fo ...

随机推荐

  1. Android--View事件传递

    Android--View事件传递 View事件传递首先要明白以下要素: 事件就是MotionEvent.该对象包含了传递的事件中的所有信息 事件的来源是Window(即PhoneWindow),包含 ...

  2. 如何删除 CentOS 6 更新后产生的多余的内核?

    第一种方法:通过命令的方式解决多余的内核 1.首先查看当前内核的版本号: [root@jxatei ~]# uname  -a Linux jxatei.server2.6.32-573.1.1.el ...

  3. 一键部署Moodle开源课程管理系统

    产品详情 产品介绍Moodle https://moodle.org/ 是一个开源及自由的电子学习软件平台,亦称为课程管理系统.学习管理系统或虚拟学习环境.Moodle 特色异于其他商业线上教学平台, ...

  4. 编写生成32位大写和小写字符的md5的函数

    package nicetime.com.practise; import java.security.MessageDigest; /** * MD5加密是JAVA应用中常见的算法,请写出两个MD5 ...

  5. LeetCode Min Stack 最小值栈

    题意:实现栈的四个基本功能.要求:在get最小元素值时,复杂度O(1). 思路:链表直接实现.最快竟然还要61ms,醉了. class MinStack { public: MinStack(){ h ...

  6. 在一个另一个文件中 #include一个**dlg.h文件,会发生dlg的资源ID未定义的错误 :

    1    在一个另一个文件中 #include一个**dlg.h文件,会发生dlg的资源ID未定义的错误 : dlg1.h(23) : error C2065: 'IDD_DIALOG1' : und ...

  7. topcpder SRM 664 div2 A,B,C BearCheats , BearPlays equalPiles , BearSorts (映射)

    A题,熊孩子测视力,水题,题意就是判断一下两个数对应位不相同的数字有多少个. #include<bits/stdc++.h> using namespace std; class Bear ...

  8. js判断是否为app

    var ua = navigator.userAgent; var isapp = ua.match("lenovomallapp") == null ? 0 : 1;

  9. 【胎教】做AI的基础,开始学习。

    昨天,找了博导,他给我聊了一下暑假任务.现总结如下: 1. 周志华, 机器学习: 2. GoodFellow,深度学习: 3. 曾更生,*****医学图像处理: 4. cs231n,公式推导,课后习题 ...

  10. JDBC操作数据库的详细步骤

    1.注册驱动 告知JVM使用的是哪一个数据库的驱动 2.创建连接 使用JDBC中的类,完成对MySQL数据库的连接 3. 得到执行sql语句的Statement对象 通过连接对象获取对SQL语句的执行 ...