start test11
parent
5a06b48f20
commit
7dba1d4c71
@ -0,0 +1,338 @@
|
||||
// Generated by CoffeeScript 1.12.5
|
||||
(function() {
|
||||
var LineWrapper, number;
|
||||
|
||||
LineWrapper = require('../line_wrapper');
|
||||
|
||||
number = require('../object').number;
|
||||
|
||||
module.exports = {
|
||||
initText: function() {
|
||||
this.x = 0;
|
||||
this.y = 0;
|
||||
return this._lineGap = 0;
|
||||
},
|
||||
lineGap: function(_lineGap) {
|
||||
this._lineGap = _lineGap;
|
||||
return this;
|
||||
},
|
||||
moveDown: function(lines) {
|
||||
if (lines == null) {
|
||||
lines = 1;
|
||||
}
|
||||
this.y += this.currentLineHeight(true) * lines + this._lineGap;
|
||||
return this;
|
||||
},
|
||||
moveUp: function(lines) {
|
||||
if (lines == null) {
|
||||
lines = 1;
|
||||
}
|
||||
this.y -= this.currentLineHeight(true) * lines + this._lineGap;
|
||||
return this;
|
||||
},
|
||||
_text: function(text, x, y, options, lineCallback) {
|
||||
var j, len, line, ref, wrapper;
|
||||
options = this._initOptions(x, y, options);
|
||||
text = '' + text;
|
||||
if (options.wordSpacing) {
|
||||
text = text.replace(/\s{2,}/g, ' ');
|
||||
}
|
||||
if (options.width) {
|
||||
wrapper = this._wrapper;
|
||||
if (!wrapper) {
|
||||
wrapper = new LineWrapper(this, options);
|
||||
wrapper.on('line', lineCallback);
|
||||
}
|
||||
this._wrapper = options.continued ? wrapper : null;
|
||||
this._textOptions = options.continued ? options : null;
|
||||
wrapper.wrap(text, options);
|
||||
} else {
|
||||
ref = text.split('\n');
|
||||
for (j = 0, len = ref.length; j < len; j++) {
|
||||
line = ref[j];
|
||||
lineCallback(line, options);
|
||||
}
|
||||
}
|
||||
return this;
|
||||
},
|
||||
text: function(text, x, y, options) {
|
||||
return this._text(text, x, y, options, this._line.bind(this));
|
||||
},
|
||||
widthOfString: function(string, options) {
|
||||
if (options == null) {
|
||||
options = {};
|
||||
}
|
||||
return this._font.widthOfString(string, this._fontSize, options.features) + (options.characterSpacing || 0) * (string.length - 1);
|
||||
},
|
||||
heightOfString: function(text, options) {
|
||||
var height, lineGap, ref, x, y;
|
||||
if (options == null) {
|
||||
options = {};
|
||||
}
|
||||
ref = this, x = ref.x, y = ref.y;
|
||||
options = this._initOptions(options);
|
||||
options.height = 2e308;
|
||||
lineGap = options.lineGap || this._lineGap || 0;
|
||||
this._text(text, this.x, this.y, options, (function(_this) {
|
||||
return function(line, options) {
|
||||
return _this.y += _this.currentLineHeight(true) + lineGap;
|
||||
};
|
||||
})(this));
|
||||
height = this.y - y;
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
return height;
|
||||
},
|
||||
list: function(list, x, y, options, wrapper) {
|
||||
var flatten, i, indent, itemIndent, items, level, levels, midLine, r;
|
||||
options = this._initOptions(x, y, options);
|
||||
midLine = Math.round((this._font.ascender / 1000 * this._fontSize) / 2);
|
||||
r = options.bulletRadius || Math.round((this._font.ascender / 1000 * this._fontSize) / 3);
|
||||
indent = options.textIndent || r * 5;
|
||||
itemIndent = options.bulletIndent || r * 8;
|
||||
level = 1;
|
||||
items = [];
|
||||
levels = [];
|
||||
flatten = function(list) {
|
||||
var i, item, j, len, results;
|
||||
results = [];
|
||||
for (i = j = 0, len = list.length; j < len; i = ++j) {
|
||||
item = list[i];
|
||||
if (Array.isArray(item)) {
|
||||
level++;
|
||||
flatten(item);
|
||||
results.push(level--);
|
||||
} else {
|
||||
items.push(item);
|
||||
results.push(levels.push(level));
|
||||
}
|
||||
}
|
||||
return results;
|
||||
};
|
||||
flatten(list);
|
||||
wrapper = new LineWrapper(this, options);
|
||||
wrapper.on('line', this._line.bind(this));
|
||||
level = 1;
|
||||
i = 0;
|
||||
wrapper.on('firstLine', (function(_this) {
|
||||
return function() {
|
||||
var diff, l;
|
||||
if ((l = levels[i++]) !== level) {
|
||||
diff = itemIndent * (l - level);
|
||||
_this.x += diff;
|
||||
wrapper.lineWidth -= diff;
|
||||
level = l;
|
||||
}
|
||||
_this.circle(_this.x - indent + r, _this.y + midLine, r);
|
||||
return _this.fill();
|
||||
};
|
||||
})(this));
|
||||
wrapper.on('sectionStart', (function(_this) {
|
||||
return function() {
|
||||
var pos;
|
||||
pos = indent + itemIndent * (level - 1);
|
||||
_this.x += pos;
|
||||
return wrapper.lineWidth -= pos;
|
||||
};
|
||||
})(this));
|
||||
wrapper.on('sectionEnd', (function(_this) {
|
||||
return function() {
|
||||
var pos;
|
||||
pos = indent + itemIndent * (level - 1);
|
||||
_this.x -= pos;
|
||||
return wrapper.lineWidth += pos;
|
||||
};
|
||||
})(this));
|
||||
wrapper.wrap(items.join('\n'), options);
|
||||
return this;
|
||||
},
|
||||
_initOptions: function(x, y, options) {
|
||||
var key, margins, ref, val;
|
||||
if (x == null) {
|
||||
x = {};
|
||||
}
|
||||
if (options == null) {
|
||||
options = {};
|
||||
}
|
||||
if (typeof x === 'object') {
|
||||
options = x;
|
||||
x = null;
|
||||
}
|
||||
options = (function() {
|
||||
var k, opts, v;
|
||||
opts = {};
|
||||
for (k in options) {
|
||||
v = options[k];
|
||||
opts[k] = v;
|
||||
}
|
||||
return opts;
|
||||
})();
|
||||
if (this._textOptions) {
|
||||
ref = this._textOptions;
|
||||
for (key in ref) {
|
||||
val = ref[key];
|
||||
if (key !== 'continued') {
|
||||
if (options[key] == null) {
|
||||
options[key] = val;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (x != null) {
|
||||
this.x = x;
|
||||
}
|
||||
if (y != null) {
|
||||
this.y = y;
|
||||
}
|
||||
if (options.lineBreak !== false) {
|
||||
margins = this.page.margins;
|
||||
if (options.width == null) {
|
||||
options.width = this.page.width - this.x - margins.right;
|
||||
}
|
||||
}
|
||||
options.columns || (options.columns = 0);
|
||||
if (options.columnGap == null) {
|
||||
options.columnGap = 18;
|
||||
}
|
||||
return options;
|
||||
},
|
||||
_line: function(text, options, wrapper) {
|
||||
var lineGap;
|
||||
if (options == null) {
|
||||
options = {};
|
||||
}
|
||||
this._fragment(text, this.x, this.y, options);
|
||||
lineGap = options.lineGap || this._lineGap || 0;
|
||||
if (!wrapper) {
|
||||
return this.x += this.widthOfString(text);
|
||||
} else {
|
||||
return this.y += this.currentLineHeight(true) + lineGap;
|
||||
}
|
||||
},
|
||||
_fragment: function(text, x, y, options) {
|
||||
var addSegment, align, base, characterSpacing, commands, d, encoded, encodedWord, flush, hadOffset, i, j, last, len, len1, lineWidth, lineY, m, mode, name, pos, positions, positionsWord, ref, ref1, renderedWidth, scale, spaceWidth, textWidth, word, wordSpacing, words;
|
||||
text = ('' + text).replace(/\n/g, '');
|
||||
if (text.length === 0) {
|
||||
return;
|
||||
}
|
||||
align = options.align || 'left';
|
||||
wordSpacing = options.wordSpacing || 0;
|
||||
characterSpacing = options.characterSpacing || 0;
|
||||
if (options.width) {
|
||||
switch (align) {
|
||||
case 'right':
|
||||
textWidth = this.widthOfString(text.replace(/\s+$/, ''), options);
|
||||
x += options.lineWidth - textWidth;
|
||||
break;
|
||||
case 'center':
|
||||
x += options.lineWidth / 2 - options.textWidth / 2;
|
||||
break;
|
||||
case 'justify':
|
||||
words = text.trim().split(/\s+/);
|
||||
textWidth = this.widthOfString(text.replace(/\s+/g, ''), options);
|
||||
spaceWidth = this.widthOfString(' ') + characterSpacing;
|
||||
wordSpacing = Math.max(0, (options.lineWidth - textWidth) / Math.max(1, words.length - 1) - spaceWidth);
|
||||
}
|
||||
}
|
||||
renderedWidth = options.textWidth + (wordSpacing * (options.wordCount - 1)) + (characterSpacing * (text.length - 1));
|
||||
if (options.link) {
|
||||
this.link(x, y, renderedWidth, this.currentLineHeight(), options.link);
|
||||
}
|
||||
if (options.underline || options.strike) {
|
||||
this.save();
|
||||
if (!options.stroke) {
|
||||
this.strokeColor.apply(this, this._fillColor);
|
||||
}
|
||||
lineWidth = this._fontSize < 10 ? 0.5 : Math.floor(this._fontSize / 10);
|
||||
this.lineWidth(lineWidth);
|
||||
d = options.underline ? 1 : 2;
|
||||
lineY = y + this.currentLineHeight() / d;
|
||||
if (options.underline) {
|
||||
lineY -= lineWidth;
|
||||
}
|
||||
this.moveTo(x, lineY);
|
||||
this.lineTo(x + renderedWidth, lineY);
|
||||
this.stroke();
|
||||
this.restore();
|
||||
}
|
||||
this.save();
|
||||
this.transform(1, 0, 0, -1, 0, this.page.height);
|
||||
y = this.page.height - y - (this._font.ascender / 1000 * this._fontSize);
|
||||
if ((base = this.page.fonts)[name = this._font.id] == null) {
|
||||
base[name] = this._font.ref();
|
||||
}
|
||||
this.addContent("BT");
|
||||
this.addContent("1 0 0 1 " + (number(x)) + " " + (number(y)) + " Tm");
|
||||
this.addContent("/" + this._font.id + " " + (number(this._fontSize)) + " Tf");
|
||||
mode = options.fill && options.stroke ? 2 : options.stroke ? 1 : 0;
|
||||
if (mode) {
|
||||
this.addContent(mode + " Tr");
|
||||
}
|
||||
if (characterSpacing) {
|
||||
this.addContent((number(characterSpacing)) + " Tc");
|
||||
}
|
||||
if (wordSpacing) {
|
||||
words = text.trim().split(/\s+/);
|
||||
wordSpacing += this.widthOfString(' ') + characterSpacing;
|
||||
wordSpacing *= 1000 / this._fontSize;
|
||||
encoded = [];
|
||||
positions = [];
|
||||
for (j = 0, len = words.length; j < len; j++) {
|
||||
word = words[j];
|
||||
ref = this._font.encode(word, options.features), encodedWord = ref[0], positionsWord = ref[1];
|
||||
encoded.push.apply(encoded, encodedWord);
|
||||
positions.push.apply(positions, positionsWord);
|
||||
positions[positions.length - 1].xAdvance += wordSpacing;
|
||||
}
|
||||
} else {
|
||||
ref1 = this._font.encode(text, options.features), encoded = ref1[0], positions = ref1[1];
|
||||
}
|
||||
scale = this._fontSize / 1000;
|
||||
commands = [];
|
||||
last = 0;
|
||||
hadOffset = false;
|
||||
addSegment = (function(_this) {
|
||||
return function(cur) {
|
||||
var advance, hex;
|
||||
if (last < cur) {
|
||||
hex = encoded.slice(last, cur).join('');
|
||||
advance = positions[cur - 1].xAdvance - positions[cur - 1].advanceWidth;
|
||||
commands.push("<" + hex + "> " + (number(-advance)));
|
||||
}
|
||||
return last = cur;
|
||||
};
|
||||
})(this);
|
||||
flush = (function(_this) {
|
||||
return function(i) {
|
||||
addSegment(i);
|
||||
if (commands.length > 0) {
|
||||
_this.addContent("[" + (commands.join(' ')) + "] TJ");
|
||||
return commands.length = 0;
|
||||
}
|
||||
};
|
||||
})(this);
|
||||
for (i = m = 0, len1 = positions.length; m < len1; i = ++m) {
|
||||
pos = positions[i];
|
||||
if (pos.xOffset || pos.yOffset) {
|
||||
flush(i);
|
||||
this.addContent("1 0 0 1 " + (number(x + pos.xOffset * scale)) + " " + (number(y + pos.yOffset * scale)) + " Tm");
|
||||
flush(i + 1);
|
||||
hadOffset = true;
|
||||
} else {
|
||||
if (hadOffset) {
|
||||
this.addContent("1 0 0 1 " + (number(x)) + " " + (number(y)) + " Tm");
|
||||
hadOffset = false;
|
||||
}
|
||||
if (pos.xAdvance - pos.advanceWidth !== 0) {
|
||||
addSegment(i + 1);
|
||||
}
|
||||
}
|
||||
x += pos.xAdvance * scale;
|
||||
}
|
||||
flush(i);
|
||||
this.addContent("ET");
|
||||
return this.restore();
|
||||
}
|
||||
};
|
||||
|
||||
}).call(this);
|
@ -0,0 +1,58 @@
|
||||
#lang pitfall/racket
|
||||
(provide annotation-mixin)
|
||||
|
||||
(define (annotation-mixin [% mixin-tester%])
|
||||
(class %
|
||||
(super-new)
|
||||
|
||||
(as-methods
|
||||
annotate
|
||||
link
|
||||
_convertRect)))
|
||||
|
||||
(define/contract (annotate this x y w h options)
|
||||
(number? number? number? number? hash? . ->m . object?)
|
||||
(hash-set*! options
|
||||
'Type "Annot"
|
||||
'Rect (send this _convertRect x y w h)
|
||||
'Border '(0 0 0))
|
||||
(hash-ref! options 'C
|
||||
(λ ()
|
||||
(unless (equal? (· options Subtype) "Link")
|
||||
(send this _normalizeColor (or (· options color) '(0 0 0))))))
|
||||
(hash-remove! options 'color)
|
||||
|
||||
(when (string? (· options Dest))
|
||||
(hash-update! options 'Dest (λ (val) (String val))))
|
||||
|
||||
(for ([(k v) (in-hash options)])
|
||||
(hash-set! options (string->symbol (string-titlecase (symbol->string k))) v))
|
||||
|
||||
(define ref (· this ref options))
|
||||
(push-field! annotations this ref)
|
||||
(· ref end)
|
||||
this)
|
||||
|
||||
|
||||
|
||||
(define/contract (link this x y w h url [options (mhash)])
|
||||
((number? number? number? number? string?) (hash?) . ->*m . object?)
|
||||
(hash-set! options 'Subtype "Link")
|
||||
(hash-set! options 'A (send this ref (mhash 'S "URI"
|
||||
'URI (String url))))
|
||||
(send (· options A) end)
|
||||
(send this annotate x y w h options))
|
||||
|
||||
|
||||
(define/contract (_convertRect this x1 y1 w h)
|
||||
(number? number? number? number? . ->m . (list/c number? number? number? number?))
|
||||
;; flip y1 and y2
|
||||
(let ([y2 y1]
|
||||
[y1 (+ y1 h)]
|
||||
[x2 (+ x1 w)])
|
||||
(match-define (list m0 m1 m2 m3 m4 m5) (· this _ctm))
|
||||
(list
|
||||
(+ (* x1 m0) (* y1 m2) m4)
|
||||
(+ (* x1 m1) (* y1 m3) m5)
|
||||
(+ (* x2 m0) (* y2 m2) m4)
|
||||
(+ (* x2 m1) (* y2 m3) m5))))
|
@ -0,0 +1,14 @@
|
||||
PDFDocument = require 'pdfkit'
|
||||
fs = require 'fs'
|
||||
|
||||
make = (doc) ->
|
||||
# Add some text with annotations
|
||||
doc.fillColor("blue")
|
||||
.font('Helvetica', 30)
|
||||
.text('Here is a link!', 100, 100, { link: 'http://google.com/', underline: true })
|
||||
|
||||
doc.end()
|
||||
|
||||
doc = new PDFDocument({compress: yes})
|
||||
doc.pipe(fs.createWriteStream('test11c.pdf'))
|
||||
make doc
|
@ -1,15 +1,12 @@
|
||||
#lang pitfall/pdftest
|
||||
|
||||
(define (proc doc)
|
||||
(send doc translate 200 300)
|
||||
(send* doc [path "M 0 0 v 100 h 100 v -100 h -100"]
|
||||
[stroke])
|
||||
|
||||
(send doc translate 0 150)
|
||||
(send* doc [path "M 0 0 l 0 100 l 100 0 l 0 -100 l -100 0"]
|
||||
[stroke]))
|
||||
|
||||
|
||||
(send* doc
|
||||
[fillColor "blue"]
|
||||
[font "Helvetica" 30]
|
||||
[text "Here is a link!" 100 100 (hash
|
||||
'link "http://google.com/"
|
||||
'underline #t)]))
|
||||
|
||||
(define-runtime-path that "test11crkt.pdf")
|
||||
(make-doc that #t proc #:test #f)
|
||||
|
Binary file not shown.
@ -1,83 +0,0 @@
|
||||
%PDF-1.3
|
||||
%ÿÿÿÿ
|
||||
5 0 obj
|
||||
<<
|
||||
/Parent 1 0 R
|
||||
/Resources 4 0 R
|
||||
/Contents 3 0 R
|
||||
/MediaBox [0 0 612 792]
|
||||
/Type /Page
|
||||
>>
|
||||
endobj
|
||||
4 0 obj
|
||||
<<
|
||||
/Font <<
|
||||
/F1 6 0 R
|
||||
>>
|
||||
/ProcSet [/PDF /Text /ImageB /ImageC /ImageI]
|
||||
>>
|
||||
endobj
|
||||
3 0 obj
|
||||
<<
|
||||
/Length 123
|
||||
>>
|
||||
stream
|
||||
1 0 0 -1 0 792 cm
|
||||
q
|
||||
1 0 0 -1 0 792 cm
|
||||
BT
|
||||
1 0 0 1 72 711.384 Tm
|
||||
/F1 12 Tf
|
||||
[<48656c6c6f2077> 10 <6f72> -15 <6c64> 0] TJ
|
||||
ET
|
||||
Q
|
||||
|
||||
endstream
|
||||
endobj
|
||||
7 0 obj
|
||||
<<
|
||||
/CreationDate (D:19700101000000Z)
|
||||
/Creator (PITKIT)
|
||||
/Producer (PITKIT)
|
||||
>>
|
||||
endobj
|
||||
6 0 obj
|
||||
<<
|
||||
/BaseFont /Helvetica
|
||||
/Encoding /WinAnsiEncoding
|
||||
/Subtype /Type1
|
||||
/Type /Font
|
||||
>>
|
||||
endobj
|
||||
2 0 obj
|
||||
<<
|
||||
/Pages 1 0 R
|
||||
/Type /Catalog
|
||||
>>
|
||||
endobj
|
||||
1 0 obj
|
||||
<<
|
||||
/Kids [5 0 R]
|
||||
/Count 1
|
||||
/Type /Pages
|
||||
>>
|
||||
endobj
|
||||
xref
|
||||
0 8
|
||||
0000000000 65535 f
|
||||
0000000620 00000 n
|
||||
0000000571 00000 n
|
||||
0000000208 00000 n
|
||||
0000000119 00000 n
|
||||
0000000015 00000 n
|
||||
0000000474 00000 n
|
||||
0000000382 00000 n
|
||||
trailer
|
||||
<<
|
||||
/Info 7 0 R
|
||||
/Root 2 0 R
|
||||
/Size 8
|
||||
>>
|
||||
startxref
|
||||
677
|
||||
%%EOF
|
Loading…
Reference in New Issue