Skip to content

Commit 12098f0

Browse files
committed
Merge branch 'pr/2'
Conflicts: src/Pdf.js
2 parents bced083 + 167f0cd commit 12098f0

File tree

2 files changed

+104
-4
lines changed

2 files changed

+104
-4
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,5 @@ dist
44
lib
55
npm-debug.log
66
.DS_Store
7+
/.idea/
8+
/react-pdf-js.iml

src/Pdf.js

Lines changed: 102 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ class Pdf extends React.Component {
55
constructor(props) {
66
super(props);
77
this.state = {};
8+
this.onGetPdfRaw = this.onGetPdfRaw.bind(this);
89
this.onDocumentComplete = this.onDocumentComplete.bind(this);
910
this.onPageComplete = this.onPageComplete.bind(this);
1011
}
@@ -20,10 +21,19 @@ class Pdf extends React.Component {
2021
const newDocInit = newProps.documentInitParameters;
2122
const docInit = this.props.documentInitParameters;
2223

23-
if ((newProps.file && newProps.file !== this.props.file) ||
24+
// Only reload if the most significant source has changed!
25+
let newSource = newProps.file;
26+
let oldSource = newSource ? this.props.file : null;
27+
newSource = newSource || newProps.binaryContent;
28+
oldSource = newSource && !oldSource ? this.props.binaryContent : oldSource;
29+
newSource = newSource || newProps.content;
30+
oldSource = newSource && !oldSource ? this.props.content : oldSource;
31+
32+
if (newSource && newSource !== oldSource &&
33+
((newProps.file && newProps.file !== this.props.file) ||
2434
(newProps.content && newProps.content !== this.props.content) ||
2535
(newDocInit && newDocInit !== docInit) ||
26-
(newDocInit && docInit && newDocInit.url !== docInit.url)) {
36+
(newDocInit && docInit && newDocInit.url !== docInit.url))) {
2737
this.loadPDFDocument(newProps);
2838
}
2939

@@ -34,12 +44,34 @@ class Pdf extends React.Component {
3444
}
3545
}
3646

47+
componentWillUnmount() {
48+
const { pdf } = this.state;
49+
pdf.destroy();
50+
}
51+
52+
onGetPdfRaw(pdfRaw) {
53+
const { onContentAvailable, onBinaryContentAvailable, binaryToBase64 } = this.props;
54+
if (typeof onBinaryContentAvailable === 'function') {
55+
onBinaryContentAvailable(pdfRaw);
56+
}
57+
if (typeof onContentAvailable === 'function') {
58+
let convertBinaryToBase64 = this.defaultBinaryToBase64;
59+
if (typeof binaryToBase64 === 'function') {
60+
convertBinaryToBase64 = binaryToBase64;
61+
}
62+
onContentAvailable(convertBinaryToBase64(pdfRaw));
63+
}
64+
}
65+
3766
onDocumentComplete(pdf) {
3867
this.setState({ pdf });
39-
const { onDocumentComplete } = this.props;
68+
const { onDocumentComplete, onContentAvailable, onBinaryContentAvailable } = this.props;
4069
if (typeof onDocumentComplete === 'function') {
4170
onDocumentComplete(pdf.numPages);
4271
}
72+
if (typeof onContentAvailable === 'function' || typeof onBinaryContentAvailable === 'function') {
73+
pdf.getData().then(this.onGetPdfRaw);
74+
}
4375
pdf.getPage(this.props.page).then(this.onPageComplete);
4476
}
4577

@@ -67,6 +99,8 @@ class Pdf extends React.Component {
6799
reader.onloadend = () =>
68100
this.loadByteArray(new Uint8Array(reader.result));
69101
reader.readAsArrayBuffer(props.file);
102+
} else if (props.binaryContent) {
103+
this.loadByteArray(props.binaryContent);
70104
} else if (!!props.content) {
71105
const bytes = window.atob(props.content);
72106
const byteLength = bytes.length;
@@ -83,6 +117,65 @@ class Pdf extends React.Component {
83117
}
84118
}
85119

120+
// Converts an ArrayBuffer directly to base64, without any intermediate 'convert to string then
121+
// use window.btoa' step and without risking a blow of the stack. According to [Jon Leightons's]
122+
// tests, this appears to be a faster approach: http://jsperf.com/encoding-xhr-image-data/5
123+
// Jon Leighton https://gist.github.com/jonleighton/958841
124+
defaultBinaryToBase64(arrayBuffer) {
125+
let base64 = '';
126+
const encodings = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
127+
128+
const bytes = new Uint8Array(arrayBuffer);
129+
const byteLength = bytes.byteLength;
130+
const byteRemainder = byteLength % 3;
131+
const mainLength = byteLength - byteRemainder;
132+
133+
let a;
134+
let b;
135+
let c;
136+
let d;
137+
let chunk;
138+
139+
// Main loop deals with bytes in chunks of 3
140+
for (let i = 0; i < mainLength; i = i + 3) {
141+
// Combine the three bytes into a single integer
142+
chunk = (bytes[i] << 16) | (bytes[i + 1] << 8) | bytes[i + 2];
143+
144+
// Use bitmasks to extract 6-bit segments from the triplet
145+
a = (chunk & 16515072) >> 18; // 16515072 = (2^6 - 1) << 18
146+
b = (chunk & 258048) >> 12; // 258048 = (2^6 - 1) << 12
147+
c = (chunk & 4032) >> 6; // 4032 = (2^6 - 1) << 6
148+
d = chunk & 63; // 63 = 2^6 - 1
149+
150+
// Convert the raw binary segments to the appropriate ASCII encoding
151+
base64 = [base64, encodings[a], encodings[b], encodings[c], encodings[d]].join('');
152+
}
153+
154+
// Deal with the remaining bytes and padding
155+
if (byteRemainder === 1) {
156+
chunk = bytes[mainLength];
157+
158+
a = (chunk & 252) >> 2; // 252 = (2^6 - 1) << 2
159+
160+
// Set the 4 least significant bits to zero
161+
b = (chunk & 3) << 4; // 3 = 2^2 - 1
162+
163+
base64 = [base64, encodings[a], encodings[b], '=='].join('');
164+
} else if (byteRemainder === 2) {
165+
chunk = (bytes[mainLength] << 8) | bytes[mainLength + 1];
166+
167+
a = (chunk & 64512) >> 10; // 64512 = (2^6 - 1) << 10
168+
b = (chunk & 1008) >> 4; // 1008 = (2^6 - 1) << 4
169+
170+
// Set the 2 least significant bits to zero
171+
c = (chunk & 15) << 2; // 15 = 2^4 - 1
172+
173+
base64 = [base64, encodings[a], encodings[b], encodings[c], '='].join('');
174+
}
175+
176+
return base64;
177+
}
178+
86179
renderPdf() {
87180
const { page } = this.state;
88181
if (page) {
@@ -102,14 +195,19 @@ class Pdf extends React.Component {
102195
return page ? <canvas ref="canvas" /> : loading || <div>Loading PDF...</div>;
103196
}
104197
}
198+
105199
Pdf.displayName = 'react-pdf-js';
106200
Pdf.propTypes = {
107201
content: React.PropTypes.string,
108-
file: React.PropTypes.string,
109202
documentInitParameters: React.PropTypes.object,
203+
binaryContent: React.PropTypes.object,
204+
file: React.PropTypes.any, // Could be File object or URL string.
110205
loading: React.PropTypes.any,
111206
page: React.PropTypes.number,
112207
scale: React.PropTypes.number,
208+
onContentAvailable: React.PropTypes.func,
209+
onBinaryContentAvailable: React.PropTypes.func.isRequired,
210+
binaryToBase64: React.PropTypes.func,
113211
onDocumentComplete: React.PropTypes.func,
114212
onPageComplete: React.PropTypes.func,
115213
};

0 commit comments

Comments
 (0)