@@ -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+
105199Pdf . displayName = 'react-pdf-js' ;
106200Pdf . 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