Skip to content

Commit 10caf31

Browse files
author
Kenneth Glassey
committed
Resolved conflict with strokeoption
2 parents b84c743 + 2204746 commit 10caf31

11 files changed

+1868
-5
lines changed

jspdf.js

Lines changed: 96 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
* 2014 Juan Pablo Gaviria, https://github.com/juanpgaviria
1818
* 2014 James Makes, https://github.com/dollaruw
1919
* 2014 Diego Casorran, https://github.com/diegocr
20+
* 2014 Steven Spungin, https://github.com/Flamenco
2021
*
2122
* Permission is hereby granted, free of charge, to any person obtaining
2223
* a copy of this software and associated documentation files (the
@@ -39,7 +40,7 @@
3940
*
4041
* Contributor(s):
4142
* siefkenj, ahwolf, rickygu, Midnith, saintclair, eaparango,
42-
* kim3er, mfo, alnorth,
43+
* kim3er, mfo, alnorth, Flamenco
4344
*/
4445

4546
/**
@@ -198,6 +199,7 @@ var jsPDF = (function(global) {
198199
},
199200
API = {},
200201
events = new PubSub(API),
202+
lastTextWasStroke = false,
201203

202204
/////////////////////
203205
// Private functions
@@ -228,6 +230,17 @@ var jsPDF = (function(global) {
228230
out(objectNumber + ' 0 obj');
229231
return objectNumber;
230232
},
233+
// Does not output the object. The caller must call newObjectDeferredBegin(oid) before outputing any data
234+
newObjectDeferred = function() {
235+
objectNumber++;
236+
offsets[objectNumber] = function(){
237+
return content_length;
238+
};
239+
return objectNumber;
240+
},
241+
newObjectDeferredBegin = function(oid) {
242+
offsets[oid] = content_length;
243+
},
231244
putStream = function(str) {
232245
out('stream');
233246
out(str);
@@ -251,7 +264,10 @@ var jsPDF = (function(global) {
251264
out('/Parent 1 0 R');
252265
out('/Resources 2 0 R');
253266
out('/MediaBox [0 0 ' + f2(wPt) + ' ' + f2(hPt) + ']');
254-
out('/Contents ' + (objectNumber + 1) + ' 0 R>>');
267+
out('/Contents ' + (objectNumber + 1) + ' 0 R');
268+
// Added for annotation plugin
269+
events.publish('putPage', {pageNumber:n,page:pages[n]});
270+
out('>>');
255271
out('endobj');
256272

257273
// Page content
@@ -766,7 +782,12 @@ var jsPDF = (function(global) {
766782
out('0 ' + (objectNumber + 1));
767783
out(p+' 65535 f ');
768784
for (i = 1; i <= objectNumber; i++) {
769-
out((p + offsets[i]).slice(-10) + ' 00000 n ');
785+
var offset = offsets[i];
786+
if (typeof offset === 'function'){
787+
out((p + offsets[i]()).slice(-10) + ' 00000 n ');
788+
}else{
789+
out((p + offsets[i]).slice(-10) + ' 00000 n ');
790+
}
770791
}
771792
// Trailer
772793
out('trailer');
@@ -918,6 +939,8 @@ var jsPDF = (function(global) {
918939
},
919940
'collections' : {},
920941
'newObject' : newObject,
942+
'newObjectDeferred' : newObjectDeferred,
943+
'newObjectDeferredBegin' : newObjectDeferredBegin,
921944
'putStream' : putStream,
922945
'events' : events,
923946
// ratio that you use in multiplication of a given "size" number to arrive to 'point'
@@ -941,7 +964,17 @@ var jsPDF = (function(global) {
941964
'getNumberOfPages' : function() {
942965
return pages.length - 1;
943966
},
944-
'pages' : pages
967+
'pages' : pages,
968+
'out' : out,
969+
'f2' : f2,
970+
'getPageInfo' : function(pageNumberOneBased){
971+
var objId = (pageNumberOneBased - 1) * 2 + 3;
972+
return {objId:objId, pageNumber:pageNumberOneBased};
973+
},
974+
'getCurrentPageInfo' : function(){
975+
var objId = (currentPage - 1) * 2 + 3;
976+
return {objId:objId, pageNumber:currentPage};
977+
}
945978
};
946979

947980
/**
@@ -960,6 +993,47 @@ var jsPDF = (function(global) {
960993
_setPage.apply(this, arguments);
961994
return this;
962995
};
996+
API.insertPage = function(beforePage) {
997+
this.addPage();
998+
this.movePage(currentPage, beforePage);
999+
return this;
1000+
};
1001+
API.movePage = function(targetPage, beforePage) {
1002+
if (targetPage > beforePage){
1003+
var tmpPages = pages[targetPage];
1004+
var tmpPagedim = pagedim[targetPage];
1005+
for (var i=targetPage; i>beforePage; i--){
1006+
pages[i] = pages[i-1];
1007+
pagedim[i] = pagedim[i-1];
1008+
}
1009+
pages[beforePage] = tmpPages;
1010+
pagedim[beforePage] = tmpPagedim;
1011+
this.setPage(beforePage);
1012+
}else if (targetPage < beforePage){
1013+
var tmpPages = pages[targetPage];
1014+
var tmpPagedim = pagedim[targetPage];
1015+
for (var i=targetPage; i<beforePage; i++){
1016+
pages[i] = pages[i+1];
1017+
pagedim[i] = pagedim[i+1];
1018+
}
1019+
pages[beforePage] = tmpPages;
1020+
pagedim[beforePage] = tmpPagedim;
1021+
this.setPage(beforePage);
1022+
}
1023+
return this;
1024+
};
1025+
API.deletePage = function(targetPage) {
1026+
for (var i=targetPage; i< page; i++){
1027+
pages[i] = pages[i+1];
1028+
pagedim[i] = pagedim[i+1];
1029+
}
1030+
page--;
1031+
if (currentPage > page){
1032+
currentPage = page;
1033+
}
1034+
this.setPage(currentPage);
1035+
return this;
1036+
};
9631037
API.setDisplayMode = function(zoom, layout, pmode) {
9641038
zoomMode = zoom;
9651039
layoutMode = layout;
@@ -1047,7 +1121,23 @@ var jsPDF = (function(global) {
10471121
flags.noBOM = true;
10481122
if (!('autoencode' in flags))
10491123
flags.autoencode = true;
1050-
1124+
1125+
//TODO this might not work after object block changes
1126+
// It would be better to pass in a page context
1127+
var strokeOption = '';
1128+
if (true === flags.stroke){
1129+
if (this.lastTextWasStroke !== true){
1130+
strokeOption = '1 Tr\n';
1131+
this.lastTextWasStroke = true;
1132+
}
1133+
}
1134+
else{
1135+
if (this.lastTextWasStroke){
1136+
strokeOption = '0 Tr\n';
1137+
}
1138+
this.lastTextWasStroke = false;
1139+
}
1140+
10511141
if (text instanceof Array) {
10521142
// we don't want to destroy original text array, so cloning it
10531143
var sa = text.concat(), da = [], i, len = sa.length;
@@ -1108,6 +1198,7 @@ var jsPDF = (function(global) {
11081198
'BT\n/' +
11091199
activeFontKey + ' ' + activeFontSize + ' Tf\n' + // font face, style, size
11101200
(activeFontSize * lineHeightProportion) + ' TL\n' + // line spacing
1201+
strokeOption +// stroke option
11111202
textColor +
11121203
'\n' + xtra + f2(x * k) + ' ' + f2((pageHeight - y) * k) + ' ' + mode + '\n(' +
11131204
text +

jspdf.plugin.annotations.js

Lines changed: 197 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,197 @@
1+
/**
2+
* jsPDF Annotations PlugIn
3+
* Copyright (c) 2014 Steven Spungin (TwelveTone LLC) [email protected]
4+
*
5+
* Licensed under the MIT License.
6+
* http://opensource.org/licenses/mit-license
7+
*/
8+
9+
/**
10+
* There are many types of annotations in a PDF document. Annotations are placed
11+
* on a page at a particular location. They are not 'attached' to an object.
12+
* <br />
13+
* This plugin current supports <br />
14+
* <li> Goto Page (set pageNumber in options)
15+
* <li> Goto URL (set url in options)
16+
* <p>
17+
* The destination magnification factor can also be specified when goto is a page number or a named destination. (see documentation below)
18+
* (set magFactor in options). XYZ is the default.
19+
* </p>
20+
* <p>
21+
* Options In PDF spec Not Implemented Yet
22+
* <li> link border
23+
* <li> named target
24+
* <li> page coordinates
25+
* <li> destination page scaling and layout
26+
* <li> actions other than URL and GotoPage
27+
* <li> background / hover actions
28+
* </p>
29+
*/
30+
31+
/*
32+
Destination Magnification Factors
33+
See PDF 1.3 Page 386 for meanings and options
34+
35+
[supported]
36+
XYZ (options; left top zoom)
37+
Fit (no options)
38+
FitH (options: top)
39+
FitV (options: left)
40+
41+
[not supported]
42+
FitR
43+
FitB
44+
FitBH
45+
FitBV
46+
*/
47+
48+
(function(jsPDFAPI) {
49+
'use strict';
50+
51+
var annotationPlugin = {
52+
53+
/**
54+
* An array of arrays, indexed by <em>pageNumber</em>.
55+
*/
56+
annotations : [],
57+
58+
f2 : function(number) {
59+
return number.toFixed(2);
60+
},
61+
62+
notEmpty : function(obj) {
63+
if (typeof obj != 'undefined') {
64+
if (obj != '') {
65+
return true;
66+
}
67+
}
68+
}
69+
};
70+
71+
jsPDF.API.annotationPlugin = annotationPlugin;
72+
73+
jsPDF.API.events.push([
74+
'addPage', function(info) {
75+
this.annotationPlugin.annotations[info.pageNumber] = [];
76+
}
77+
]);
78+
79+
jsPDFAPI.events.push([
80+
'putPage', function(info) {
81+
var pageAnnos = this.annotationPlugin.annotations[info.pageNumber];
82+
83+
var found = false;
84+
for (var a = 0; a < pageAnnos.length; a++) {
85+
var anno = pageAnnos[a];
86+
if (anno.type === 'link') {
87+
if (annotationPlugin.notEmpty(anno.options.url) || annotationPlugin.notEmpty(anno.options.pageNumber)) {
88+
found = true;
89+
break;
90+
}
91+
}
92+
}
93+
if (found == false) {
94+
return;
95+
}
96+
97+
this.internal.write("/Annots [");
98+
var f2 = this.annotationPlugin.f2;
99+
for (var a = 0; a < pageAnnos.length; a++) {
100+
var anno = pageAnnos[a];
101+
102+
var k = this.internal.scaleFactor;
103+
var pageHeight = this.internal.pageSize.height;
104+
//var pageHeight = this.internal.pageSize.height * this.internal.scaleFactor;
105+
var rect = "/Rect [" + f2(anno.x * k) + " " + f2((pageHeight - anno.y) * k) + " " + f2(anno.x + anno.w * k) + " " + f2(pageHeight - (anno.y + anno.h) * k) + "] ";
106+
107+
var line = '';
108+
if (anno.options.url) {
109+
line = '<</Type /Annot /Subtype /Link ' + rect + '/Border [0 0 0] /A <</S /URI /URI (' + anno.options.url + ') >>';
110+
} else if (anno.options.pageNumber) {
111+
// first page is 0
112+
var info = this.internal.getPageInfo(anno.options.pageNumber);
113+
line = '<</Type /Annot /Subtype /Link ' + rect + '/Border [0 0 0] /Dest [' + info.objId + " 0 R";
114+
anno.options.magFactor = anno.options.magFactor || "XYZ";
115+
switch (anno.options.magFactor) {
116+
case 'Fit':
117+
line += ' /Fit]';
118+
break;
119+
case 'FitH':
120+
anno.options.top = anno.options.top || f2(pageHeight * k);
121+
line += ' /FitH ' + anno.options.top + ']';
122+
break;
123+
case 'FitV':
124+
anno.options.left = anno.options.left || 0;
125+
line += ' /FitV ' + anno.options.left + ']';
126+
break;
127+
case 'XYZ':
128+
default:
129+
anno.options.top = anno.options.top || f2(pageHeight * k);
130+
anno.options.left = anno.options.left || 0;
131+
// 0 or null zoom will not change zoom factor
132+
if (typeof anno.options.zoom === 'undefined'){
133+
anno.options.zoom = 0;
134+
}
135+
line += ' /XYZ ' + anno.options.left + ' ' + anno.options.top + ' ' + anno.options.zoom + ']';
136+
break;
137+
}
138+
} else {
139+
// TODO error - should not be here
140+
}
141+
if (line != '') {
142+
line += " >>";
143+
this.internal.write(line);
144+
}
145+
}
146+
this.internal.write("]");
147+
}
148+
]);
149+
150+
/**
151+
* valid options
152+
* <li> pageNumber or url [required]
153+
*/
154+
jsPDFAPI.link = function(x,y,w,h,options) {
155+
'use strict';
156+
this.annotationPlugin.annotations[this.internal.getCurrentPageInfo().pageNumber].push({
157+
x : x,
158+
y : y,
159+
w : w,
160+
h : h,
161+
options : options,
162+
type : 'link'
163+
});
164+
};
165+
166+
/**
167+
* Currently only supports single line text.
168+
* Returns the width of the text/link
169+
*/
170+
jsPDFAPI.textWithLink = function(text,x,y,options) {
171+
'use strict';
172+
var width = this.getTextWidth(text);
173+
var height = this.internal.getLineHeight();
174+
this.text(text, x, y);
175+
//TODO We really need the text baseline height to do this correctly.
176+
// Or ability to draw text on top, bottom, center, or baseline.
177+
y += height * .2;
178+
this.link(x, y - height, width, height, options);
179+
return width;
180+
};
181+
182+
//TODO move into external library
183+
jsPDFAPI.getTextWidth = function(text) {
184+
'use strict';
185+
var fontSize = this.internal.getFontSize();
186+
var txtWidth = this.getStringUnitWidth(text) * fontSize / this.internal.scaleFactor;
187+
return txtWidth;
188+
};
189+
190+
//TODO move into external library
191+
jsPDFAPI.getLineHeight = function() {
192+
return this.internal.getLineHeight();
193+
};
194+
195+
return this;
196+
197+
})(jsPDF.API);

0 commit comments

Comments
 (0)