-
Notifications
You must be signed in to change notification settings - Fork 1.2k
/
Copy pathobject.js
134 lines (115 loc) · 3.59 KB
/
object.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
/*
PDFObject - converts JavaScript types into their corresponding PDF types.
By Devon Govett
*/
import PDFAbstractReference from './abstract_reference';
import PDFTree from './tree';
import SpotColor from './spotcolor';
const pad = (str, length) => (Array(length + 1).join('0') + str).slice(-length);
const escapableRe = /[\n\r\t\b\f()\\]/g;
const escapable = {
'\n': '\\n',
'\r': '\\r',
'\t': '\\t',
'\b': '\\b',
'\f': '\\f',
'\\': '\\\\',
'(': '\\(',
')': '\\)'
};
// Convert little endian UTF-16 to big endian
const swapBytes = function(buff) {
const l = buff.length;
if (l & 0x01) {
throw new Error('Buffer length must be even');
} else {
for (let i = 0, end = l - 1; i < end; i += 2) {
const a = buff[i];
buff[i] = buff[i + 1];
buff[i + 1] = a;
}
}
return buff;
};
class PDFObject {
static convert(object, encryptFn = null) {
// String literals are converted to the PDF name type
if (typeof object === 'string') {
return `/${object}`;
// String objects are converted to PDF strings (UTF-16)
} else if (object instanceof String) {
let string = object;
// Detect if this is a unicode string
let isUnicode = false;
for (let i = 0, end = string.length; i < end; i++) {
if (string.charCodeAt(i) > 0x7f) {
isUnicode = true;
break;
}
}
// If so, encode it as big endian UTF-16
let stringBuffer;
if (isUnicode) {
stringBuffer = swapBytes(Buffer.from(`\ufeff${string}`, 'utf16le'));
} else {
stringBuffer = Buffer.from(string.valueOf(), 'ascii');
}
// Encrypt the string when necessary
if (encryptFn) {
string = encryptFn(stringBuffer).toString('binary');
} else {
string = stringBuffer.toString('binary');
}
// Escape characters as required by the spec
string = string.replace(escapableRe, c => escapable[c]);
return `(${string})`;
// Buffers are converted to PDF hex strings
} else if (Buffer.isBuffer(object)) {
return `<${object.toString('hex')}>`;
} else if (
object instanceof PDFAbstractReference ||
object instanceof PDFTree ||
object instanceof SpotColor
) {
return object.toString();
} else if (object instanceof Date) {
let string =
`D:${pad(object.getUTCFullYear(), 4)}` +
pad(object.getUTCMonth() + 1, 2) +
pad(object.getUTCDate(), 2) +
pad(object.getUTCHours(), 2) +
pad(object.getUTCMinutes(), 2) +
pad(object.getUTCSeconds(), 2) +
'Z';
// Encrypt the string when necessary
if (encryptFn) {
string = encryptFn(Buffer.from(string, 'ascii')).toString('binary');
// Escape characters as required by the spec
string = string.replace(escapableRe, c => escapable[c]);
}
return `(${string})`;
} else if (Array.isArray(object)) {
const items = object.map(e => PDFObject.convert(e, encryptFn)).join(' ');
return `[${items}]`;
} else if ({}.toString.call(object) === '[object Object]') {
const out = ['<<'];
for (let key in object) {
const val = object[key];
out.push(`/${key} ${PDFObject.convert(val, encryptFn)}`);
}
out.push('>>');
return out.join('\n');
} else if (typeof object === 'number') {
return PDFObject.number(object);
} else {
return `${object}`;
}
}
static number(n) {
if (n > -1e21 && n < 1e21) {
return Math.round(n * 1e6) / 1e6;
}
throw new Error(`unsupported number: ${n}`);
}
}
export default PDFObject;