|
165 | 165 | return UnitedNumberMap[css_line_height_string] = 1;
|
166 | 166 | };
|
167 | 167 | GetCSS = function (element) {
|
168 |
| - var css, |
169 |
| - tmp, |
170 |
| - computedCSSElement; |
| 168 | + var css,tmp,computedCSSElement; |
171 | 169 | computedCSSElement = (function (el) {
|
172 | 170 | var compCSS;
|
173 | 171 | compCSS = (function (el) {
|
|
202 | 200 | css["font-size"] = ResolveUnitedNumber(computedCSSElement("font-size")) || 1;
|
203 | 201 | css["line-height"] = ResolveUnitedNumber(computedCSSElement("line-height")) || 1;
|
204 | 202 | css["display"] = (computedCSSElement("display") === "inline" ? "inline" : "block");
|
205 |
| - if (css["display"] === "block") { |
206 |
| - css["margin-top"] = ResolveUnitedNumber(computedCSSElement("margin-top")) || 0; |
207 |
| - css["margin-bottom"] = ResolveUnitedNumber(computedCSSElement("margin-bottom")) || 0; |
208 |
| - css["padding-top"] = ResolveUnitedNumber(computedCSSElement("padding-top")) || 0; |
209 |
| - css["padding-bottom"] = ResolveUnitedNumber(computedCSSElement("padding-bottom")) || 0; |
210 |
| - css["margin-left"] = ResolveUnitedNumber(computedCSSElement("margin-left")) || 0; |
211 |
| - css["margin-right"] = ResolveUnitedNumber(computedCSSElement("margin-right")) || 0; |
212 |
| - css["padding-left"] = ResolveUnitedNumber(computedCSSElement("padding-left")) || 0; |
213 |
| - css["padding-right"] = ResolveUnitedNumber(computedCSSElement("padding-right")) || 0; |
214 |
| - } |
| 203 | + |
| 204 | + tmp = (css["display"] === "block"); |
| 205 | + css["margin-top"] = tmp && ResolveUnitedNumber(computedCSSElement("margin-top")) || 0; |
| 206 | + css["margin-bottom"] = tmp && ResolveUnitedNumber(computedCSSElement("margin-bottom")) || 0; |
| 207 | + css["padding-top"] = tmp && ResolveUnitedNumber(computedCSSElement("padding-top")) || 0; |
| 208 | + css["padding-bottom"] = tmp && ResolveUnitedNumber(computedCSSElement("padding-bottom")) || 0; |
| 209 | + css["margin-left"] = tmp && ResolveUnitedNumber(computedCSSElement("margin-left")) || 0; |
| 210 | + css["margin-right"] = tmp && ResolveUnitedNumber(computedCSSElement("margin-right")) || 0; |
| 211 | + css["padding-left"] = tmp && ResolveUnitedNumber(computedCSSElement("padding-left")) || 0; |
| 212 | + css["padding-right"] = tmp && ResolveUnitedNumber(computedCSSElement("padding-right")) || 0; |
| 213 | + |
215 | 214 | //float and clearing of floats
|
216 | 215 | css["float"] = FloatMap[computedCSSElement("cssFloat")] || "none";
|
217 | 216 | css["clear"] = ClearMap[computedCSSElement("clear")] || "none";
|
|
330 | 329 | while (i < l) {
|
331 | 330 | cn = cns[i];
|
332 | 331 | if (typeof cn === "object") {
|
333 |
| - |
| 332 | + |
334 | 333 | //execute all watcher functions to e.g. reset floating
|
335 | 334 | renderer.executeWatchFunctions(cn);
|
336 | 335 |
|
|
357 | 356 | renderer.pdf.addPage();
|
358 | 357 | renderer.y = renderer.pdf.margins_doc.top;
|
359 | 358 | }
|
360 |
| - |
| 359 | + |
361 | 360 | } else if (cn.nodeType === 1 && !SkipNode[cn.nodeName]) {
|
362 | 361 | /*** IMAGE RENDERING ***/
|
363 |
| - if (cn.nodeName === "IMG" && images[cn.getAttribute("src")]) { |
| 362 | + var cached_image; |
| 363 | + if (cn.nodeName === "IMG") { |
| 364 | + var url = cn.getAttribute("src"); |
| 365 | + cached_image = images[renderer.pdf.sHashCode(url) || url]; |
| 366 | + } |
| 367 | + if (cached_image) { |
364 | 368 | if ((renderer.pdf.internal.pageSize.height - renderer.pdf.margins_doc.bottom < renderer.y + cn.height) && (renderer.y > renderer.pdf.margins_doc.top)) {
|
365 | 369 | renderer.pdf.addPage();
|
366 | 370 | renderer.y = renderer.pdf.margins_doc.top;
|
367 | 371 | //check if we have to set back some values due to e.g. header rendering for new page
|
368 | 372 | renderer.executeWatchFunctions(cn);
|
369 |
| - } |
370 |
| - |
| 373 | + } |
| 374 | + |
371 | 375 | var imagesCSS = GetCSS(cn);
|
372 | 376 | var imageX = renderer.x;
|
373 | 377 | var fontToUnitRatio = 12 / renderer.pdf.internal.scaleFactor;
|
374 |
| - |
| 378 | + |
375 | 379 | //define additional paddings, margins which have to be taken into account for margin calculations
|
376 | 380 | var additionalSpaceLeft = (imagesCSS["margin-left"] + imagesCSS["padding-left"])*fontToUnitRatio;
|
377 | 381 | var additionalSpaceRight = (imagesCSS["margin-right"] + imagesCSS["padding-right"])*fontToUnitRatio;
|
378 | 382 | var additionalSpaceTop = (imagesCSS["margin-top"] + imagesCSS["padding-top"])*fontToUnitRatio;
|
379 | 383 | var additionalSpaceBottom = (imagesCSS["margin-bottom"] + imagesCSS["padding-bottom"])*fontToUnitRatio;
|
380 |
| - |
| 384 | + |
381 | 385 | //if float is set to right, move the image to the right border
|
382 | 386 | //add space if margin is set
|
383 | 387 | if (imagesCSS['float'] !== undefined && imagesCSS['float'] === 'right') {
|
|
386 | 390 | imageX += additionalSpaceLeft;
|
387 | 391 | }
|
388 | 392 |
|
389 |
| - renderer.pdf.addImage(images[cn.getAttribute("src")], imageX, renderer.y + additionalSpaceTop, cn.width, cn.height); |
| 393 | + renderer.pdf.addImage(cached_image, imageX, renderer.y + additionalSpaceTop, cn.width, cn.height); |
| 394 | + cached_image = undefined; |
390 | 395 | //if the float prop is specified we have to float the text around the image
|
391 |
| - if (imagesCSS['float'] !== undefined) { |
392 |
| - if (imagesCSS['float'] === 'right' || imagesCSS['float'] === 'left') { |
393 |
| - |
394 |
| - //add functiont to set back coordinates after image rendering |
395 |
| - renderer.watchFunctions.push((function(diffX , thresholdY, diffWidth, el) { |
396 |
| - //undo drawing box adaptions which were set by floating |
397 |
| - if (renderer.y >= thresholdY) { |
398 |
| - renderer.x += diffX; |
399 |
| - renderer.settings.width += diffWidth; |
400 |
| - return true; |
401 |
| - } else if(el && el.nodeType === 1 && !SkipNode[el.nodeName] && renderer.x+el.width > (renderer.pdf.margins_doc.left + renderer.pdf.margins_doc.width)) { |
402 |
| - renderer.x += diffX; |
403 |
| - renderer.y = thresholdY; |
404 |
| - renderer.settings.width += diffWidth; |
| 396 | + if (imagesCSS['float'] === 'right' || imagesCSS['float'] === 'left') { |
| 397 | + //add functiont to set back coordinates after image rendering |
| 398 | + renderer.watchFunctions.push((function(diffX , thresholdY, diffWidth, el) { |
| 399 | + //undo drawing box adaptions which were set by floating |
| 400 | + if (renderer.y >= thresholdY) { |
| 401 | + renderer.x += diffX; |
| 402 | + renderer.settings.width += diffWidth; |
| 403 | + return true; |
| 404 | + } else if(el && el.nodeType === 1 && !SkipNode[el.nodeName] && renderer.x+el.width > (renderer.pdf.margins_doc.left + renderer.pdf.margins_doc.width)) { |
| 405 | + renderer.x += diffX; |
| 406 | + renderer.y = thresholdY; |
| 407 | + renderer.settings.width += diffWidth; |
| 408 | + return true; |
| 409 | + } else { |
| 410 | + return false; |
| 411 | + } |
| 412 | + }).bind(this, (imagesCSS['float'] === 'left') ? -cn.width-additionalSpaceLeft-additionalSpaceRight : 0, renderer.y+cn.height+additionalSpaceTop+additionalSpaceBottom, cn.width)); |
| 413 | + //reset floating by clear:both divs |
| 414 | + //just set cursorY after the floating element |
| 415 | + renderer.watchFunctions.push((function(yPositionAfterFloating, pages, el) { |
| 416 | + if (renderer.y < yPositionAfterFloating && pages === renderer.pdf.internal.getNumberOfPages()) { |
| 417 | + if (el.nodeType === 1 && GetCSS(el).clear === 'both') { |
| 418 | + renderer.y = yPositionAfterFloating; |
405 | 419 | return true;
|
406 | 420 | } else {
|
407 | 421 | return false;
|
408 | 422 | }
|
409 |
| - }).bind(this, (imagesCSS['float'] === 'left') ? -cn.width-additionalSpaceLeft-additionalSpaceRight : 0, renderer.y+cn.height+additionalSpaceTop+additionalSpaceBottom, cn.width)); |
410 |
| - |
411 |
| - //reset floating by clear:both divs |
412 |
| - //just set cursorY after the floating element |
413 |
| - renderer.watchFunctions.push((function(yPositionAfterFloating, pages, el) { |
414 |
| - if (renderer.y < yPositionAfterFloating && pages === renderer.pdf.internal.getNumberOfPages()) { |
415 |
| - if (el.nodeType === 1 && GetCSS(el).clear === 'both') { |
416 |
| - renderer.y = yPositionAfterFloating; |
417 |
| - return true; |
418 |
| - } else { |
419 |
| - return false; |
420 |
| - } |
421 |
| - } else { |
422 |
| - return true; |
423 |
| - } |
424 |
| - }).bind(this, renderer.y+cn.height, renderer.pdf.internal.getNumberOfPages())); |
425 |
| - |
426 |
| - //if floating is set we decrease the available width by the image width |
427 |
| - renderer.settings.width -= cn.width+additionalSpaceLeft+additionalSpaceRight; |
428 |
| - //if left just add the image width to the X coordinate |
429 |
| - if (imagesCSS['float'] === 'left') { |
430 |
| - renderer.x += cn.width+additionalSpaceLeft+additionalSpaceRight; |
| 423 | + } else { |
| 424 | + return true; |
431 | 425 | }
|
| 426 | + }).bind(this, renderer.y+cn.height, renderer.pdf.internal.getNumberOfPages())); |
| 427 | + |
| 428 | + //if floating is set we decrease the available width by the image width |
| 429 | + renderer.settings.width -= cn.width+additionalSpaceLeft+additionalSpaceRight; |
| 430 | + //if left just add the image width to the X coordinate |
| 431 | + if (imagesCSS['float'] === 'left') { |
| 432 | + renderer.x += cn.width+additionalSpaceLeft+additionalSpaceRight; |
432 | 433 | }
|
433 |
| - //if no floating is set, move the rendering cursor after the image height |
434 | 434 | } else {
|
| 435 | + //if no floating is set, move the rendering cursor after the image height |
435 | 436 | renderer.y += cn.height + additionalSpaceBottom;
|
436 |
| - } |
437 |
| - |
438 |
| - /*** TABLE RENDERING ***/ |
| 437 | + } |
| 438 | + |
| 439 | + /*** TABLE RENDERING ***/ |
439 | 440 | } else if (cn.nodeName === "TABLE") {
|
440 | 441 | table2json = tableToJson(cn, renderer);
|
441 | 442 | renderer.y += 10;
|
|
495 | 496 | images = {};
|
496 | 497 | loadImgs = function (element, renderer, elementHandlers, cb) {
|
497 | 498 | var imgs = element.getElementsByTagName('img'),
|
498 |
| - l = imgs.length, |
| 499 | + l = imgs.length, found_images, |
499 | 500 | x = 0;
|
500 | 501 | function done() {
|
501 | 502 | renderer.pdf.internal.events.publish('imagesLoaded');
|
502 |
| - cb(); |
| 503 | + cb(found_images); |
503 | 504 | }
|
504 | 505 | function loadImage(url, width, height) {
|
505 | 506 | if (!url)
|
506 | 507 | return;
|
507 | 508 | var img = new Image();
|
508 |
| - ++x; |
| 509 | + found_images = ++x; |
509 | 510 | img.crossOrigin = '';
|
510 | 511 | img.onerror = img.onload = function () {
|
511 | 512 | if(img.complete) {
|
|
517 | 518 | }
|
518 | 519 | //if valid image add to known images array
|
519 | 520 | if (img.width + img.height) {
|
520 |
| - //TODO: use a hash since data URIs could greatly increase the memory usage |
521 |
| - images[url] = images[url] || img; |
| 521 | + var hash = renderer.pdf.sHashCode(url) || url; |
| 522 | + images[hash] = images[hash] || img; |
522 | 523 | }
|
523 | 524 | }
|
524 | 525 | if(!--x) {
|
|
531 | 532 | loadImage(imgs[l].getAttribute("src"),imgs[l].width,imgs[l].height);
|
532 | 533 | return x || done();
|
533 | 534 | };
|
534 |
| - checkForFooter = function (elem, renderer, elementHandlers, callback) { |
| 535 | + checkForFooter = function (elem, renderer, elementHandlers) { |
535 | 536 | //check if we can found a <footer> element
|
536 | 537 | var footer = elem.getElementsByTagName("footer");
|
537 | 538 | if (footer.length > 0) {
|
|
596 | 597 |
|
597 | 598 | //prevent footer rendering
|
598 | 599 | SkipNode['FOOTER'] = 1;
|
599 |
| - |
600 | 600 | }
|
601 |
| - |
602 |
| - //footer preparation finished |
603 |
| - callback(); |
604 | 601 | };
|
605 | 602 | process = function (pdf, element, x, y, settings, callback) {
|
606 | 603 | if (!element)
|
|
625 | 622 | })(element.replace(/<\/?script[^>]*?>/gi, ''));
|
626 | 623 | }
|
627 | 624 | var r = new Renderer(pdf, x, y, settings);
|
628 |
| - callback = callback || function () {}; |
629 | 625 |
|
630 | 626 | // 1. load images
|
631 | 627 | // 2. prepare optional footer elements
|
632 | 628 | // 3. render content
|
633 |
| - loadImgs.call(this, element, r, settings.elementHandlers, function () { |
634 |
| - checkForFooter.call(this, element, r, settings.elementHandlers, function () { |
635 |
| - DrillForContent(element, r, settings.elementHandlers); |
636 |
| - //send event dispose for final taks (e.g. footer totalpage replacement) |
637 |
| - r.pdf.internal.events.publish('htmlRenderingFinished'); |
638 |
| - callback(r.dispose()); |
639 |
| - }); |
| 629 | + loadImgs.call(this, element, r, settings.elementHandlers, function (found_images) { |
| 630 | + checkForFooter( element, r, settings.elementHandlers); |
| 631 | + DrillForContent(element, r, settings.elementHandlers); |
| 632 | + //send event dispose for final taks (e.g. footer totalpage replacement) |
| 633 | + r.pdf.internal.events.publish('htmlRenderingFinished'); |
| 634 | + r = r.dispose(); |
| 635 | + if (typeof callback === 'function') callback(r); |
| 636 | + else if (found_images) console.error('jsPDF Warning: rendering issues? provide a callback to fromHTML!'); |
640 | 637 | });
|
641 |
| - |
642 | 638 | return pdf;
|
643 | 639 | };
|
644 | 640 | Renderer.prototype.init = function () {
|
|
655 | 651 | y : this.y
|
656 | 652 | };
|
657 | 653 | };
|
658 |
| - |
| 654 | + |
659 | 655 | //Checks if we have to execute some watcher functions
|
660 | 656 | //e.g. to end text floating around an image
|
661 | 657 | Renderer.prototype.executeWatchFunctions = function(el) {
|
|
672 | 668 | this.watchFunctions = narray;
|
673 | 669 | }
|
674 | 670 | return ret;
|
675 |
| - }; |
| 671 | + }; |
676 | 672 |
|
677 | 673 | Renderer.prototype.splitFragmentsIntoLines = function (fragments, styles) {
|
678 | 674 | var currentLineLength,
|
|
843 | 839 |
|
844 | 840 | //stores the current indent of cursor position
|
845 | 841 | var currentIndent = 0;
|
846 |
| - |
| 842 | + |
847 | 843 | while (lines.length) {
|
848 | 844 | line = lines.shift();
|
849 | 845 | maxLineHeight = 0;
|
|
875 | 871 | i++;
|
876 | 872 | }
|
877 | 873 | this.y += maxLineHeight * fontToUnitRatio;
|
878 |
| - |
| 874 | + |
879 | 875 | //if some watcher function was executed sucessful, so e.g. margin and widths were changed,
|
880 | 876 | //reset line drawing and calculate position and lines again
|
881 | 877 | //e.g. to stop text floating around an image
|
882 | 878 | if (this.executeWatchFunctions(line[0][1]) && lines.length > 0) {
|
883 | 879 | var localFragments = [];
|
884 | 880 | var localStyles = [];
|
885 |
| - //create fragement array of |
| 881 | + //create fragement array of |
886 | 882 | lines.forEach(function(localLine) {
|
887 | 883 | var i = 0;
|
888 | 884 | var l = localLine.length;
|
889 | 885 | while (i !== l) {
|
890 | 886 | if (localLine[i][0]) {
|
891 |
| - localFragments.push(localLine[i][0]+' '); |
| 887 | + localFragments.push(localLine[i][0]+' '); |
892 | 888 | localStyles.push(localLine[i][1]);
|
893 | 889 | }
|
894 | 890 | ++i;
|
|
897 | 893 | //split lines again due to possible coordinate changes
|
898 | 894 | lines = this.splitFragmentsIntoLines(PurgeWhiteSpace(localFragments), localStyles);
|
899 | 895 | //reposition the current cursor
|
900 |
| - out("ET", "Q"); |
| 896 | + out("ET", "Q"); |
901 | 897 | out("q", "BT", this.pdf.internal.getCoordinateString(this.x), this.pdf.internal.getVerticalCoordinateString(this.y), "Td");
|
902 |
| - } |
903 |
| - |
| 898 | + } |
| 899 | + |
904 | 900 | }
|
905 | 901 | if (cb && typeof cb === "function") {
|
906 | 902 | cb.call(this, this.x - 9, this.y - fontSize / 2);
|
|
961 | 957 | ClearMap = {
|
962 | 958 | none : 'none',
|
963 | 959 | both : 'both'
|
964 |
| - }; |
| 960 | + }; |
965 | 961 | UnitedNumberMap = {
|
966 | 962 | normal : 1
|
967 | 963 | };
|
|
0 commit comments