@@ -21,6 +21,71 @@ var range = function(n) {
21
21
* @class ICO
22
22
*/
23
23
24
+ /**
25
+ * Generate the hexadecimal value from an arrayBuffer.
26
+ * @memberof ICO
27
+ * @param {ArrayBuffer } buffer The ArrayBuffer object contain the TypedArray of a ICO file.
28
+ * @returns {String } The hexadecimal value.
29
+ */
30
+ function buf2hex ( buffer ) { // buffer is an ArrayBuffer
31
+ return Array . prototype . map . call ( new Uint8Array ( buffer ) , x => ( '00' + x . toString ( 16 ) ) . slice ( - 2 ) ) . join ( '' ) ;
32
+ }
33
+
34
+ /**
35
+ * Creates a PNG image object using the createIcon method.
36
+ * @memberof ICO
37
+ * @param {Int } index The image index.
38
+ * @param {ArrayBuffer } buffer The ArrayBuffer object contain the TypedArray of a ICO file.
39
+ * @returns {Object } PNG icon object.
40
+ */
41
+
42
+ function createPng ( index , buffer ) {
43
+ var dv = new DataView ( buffer ) ;
44
+
45
+ var icoWidth = dv . getUint8 ( 6 + ( index * 16 ) ) || 256 ;
46
+ var icoHeight = dv . getUint8 ( 7 + ( index * 16 ) ) || 256 ;
47
+ var icoOffset = dv . getUint32 ( 18 + ( index * 16 ) , true ) ;
48
+ var icoBit = dv . getUint8 ( ( icoOffset + 16 ) + 8 , true ) ;
49
+ var endImage = ( buf2hex ( buffer . slice ( icoOffset , buffer . byteLength ) ) ) . indexOf ( "49454e44" ) ;
50
+ var imgBuffer = buffer . slice ( icoOffset , icoOffset + endImage ) ;
51
+
52
+ return createIcon ( icoBit , icoWidth , icoHeight , imgBuffer ) ;
53
+ }
54
+
55
+ /**
56
+ * Validates if the image is PNG.
57
+ * @memberof ICO
58
+ * @param {Int } index The image index.
59
+ * @param {ArrayBuffer } buffer The ArrayBuffer object contain the TypedArray of a ICO file.
60
+ * @returns {Boolean } True if the image is PNG.
61
+ */
62
+
63
+ function isPNG ( index , buffer ) {
64
+ var icoDv = new DataView ( buffer ) ;
65
+ var startImage = icoDv . getUint32 ( 18 + ( index * 16 ) , true ) ;
66
+ var bufferSlice = buf2hex ( buffer . slice ( startImage , startImage + 4 ) )
67
+ return ( bufferSlice === "89504e47" ) ;
68
+ }
69
+
70
+
71
+ /**
72
+ * Creates an image object.
73
+ * @memberof ICO
74
+ * @param {Int } bit The image bit depth.
75
+ * @param {Int } width The image width.
76
+ * @param {Int } height The image height.
77
+ * @param {ArrayBuffer } buffer The ArrayBuffer object contain the TypedArray of a ICO file.
78
+ * @returns {Object } An icon object.
79
+ */
80
+ function createIcon ( bit , width , height , buffer ) {
81
+ return {
82
+ bit : bit ,
83
+ width : width ,
84
+ height : height ,
85
+ buffer : buffer
86
+ }
87
+ }
88
+
24
89
var factory = function ( config ) {
25
90
var previousICO = global . ICO ;
26
91
var Image = config . Image ;
@@ -38,47 +103,49 @@ var factory = function(config) {
38
103
* * `buffer` **ArrayBuffer** - Image buffer.
39
104
*/
40
105
parse : function ( buffer , mime ) {
106
+
41
107
var icoDv = new DataView ( buffer ) ;
42
108
if ( icoDv . getUint16 ( 0 , true ) !== 0 || icoDv . getUint16 ( 2 , true ) !== 1 ) {
43
109
var deferred = Q . defer ( ) ;
44
110
return deferred . reject ( new Error ( 'buffer is not ico' ) ) ;
45
111
}
46
-
47
- // make single image icon
48
- // let idCount = icoDv.getUint16(4, true);
49
- return Q . all ( range ( icoDv . getUint16 ( 4 , true ) ) . map ( function ( i ) {
50
- var ico = extractOne ( buffer , i ) ;
51
- var image = {
52
- width : ico . width ,
53
- height : ico . height
54
- } ;
55
-
56
- switch ( ico . bit ) { // eslint-disable-line default-case
57
- case 1 :
58
- image . data = imageData . from1bit ( ico ) ;
59
- break ;
60
- case 4 :
61
- image . data = imageData . from4bit ( ico ) ;
62
- break ;
63
- case 8 :
64
- image . data = imageData . from8bit ( ico ) ;
65
- break ;
66
- case 24 :
67
- image . data = imageData . from24bit ( ico ) ;
68
- break ;
69
- case 32 :
70
- image . data = imageData . from32bit ( ico ) ;
71
- break ;
72
- }
73
-
74
- return Image . encode ( image , mime ) . then ( function ( pngBuffer ) {
75
- return {
76
- bit : ico . bit ,
77
- width : ico . width ,
78
- height : ico . height ,
79
- buffer : pngBuffer
80
- } ;
81
- } ) ;
112
+
113
+ return Q . all ( range ( icoDv . getUint16 ( 4 , true ) )
114
+ . map ( function ( i ) {
115
+
116
+ if ( isPNG ( i , buffer ) ) {
117
+ var deferred = Q . defer ( ) ;
118
+ deferred . resolve ( createPng ( i , buffer ) ) ;
119
+ return deferred . promise ;
120
+ } else {
121
+ var ico = extractOne ( buffer , i ) ;
122
+ var image = {
123
+ width : ico . width ,
124
+ height : ico . height
125
+ } ;
126
+
127
+ switch ( ico . bit ) { // eslint-disable-line default-case
128
+ case 1 :
129
+ image . data = imageData . from1bit ( ico ) ;
130
+ break ;
131
+ case 4 :
132
+ image . data = imageData . from4bit ( ico ) ;
133
+ break ;
134
+ case 8 :
135
+ image . data = imageData . from8bit ( ico ) ;
136
+ break ;
137
+ case 24 :
138
+ image . data = imageData . from24bit ( ico ) ;
139
+ break ;
140
+ case 32 :
141
+ image . data = imageData . from32bit ( ico ) ;
142
+ break ;
143
+ }
144
+
145
+ return Image . encode ( image , mime ) . then ( function ( pngBuffer ) {
146
+ return createIcon ( ico . bit , ico . width , ico . height , pngBuffer ) ;
147
+ } ) ;
148
+ }
82
149
} ) ) ;
83
150
} ,
84
151
/**
0 commit comments