1
+ /*
2
+ * Simple png decoder
3
+ * https://github.com/b37t1td/png-decoder
4
+ */
5
+
6
+ var CRCTable = new Int32Array ( [
7
+ 0x00000000 , 0x77073096 , 0xee0e612c , 0x990951ba , 0x076dc419 , 0x706af48f ,
8
+ 0xe963a535 , 0x9e6495a3 , 0x0edb8832 , 0x79dcb8a4 , 0xe0d5e91e , 0x97d2d988 ,
9
+ 0x09b64c2b , 0x7eb17cbd , 0xe7b82d07 , 0x90bf1d91 , 0x1db71064 , 0x6ab020f2 ,
10
+ 0xf3b97148 , 0x84be41de , 0x1adad47d , 0x6ddde4eb , 0xf4d4b551 , 0x83d385c7 ,
11
+ 0x136c9856 , 0x646ba8c0 , 0xfd62f97a , 0x8a65c9ec , 0x14015c4f , 0x63066cd9 ,
12
+ 0xfa0f3d63 , 0x8d080df5 , 0x3b6e20c8 , 0x4c69105e , 0xd56041e4 , 0xa2677172 ,
13
+ 0x3c03e4d1 , 0x4b04d447 , 0xd20d85fd , 0xa50ab56b , 0x35b5a8fa , 0x42b2986c ,
14
+ 0xdbbbc9d6 , 0xacbcf940 , 0x32d86ce3 , 0x45df5c75 , 0xdcd60dcf , 0xabd13d59 ,
15
+ 0x26d930ac , 0x51de003a , 0xc8d75180 , 0xbfd06116 , 0x21b4f4b5 , 0x56b3c423 ,
16
+ 0xcfba9599 , 0xb8bda50f , 0x2802b89e , 0x5f058808 , 0xc60cd9b2 , 0xb10be924 ,
17
+ 0x2f6f7c87 , 0x58684c11 , 0xc1611dab , 0xb6662d3d , 0x76dc4190 , 0x01db7106 ,
18
+ 0x98d220bc , 0xefd5102a , 0x71b18589 , 0x06b6b51f , 0x9fbfe4a5 , 0xe8b8d433 ,
19
+ 0x7807c9a2 , 0x0f00f934 , 0x9609a88e , 0xe10e9818 , 0x7f6a0dbb , 0x086d3d2d ,
20
+ 0x91646c97 , 0xe6635c01 , 0x6b6b51f4 , 0x1c6c6162 , 0x856530d8 , 0xf262004e ,
21
+ 0x6c0695ed , 0x1b01a57b , 0x8208f4c1 , 0xf50fc457 , 0x65b0d9c6 , 0x12b7e950 ,
22
+ 0x8bbeb8ea , 0xfcb9887c , 0x62dd1ddf , 0x15da2d49 , 0x8cd37cf3 , 0xfbd44c65 ,
23
+ 0x4db26158 , 0x3ab551ce , 0xa3bc0074 , 0xd4bb30e2 , 0x4adfa541 , 0x3dd895d7 ,
24
+ 0xa4d1c46d , 0xd3d6f4fb , 0x4369e96a , 0x346ed9fc , 0xad678846 , 0xda60b8d0 ,
25
+ 0x44042d73 , 0x33031de5 , 0xaa0a4c5f , 0xdd0d7cc9 , 0x5005713c , 0x270241aa ,
26
+ 0xbe0b1010 , 0xc90c2086 , 0x5768b525 , 0x206f85b3 , 0xb966d409 , 0xce61e49f ,
27
+ 0x5edef90e , 0x29d9c998 , 0xb0d09822 , 0xc7d7a8b4 , 0x59b33d17 , 0x2eb40d81 ,
28
+ 0xb7bd5c3b , 0xc0ba6cad , 0xedb88320 , 0x9abfb3b6 , 0x03b6e20c , 0x74b1d29a ,
29
+ 0xead54739 , 0x9dd277af , 0x04db2615 , 0x73dc1683 , 0xe3630b12 , 0x94643b84 ,
30
+ 0x0d6d6a3e , 0x7a6a5aa8 , 0xe40ecf0b , 0x9309ff9d , 0x0a00ae27 , 0x7d079eb1 ,
31
+ 0xf00f9344 , 0x8708a3d2 , 0x1e01f268 , 0x6906c2fe , 0xf762575d , 0x806567cb ,
32
+ 0x196c3671 , 0x6e6b06e7 , 0xfed41b76 , 0x89d32be0 , 0x10da7a5a , 0x67dd4acc ,
33
+ 0xf9b9df6f , 0x8ebeeff9 , 0x17b7be43 , 0x60b08ed5 , 0xd6d6a3e8 , 0xa1d1937e ,
34
+ 0x38d8c2c4 , 0x4fdff252 , 0xd1bb67f1 , 0xa6bc5767 , 0x3fb506dd , 0x48b2364b ,
35
+ 0xd80d2bda , 0xaf0a1b4c , 0x36034af6 , 0x41047a60 , 0xdf60efc3 , 0xa867df55 ,
36
+ 0x316e8eef , 0x4669be79 , 0xcb61b38c , 0xbc66831a , 0x256fd2a0 , 0x5268e236 ,
37
+ 0xcc0c7795 , 0xbb0b4703 , 0x220216b9 , 0x5505262f , 0xc5ba3bbe , 0xb2bd0b28 ,
38
+ 0x2bb45a92 , 0x5cb36a04 , 0xc2d7ffa7 , 0xb5d0cf31 , 0x2cd99e8b , 0x5bdeae1d ,
39
+ 0x9b64c2b0 , 0xec63f226 , 0x756aa39c , 0x026d930a , 0x9c0906a9 , 0xeb0e363f ,
40
+ 0x72076785 , 0x05005713 , 0x95bf4a82 , 0xe2b87a14 , 0x7bb12bae , 0x0cb61b38 ,
41
+ 0x92d28e9b , 0xe5d5be0d , 0x7cdcefb7 , 0x0bdbdf21 , 0x86d3d2d4 , 0xf1d4e242 ,
42
+ 0x68ddb3f8 , 0x1fda836e , 0x81be16cd , 0xf6b9265b , 0x6fb077e1 , 0x18b74777 ,
43
+ 0x88085ae6 , 0xff0f6a70 , 0x66063bca , 0x11010b5c , 0x8f659eff , 0xf862ae69 ,
44
+ 0x616bffd3 , 0x166ccf45 , 0xa00ae278 , 0xd70dd2ee , 0x4e048354 , 0x3903b3c2 ,
45
+ 0xa7672661 , 0xd06016f7 , 0x4969474d , 0x3e6e77db , 0xaed16a4a , 0xd9d65adc ,
46
+ 0x40df0b66 , 0x37d83bf0 , 0xa9bcae53 , 0xdebb9ec5 , 0x47b2cf7f , 0x30b5ffe9 ,
47
+ 0xbdbdf21c , 0xcabac28a , 0x53b39330 , 0x24b4a3a6 , 0xbad03605 , 0xcdd70693 ,
48
+ 0x54de5729 , 0x23d967bf , 0xb3667a2e , 0xc4614ab8 , 0x5d681b02 , 0x2a6f2b94 ,
49
+ 0xb40bbe37 , 0xc30c8ea1 , 0x5a05df1b , 0x2d02ef8d
50
+ ] ) ;
51
+
52
+ var crc32 = function ( buf ) {
53
+ var crc = - 1 ;
54
+ for ( var i = 0 ; i < buf . length ; i ++ ) {
55
+ crc = CRCTable [ ( crc ^ buf [ i ] ) & 0xff ] ^ ( crc >>> 8 ) ;
56
+ }
57
+ return crc ^ - 1 ;
58
+ } ;
59
+
60
+ /*
61
+ * BE byteArray implementation
62
+ * by Svetlana Linuxenko <[email protected] >
63
+ */
64
+
65
+ /* eslint no-undef: 0 */
66
+ var byteArray = Uint8Array ;
67
+
68
+ var cmp = function ( a , b ) {
69
+ if ( ! b ) b = a ; a = this ;
70
+ return a . filter ( function ( c , i ) { return c === b [ i ] ; } ) . length === a . length ;
71
+ } ;
72
+
73
+ var toInt = function ( a ) {
74
+ if ( ! a ) a = this . slice ( this . off , 4 ) ;
75
+ return ( a [ 0 ] << 24 ) | ( a [ 1 ] << 16 ) | ( a [ 2 ] << 8 ) | a [ 3 ] ;
76
+ //return a[0] | (a[1] << 8) | (a[2] << 16) | (a[3] << 24);
77
+ } ;
78
+
79
+ var toBytes = function ( int ) {
80
+ return new byteArray ( [
81
+ ( int >> 24 ) & 0xff ,
82
+ ( int >> 16 ) & 0xff ,
83
+ ( int >> 8 ) & 0xff ,
84
+ int & 0xff
85
+ ] ) ;
86
+ } ;
87
+
88
+ var nextInt = function ( ) {
89
+ return this . toInt ( this . slice ( this . off , ( this . off += 4 ) ) ) ;
90
+ } ;
91
+
92
+ var nextIntBytes = function ( ) {
93
+ return this . nextBytes ( 4 ) ;
94
+ } ;
95
+
96
+ var nextBytes = function ( size ) {
97
+ return this . slice ( this . off , ( this . off += size ) ) ;
98
+ } ;
99
+
100
+ var nextByte = function ( ) {
101
+ return this . nextBytes ( 1 ) [ 0 ] ;
102
+ } ;
103
+
104
+ var insertInt = function ( int ) {
105
+ this . insertBytes ( this . toBytes ( int ) ) ;
106
+ } ;
107
+
108
+ var insertBytes = function ( bytes , length ) {
109
+ length = length || 4 ;
110
+ this . set ( bytes , this . off , length ) ;
111
+ this . off += length ;
112
+ } ;
113
+
114
+ var insertByte = function ( byte ) {
115
+ this . set ( [ byte ] , this . off , ( this . off += 1 ) ) ;
116
+ } ;
117
+
118
+ byteArray . prototype . cmp = cmp ;
119
+ byteArray . prototype . toInt = toInt ;
120
+ byteArray . prototype . nextInt = nextInt ;
121
+ byteArray . prototype . nextIntBytes = nextIntBytes ;
122
+ byteArray . prototype . toBytes = toBytes ;
123
+ byteArray . prototype . insertInt = insertInt ;
124
+ byteArray . prototype . insertBytes = insertBytes ;
125
+ byteArray . prototype . nextBytes = nextBytes ;
126
+ byteArray . prototype . nextByte = nextByte ;
127
+ byteArray . prototype . insertByte = insertByte ;
128
+
129
+ Object . defineProperty ( byteArray . prototype , 'off' , {
130
+ enumerable : false ,
131
+ configurable : false ,
132
+ writable : true ,
133
+ value : 0
134
+ } ) ;
135
+
136
+
137
+ var SIGNATURE = new byteArray ( [ 0x89 , 0x50 , 0x4e , 0x47 , 0x0d , 0x0a , 0x1a , 0x0a ] ) ;
138
+ var IHDR = new byteArray ( [ 0x49 , 0x48 , 0x44 , 0x52 ] ) ;
139
+ var IDAT = new byteArray ( [ 0x49 , 0x44 , 0x41 , 0x54 ] ) ;
140
+ var IEND = new byteArray ( [ 0x49 , 0x45 , 0x4e , 0x44 ] ) ;
141
+
142
+
143
+ /*
144
+ * Decoder
145
+ */
146
+ var zlib = require ( 'zlib' ) ;
147
+
148
+ var inflateFunction = function ( data ) {
149
+ return zlib . inflateSync ( Buffer . from ( data ) ) ;
150
+ } ;
151
+
152
+
153
+ var Decoder = function ( ) { } ;
154
+
155
+ Decoder . prototype . parse = function ( data ) {
156
+ if ( ! ( data instanceof byteArray ) ) {
157
+ data = new byteArray ( data ) ;
158
+ }
159
+
160
+ if ( ! SIGNATURE . cmp ( data . nextBytes ( SIGNATURE . length ) ) ) {
161
+ throw new Error ( 'Not png' ) ;
162
+ }
163
+
164
+ while ( data . off < data . length ) {
165
+ var len = data . nextInt ( ) ;
166
+ var hdr = data . nextBytes ( len + 4 ) ;
167
+
168
+ if ( crc32 ( hdr ) !== data . nextInt ( ) ) {
169
+ throw new Error ( 'Crc error' ) ;
170
+ }
171
+
172
+ if ( IHDR . cmp ( hdr ) ) {
173
+ this . _IHDR = this . _chunkIHDR ( hdr . slice ( 4 , len + 4 ) ) ;
174
+
175
+ if ( this . _IHDR . palette !== 8 ) {
176
+ throw new Error ( 'Depth error' ) ;
177
+ }
178
+
179
+ if ( this . _IHDR . compression !== 0 ) {
180
+ throw new Error ( 'Compression error' ) ;
181
+ }
182
+
183
+ if ( this . _IHDR . filter !== 0 ) {
184
+ throw new Error ( 'Filter error' ) ;
185
+ }
186
+
187
+ if ( this . _IHDR . interlace !== 0 ) {
188
+ throw new Error ( 'Interlace error' ) ;
189
+ }
190
+
191
+ switch ( this . _IHDR . colorType ) {
192
+ case 0 : this . bpp = 1 ; break ;
193
+ case 2 : this . bpp = 3 ; break ;
194
+ case 3 : this . bpp = 1 ; break ;
195
+ case 4 : this . bpp = 2 ; break ;
196
+ case 6 : this . bpp = 4 ; break ;
197
+ default : throw new Error ( 'ColorType error' ) ;
198
+ }
199
+ this . chunks = [ ] ;
200
+ }
201
+
202
+ if ( IDAT . cmp ( hdr ) ) {
203
+ if ( ! this . _IHDR ) {
204
+ throw new Error ( 'IHDR error' ) ;
205
+ }
206
+
207
+ this . _chunkIDAT ( hdr . slice ( 4 , len + 4 ) ) ;
208
+ }
209
+
210
+ if ( IEND . cmp ( hdr ) ) {
211
+ return this . _chunkIEND ( ) ;
212
+ }
213
+ }
214
+
215
+ throw new Error ( 'Data error' ) ;
216
+ } ;
217
+
218
+ Decoder . prototype . _chunkIEND = function ( ) {
219
+ var tmp = [ ] ;
220
+ for ( var i = 0 ; i < this . chunks . length ; i ++ ) {
221
+ for ( var j = 0 ; j < this . chunks [ i ] . length ; j ++ ) {
222
+ tmp . push ( this . chunks [ i ] [ j ] ) ;
223
+ }
224
+ }
225
+ return this . filter ( inflateFunction ( tmp ) ) ;
226
+ } ;
227
+
228
+ Decoder . prototype . _chunkIDAT = function ( chunk ) {
229
+ this . chunks . push ( chunk ) ;
230
+ } ;
231
+
232
+ Decoder . prototype . _chunkIHDR = function ( chunk ) {
233
+ return {
234
+ width : chunk . nextInt ( ) ,
235
+ height : chunk . nextInt ( ) ,
236
+ palette : chunk . nextByte ( ) ,
237
+ colorType : chunk . nextByte ( ) ,
238
+ compression : chunk . nextByte ( ) ,
239
+ filter : chunk . nextByte ( ) ,
240
+ interlace : chunk . nextByte ( )
241
+ } ;
242
+ } ;
243
+
244
+ Decoder . prototype . filter = function ( data ) {
245
+ var bpp = this . bpp ;
246
+ var width = this . _IHDR . width , height = this . _IHDR . height ;
247
+ var pixels = new byteArray ( ( width * height ) * bpp ) ;
248
+ var filter , line , left , leftup , up , pixel ;
249
+ var lineWidth = width * bpp , byte , off ;
250
+
251
+ for ( var y = 0 ; y < height ; y ++ ) {
252
+
253
+ filter = data . nextByte ( ) ;
254
+ line = data . nextBytes ( lineWidth ) ;
255
+
256
+ for ( var x = 0 ; x < lineWidth ; x ++ ) {
257
+
258
+ if ( filter !== 0 ) {
259
+ off = ( y * lineWidth ) + x ;
260
+ }
261
+
262
+ byte = line . nextByte ( ) ;
263
+
264
+ switch ( filter ) {
265
+ case 0 : //None
266
+ pixel = byte ;
267
+ break ;
268
+ case 1 : // Sub Raw(x) + Raw(x - bpp)
269
+ if ( x < bpp ) {
270
+ pixel = byte ;
271
+ break ;
272
+ }
273
+ pixel = pixels [ off - bpp ] + byte & 0xff ;
274
+ break ;
275
+ case 2 : // Up(x) = Raw(x) + Prior(x)
276
+ if ( y === 0 ) {
277
+ pixel = byte ;
278
+ break ;
279
+ }
280
+ pixel = pixels [ off - lineWidth ] + byte & 0xff ;
281
+ break ;
282
+ case 3 : // Average(x) = Raw(x) + floor((Raw(x-bpp)+Prior(x))/2)
283
+ if ( y === 0 ) {
284
+ if ( x < bpp ) {
285
+ pixel = byte ;
286
+ } else {
287
+ pixel = ( byte + ( pixels [ off - bpp ] >> 1 ) ) & 0xff ;
288
+ }
289
+ break ;
290
+ }
291
+
292
+ if ( x < bpp ) {
293
+ pixel = ( byte + ( pixels [ off - lineWidth ] >> 1 ) ) & 0xff ;
294
+ break ;
295
+ }
296
+
297
+ pixel = ( byte + ( pixels [ off - bpp ] + pixels [ off - lineWidth ] >> 1 ) ) & 0xff ;
298
+ break ;
299
+ case 4 : // Paeth
300
+ if ( y === 0 ) {
301
+ if ( x < bpp ) {
302
+ pixel = byte ;
303
+ } else {
304
+ pixel = ( byte + ( pixels [ off - bpp ] ) ) & 0xff ;
305
+ }
306
+ break ;
307
+ }
308
+
309
+ if ( x < bpp ) {
310
+ pixel = ( byte + ( pixels [ off - lineWidth ] ) ) & 0xff ;
311
+ break ;
312
+ }
313
+
314
+ up = pixels [ off - lineWidth ] ;
315
+ left = pixels [ off - bpp ] ;
316
+ leftup = pixels [ ( off - lineWidth ) - bpp ] ;
317
+
318
+ var p = left + up - leftup ,
319
+ pleft = Math . abs ( p - left ) ,
320
+ pup = Math . abs ( p - up ) ,
321
+ pleftup = Math . abs ( p - leftup ) ;
322
+
323
+ if ( pleft <= pup && pleft <= pleftup ) {
324
+ pixel = byte + left & 0xff ;
325
+ break ;
326
+ } else if ( pup <= pleftup ) {
327
+ pixel = byte + up & 0xff ;
328
+ break ;
329
+ }
330
+
331
+ pixel = byte + leftup & 0xff ;
332
+ break ;
333
+ default :
334
+ throw new Error ( 'Filter error: ' + filter ) ;
335
+ }
336
+
337
+ pixels . insertByte ( pixel ) ;
338
+ }
339
+ }
340
+
341
+ return pixels ;
342
+ } ;
343
+
344
+ module . exports = Decoder ;
0 commit comments