jspdf.js 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304
  1. /**
  2. * jsPDF
  3. * (c) 2009 James Hall
  4. *
  5. * Some parts based on FPDF.
  6. */
  7. var jsPDF = function(){
  8. // Private properties
  9. var version = '20090504';
  10. var buffer = '';
  11. var pdfVersion = '1.3'; // PDF Version
  12. var defaultPageFormat = 'a4';
  13. var pageFormats = { // Size in mm of various paper formats
  14. 'a3': [841.89, 1190.55],
  15. 'a4': [595.28, 841.89],
  16. 'a5': [420.94, 595.28],
  17. 'letter': [612, 792],
  18. 'legal': [612, 1008]
  19. };
  20. var textColor = '0 g';
  21. var page = 0;
  22. var objectNumber = 2; // 'n' Current object number
  23. var state = 0; // Current document state
  24. var pages = new Array();
  25. var offsets = new Array(); // List of offsets
  26. var lineWidth = 0.200025; // 2mm
  27. var pageHeight;
  28. var k; // Scale factor
  29. var unit = 'mm'; // Default to mm for units
  30. var fontNumber; // TODO: This is temp, replace with real font handling
  31. var documentProperties = {};
  32. var fontSize = 16; // Default font size
  33. var pageFontSize = 16;
  34. // Initilisation
  35. if (unit == 'pt') {
  36. k = 1;
  37. } else if(unit == 'mm') {
  38. k = 72/25.4;
  39. } else if(unit == 'cm') {
  40. k = 72/2.54;
  41. } else if(unit == 'in') {
  42. k = 72;
  43. }
  44. // Private functions
  45. var newObject = function() {
  46. //Begin a new object
  47. objectNumber ++;
  48. offsets[objectNumber] = buffer.length;
  49. out(objectNumber + ' 0 obj');
  50. }
  51. var putHeader = function() {
  52. out('%PDF-' + pdfVersion);
  53. }
  54. var putPages = function() {
  55. // TODO: Fix, hardcoded to a4 portrait
  56. var wPt = pageWidth * k;
  57. var hPt = pageHeight * k;
  58. for(n=1; n <= page; n++) {
  59. newObject();
  60. out('<</Type /Page');
  61. out('/Parent 1 0 R');
  62. out('/Resources 2 0 R');
  63. out('/Contents ' + (objectNumber + 1) + ' 0 R>>');
  64. out('endobj');
  65. //Page content
  66. p = pages[n];
  67. newObject();
  68. out('<</Length ' + p.length + '>>');
  69. putStream(p);
  70. out('endobj');
  71. }
  72. offsets[1] = buffer.length;
  73. out('1 0 obj');
  74. out('<</Type /Pages');
  75. var kids='/Kids [';
  76. for (i = 0; i < page; i++) {
  77. kids += (3 + 2 * i) + ' 0 R ';
  78. }
  79. out(kids + ']');
  80. out('/Count ' + page);
  81. out(sprintf('/MediaBox [0 0 %.2f %.2f]', wPt, hPt));
  82. out('>>');
  83. out('endobj');
  84. }
  85. var putStream = function(str) {
  86. out('stream');
  87. out(str);
  88. out('endstream');
  89. }
  90. var putResources = function() {
  91. putFonts();
  92. putImages();
  93. //Resource dictionary
  94. offsets[2] = buffer.length;
  95. out('2 0 obj');
  96. out('<<');
  97. putResourceDictionary();
  98. out('>>');
  99. out('endobj');
  100. }
  101. var putFonts = function() {
  102. // TODO: Only supports core font hardcoded to Helvetica
  103. newObject();
  104. fontNumber = objectNumber;
  105. name = 'Helvetica';
  106. out('<</Type /Font');
  107. out('/BaseFont /' + name);
  108. out('/Subtype /Type1');
  109. out('/Encoding /WinAnsiEncoding');
  110. out('>>');
  111. out('endobj');
  112. }
  113. var putImages = function() {
  114. // TODO
  115. }
  116. var putResourceDictionary = function() {
  117. out('/ProcSet [/PDF /Text /ImageB /ImageC /ImageI]');
  118. out('/Font <<');
  119. // Do this for each font, the '1' bit is the index of the font
  120. // fontNumber is currently the object number related to 'putFonts'
  121. out('/F1 ' + fontNumber + ' 0 R');
  122. out('>>');
  123. out('/XObject <<');
  124. putXobjectDict();
  125. out('>>');
  126. }
  127. var putXobjectDict = function() {
  128. // TODO
  129. // Loop through images
  130. }
  131. var putInfo = function() {
  132. out('/Producer (jsPDF ' + version + ')');
  133. if(documentProperties.title != undefined) {
  134. out('/Title (' + pdfEscape(documentProperties.title) + ')');
  135. }
  136. if(documentProperties.subject != undefined) {
  137. out('/Subject (' + pdfEscape(documentProperties.subject) + ')');
  138. }
  139. if(documentProperties.author != undefined) {
  140. out('/Author (' + pdfEscape(documentProperties.author) + ')');
  141. }
  142. if(documentProperties.keywords != undefined) {
  143. out('/Keywords (' + pdfEscape(documentProperties.keywords) + ')');
  144. }
  145. if(documentProperties.creator != undefined) {
  146. out('/Creator (' + pdfEscape(documentProperties.creator) + ')');
  147. }
  148. var created = new Date();
  149. var year = created.getFullYear();
  150. var month = (created.getMonth() + 1);
  151. var day = created.getDate();
  152. var hour = created.getHours();
  153. var minute = created.getMinutes();
  154. var second = created.getSeconds();
  155. out('/CreationDate (D:' + sprintf('%02d%02d%02d%02d%02d%02d', year, month, day, hour, minute, second) + ')');
  156. }
  157. var putCatalog = function () {
  158. out('/Type /Catalog');
  159. out('/Pages 1 0 R');
  160. // TODO: Add zoom and layout modes
  161. out('/OpenAction [3 0 R /FitH null]');
  162. out('/PageLayout /OneColumn');
  163. }
  164. function putTrailer() {
  165. out('/Size ' + (objectNumber + 1));
  166. out('/Root ' + objectNumber + ' 0 R');
  167. out('/Info ' + (objectNumber - 1) + ' 0 R');
  168. }
  169. var endDocument = function() {
  170. state = 1;
  171. putHeader();
  172. putPages();
  173. putResources();
  174. //Info
  175. newObject();
  176. out('<<');
  177. putInfo();
  178. out('>>');
  179. out('endobj');
  180. //Catalog
  181. newObject();
  182. out('<<');
  183. putCatalog();
  184. out('>>');
  185. out('endobj');
  186. //Cross-ref
  187. var o = buffer.length;
  188. out('xref');
  189. out('0 ' + (objectNumber + 1));
  190. out('0000000000 65535 f ');
  191. for (var i=1; i <= objectNumber; i++) {
  192. out(sprintf('%010d 00000 n ', offsets[i]));
  193. }
  194. //Trailer
  195. out('trailer');
  196. out('<<');
  197. putTrailer();
  198. out('>>');
  199. out('startxref');
  200. out(o);
  201. out('%%EOF');
  202. state = 3;
  203. }
  204. var beginPage = function() {
  205. page ++;
  206. // Do dimension stuff
  207. state = 2;
  208. pages[page] = '';
  209. // TODO: Hardcoded at A4 and portrait
  210. pageHeight = pageFormats['a4'][1] / k;
  211. pageWidth = pageFormats['a4'][0] / k;
  212. }
  213. var out = function(string) {
  214. if(state == 2) {
  215. pages[page] += string + '\n';
  216. } else {
  217. buffer += string + '\n';
  218. }
  219. }
  220. var _addPage = function() {
  221. beginPage();
  222. // Set line width
  223. out(sprintf('%.2f w', (lineWidth * k)));
  224. // Set font - TODO
  225. // 16 is the font size
  226. pageFontSize = fontSize;
  227. out('BT /F1 ' + parseInt(fontSize) + '.00 Tf ET');
  228. }
  229. // Add the first page automatically
  230. _addPage();
  231. // Escape text
  232. var pdfEscape = function(text) {
  233. return text.replace(/\\/g, '\\\\').replace(/\(/g, '\\(').replace(/\)/g, '\\)');
  234. }
  235. return {
  236. addPage: function() {
  237. _addPage();
  238. },
  239. text: function(x, y, text) {
  240. // need page height
  241. if(pageFontSize != fontSize) {
  242. out('BT /F1 ' + parseInt(fontSize) + '.00 Tf ET');
  243. pageFontSize = fontSize;
  244. }
  245. var str = sprintf('BT %.2f %.2f Td (%s) Tj ET', x * k, (pageHeight - y) * k, pdfEscape(text));
  246. out(str);
  247. },
  248. setProperties: function(properties) {
  249. documentProperties = properties;
  250. },
  251. addImage: function(imageData, format, x, y, w, h) {
  252. },
  253. output: function(type, options) {
  254. endDocument();
  255. if(type == undefined) {
  256. return buffer;
  257. }
  258. if(type == 'datauri') {
  259. document.location.href = 'data:application/pdf;base64,' + Base64.encode(buffer);
  260. }
  261. // @TODO: Add different output options
  262. },
  263. setFontSize: function(size) {
  264. fontSize = size;
  265. }
  266. }
  267. };