OLD | NEW |
| (Empty) |
1 /* libs/graphics/images/SkImageDecoder_libico.cpp | |
2 ** | |
3 ** Copyright 2006, The Android Open Source Project | |
4 ** | |
5 ** Licensed under the Apache License, Version 2.0 (the "License"); | |
6 ** you may not use this file except in compliance with the License. | |
7 ** You may obtain a copy of the License at | |
8 ** | |
9 ** http://www.apache.org/licenses/LICENSE-2.0 | |
10 ** | |
11 ** Unless required by applicable law or agreed to in writing, software | |
12 ** distributed under the License is distributed on an "AS IS" BASIS, | |
13 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
14 ** See the License for the specific language governing permissions and | |
15 ** limitations under the License. | |
16 */ | |
17 | |
18 #include "SkImageDecoder.h" | |
19 #include "SkStream.h" | |
20 #include "SkColorPriv.h" | |
21 #include "SkTypes.h" | |
22 | |
23 class SkICOImageDecoder : public SkImageDecoder { | |
24 public: | |
25 SkICOImageDecoder(); | |
26 | |
27 virtual Format getFormat() const { | |
28 return kICO_Format; | |
29 } | |
30 | |
31 protected: | |
32 virtual bool onDecode(SkStream* stream, SkBitmap* bm, | |
33 SkBitmap::Config pref, Mode); | |
34 }; | |
35 | |
36 ////////////////////////////////////////////////////////////////////////////////
///////// | |
37 | |
38 //read bytes starting from the begin-th index in the buffer | |
39 //read in Intel order, and return an integer | |
40 | |
41 #define readByte(buffer,begin) buffer[begin] | |
42 #define read2Bytes(buffer,begin) buffer[begin]+(buffer[begin+1]<<8) | |
43 #define read4Bytes(buffer,begin) buffer[begin]+(buffer[begin+1]<<8)+(buffer[begi
n+2]<<16)+(buffer[begin+3]<<24) | |
44 | |
45 ////////////////////////////////////////////////////////////////////////////////
///////// | |
46 | |
47 SkImageDecoder* SkImageDecoder_ICO_Factory(SkStream*); | |
48 SkImageDecoder* SkImageDecoder_ICO_Factory(SkStream* stream) | |
49 { | |
50 //i'm going to check if we basically have 0,0,1,0 (reserved = 0, type = 1) | |
51 //is that required and sufficient? | |
52 SkAutoMalloc autoMal(4); | |
53 unsigned char* buf = (unsigned char*)autoMal.get(); | |
54 stream->read((void*)buf, 4); | |
55 int reserved = read2Bytes(buf, 0); | |
56 int type = read2Bytes(buf, 2); | |
57 if (reserved != 0 || type != 1) //it's not an ico | |
58 return NULL; | |
59 return SkNEW(SkICOImageDecoder); | |
60 } | |
61 | |
62 ////////////////////////////////////////////////////////////////////////////////
///////// | |
63 | |
64 SkICOImageDecoder::SkICOImageDecoder() | |
65 { | |
66 } | |
67 | |
68 //helpers - my function pointer will call one of these, depending on the bitCoun
t, each time through the inner loop | |
69 static void editPixelBit1(const int pixelNo, const unsigned char* buf, | |
70 const int xorOffset, int& x, int y, const int w, | |
71 SkBitmap* bm, int alphaByte, int m, int shift, SkPMColor* colors); | |
72 static void editPixelBit4(const int pixelNo, const unsigned char* buf, | |
73 const int xorOffset, int& x, int y, const int w, | |
74 SkBitmap* bm, int alphaByte, int m, int shift, SkPMColor* colors); | |
75 static void editPixelBit8(const int pixelNo, const unsigned char* buf, | |
76 const int xorOffset, int& x, int y, const int w, | |
77 SkBitmap* bm, int alphaByte, int m, int shift, SkPMColor* colors); | |
78 static void editPixelBit24(const int pixelNo, const unsigned char* buf, | |
79 const int xorOffset, int& x, int y, const int w, | |
80 SkBitmap* bm, int alphaByte, int m, int shift, SkPMColor* colors); | |
81 static void editPixelBit32(const int pixelNo, const unsigned char* buf, | |
82 const int xorOffset, int& x, int y, const int w, | |
83 SkBitmap* bm, int alphaByte, int m, int shift, SkPMColor* colors); | |
84 | |
85 | |
86 static int calculateRowBytesFor8888(int w, int bitCount) | |
87 { | |
88 // Default rowBytes is w << 2 for kARGB_8888 | |
89 // In the case of a 4 bit image with an odd width, we need to add some | |
90 // so we can go off the end of the drawn bitmap. | |
91 // Add 4 to ensure that it is still a multiple of 4. | |
92 if (4 == bitCount && (w & 0x1)) { | |
93 return (w + 1) << 2; | |
94 } | |
95 // Otherwise return 0, which will allow it to be calculated automatically. | |
96 return 0; | |
97 } | |
98 | |
99 bool SkICOImageDecoder::onDecode(SkStream* stream, SkBitmap* bm, | |
100 SkBitmap::Config pref, Mode mode) | |
101 { | |
102 size_t length = stream->read(NULL, 0); | |
103 SkAutoMalloc autoMal(length); | |
104 unsigned char* buf = (unsigned char*)autoMal.get(); | |
105 if (stream->read((void*)buf, length) != length) { | |
106 return false; | |
107 } | |
108 | |
109 //these should always be the same - should i use for error checking? - what
about files that have some | |
110 //incorrect values, but still decode properly? | |
111 int reserved = read2Bytes(buf, 0); // 0 | |
112 int type = read2Bytes(buf, 2); // 1 | |
113 if (reserved != 0 || type != 1) | |
114 return false; | |
115 int count = read2Bytes(buf, 4); | |
116 | |
117 //need to at least have enough space to hold the initial table of info | |
118 if (length < (size_t)(6 + count*16)) | |
119 return false; | |
120 | |
121 int choice; | |
122 Chooser* chooser = this->getChooser(); | |
123 //FIXME:if no chooser, consider providing the largest color image | |
124 //what are the odds that the largest image would be monochrome? | |
125 if (NULL == chooser) { | |
126 choice = 0; | |
127 } else { | |
128 chooser->begin(count); | |
129 for (int i = 0; i < count; i++) | |
130 { | |
131 //need to find out the config, width, and height from the stream | |
132 int width = readByte(buf, 6 + i*16); | |
133 int height = readByte(buf, 7 + i*16); | |
134 int offset = read4Bytes(buf, 18 + i*16); | |
135 int bitCount = read2Bytes(buf, offset+14); | |
136 SkBitmap::Config c; | |
137 //currently only provide ARGB_8888_, but maybe we want kIndex8_Confi
g for 1 and 4, and possibly 8? | |
138 //or maybe we'll determine this based on the provided config | |
139 switch (bitCount) | |
140 { | |
141 case 1: | |
142 case 4: | |
143 // In reality, at least for the moment, these will be decode
d into kARGB_8888 bitmaps. | |
144 // However, this will be used to distinguish between the low
er quality 1bpp and 4 bpp | |
145 // images and the higher quality images. | |
146 c = SkBitmap::kIndex8_Config; | |
147 break; | |
148 case 8: | |
149 case 24: | |
150 case 32: | |
151 c = SkBitmap::kARGB_8888_Config; | |
152 break; | |
153 default: | |
154 SkDEBUGF(("Image with %ibpp not supported\n", bitCount)); | |
155 continue; | |
156 } | |
157 chooser->inspect(i, c, width, height); | |
158 } | |
159 choice = chooser->choose(); | |
160 } | |
161 | |
162 //you never know what the chooser is going to supply | |
163 if (choice >= count || choice < 0) | |
164 return false; | |
165 | |
166 //skip ahead to the correct header | |
167 //commented out lines are not used, but if i switch to other read method, ne
ed to know how many to skip | |
168 //otherwise, they could be used for error checking | |
169 int w = readByte(buf, 6 + choice*16); | |
170 int h = readByte(buf, 7 + choice*16); | |
171 int colorCount = readByte(buf, 8 + choice*16); | |
172 //int reservedToo = readByte(buf, 9 + choice*16); //0 | |
173 //int planes = read2Bytes(buf, 10 + choice*16); //1 - but often 0 | |
174 //int fakeBitCount = read2Bytes(buf, 12 + choice*16); //should be real - usu
ally 0 | |
175 int size = read4Bytes(buf, 14 + choice*16); //matters? | |
176 int offset = read4Bytes(buf, 18 + choice*16); | |
177 if ((size_t)(offset + size) > length) | |
178 return false; | |
179 //int infoSize = read4Bytes(buf, offset); //40 | |
180 //int width = read4Bytes(buf, offset+4); //should == w | |
181 //int height = read4Bytes(buf, offset+8); //should == 2*h | |
182 //int planesToo = read2Bytes(buf, offset+12); //should == 1 (does it
?) | |
183 int bitCount = read2Bytes(buf, offset+14); | |
184 | |
185 void (*placePixel)(const int pixelNo, const unsigned char* buf, | |
186 const int xorOffset, int& x, int y, const int w, | |
187 SkBitmap* bm, int alphaByte, int m, int shift, SkPMColor* colors) = NULL
; | |
188 switch (bitCount) | |
189 { | |
190 case 1: | |
191 placePixel = &editPixelBit1; | |
192 colorCount = 2; | |
193 break; | |
194 case 4: | |
195 placePixel = &editPixelBit4; | |
196 colorCount = 16; | |
197 break; | |
198 case 8: | |
199 placePixel = &editPixelBit8; | |
200 colorCount = 256; | |
201 break; | |
202 case 24: | |
203 placePixel = &editPixelBit24; | |
204 colorCount = 0; | |
205 break; | |
206 case 32: | |
207 placePixel = &editPixelBit32; | |
208 colorCount = 0; | |
209 break; | |
210 default: | |
211 SkDEBUGF(("Decoding %ibpp is unimplemented\n", bitCount)); | |
212 return false; | |
213 } | |
214 | |
215 //these should all be zero, but perhaps are not - need to check | |
216 //int compression = read4Bytes(buf, offset+16); //0 | |
217 //int imageSize = read4Bytes(buf, offset+20); //0 - sometimes has a
value | |
218 //int xPixels = read4Bytes(buf, offset+24); //0 | |
219 //int yPixels = read4Bytes(buf, offset+28); //0 | |
220 //int colorsUsed = read4Bytes(buf, offset+32) //0 - might have an ac
tual value though | |
221 //int colorsImportant = read4Bytes(buf, offset+36); //0 | |
222 | |
223 int begin = offset + 40; | |
224 //this array represents the colortable | |
225 //if i allow other types of bitmaps, it may actually be used as a part of th
e bitmap | |
226 SkPMColor* colors = NULL; | |
227 int blue, green, red; | |
228 if (colorCount) | |
229 { | |
230 colors = new SkPMColor[colorCount]; | |
231 for (int j = 0; j < colorCount; j++) | |
232 { | |
233 //should this be a function - maybe a #define? | |
234 blue = readByte(buf, begin + 4*j); | |
235 green = readByte(buf, begin + 4*j + 1); | |
236 red = readByte(buf, begin + 4*j + 2); | |
237 colors[j] = SkPackARGB32(0xFF, red & 0xFF, green & 0xFF, blue & 0xFF
); | |
238 } | |
239 } | |
240 int bitWidth = w*bitCount; | |
241 int test = bitWidth & 0x1F; | |
242 int mask = -(((test >> 4) | (test >> 3) | (test >> 2) | (test >> 1) | test)
& 0x1); //either 0xFFFFFFFF or 0 | |
243 int lineBitWidth = (bitWidth & 0xFFFFFFE0) + (0x20 & mask); | |
244 int lineWidth = lineBitWidth/bitCount; | |
245 | |
246 int xorOffset = begin + colorCount*4; //beginning of the color bitmap | |
247 //other read method means we will ju
st be here already | |
248 int andOffset = xorOffset + ((lineWidth*h*bitCount) >> 3); | |
249 | |
250 /*int */test = w & 0x1F; //the low 5 bits - we are rounding up to the next
32 (2^5) | |
251 /*int */mask = -(((test >> 4) | (test >> 3) | (test >> 2) | (test >> 1) | te
st) & 0x1); //either 0xFFFFFFFF or 0 | |
252 int andLineWidth = (w & 0xFFFFFFE0) + (0x20 & mask); | |
253 //if we allow different Configs, everything is the same til here | |
254 //change the config, and use different address getter, and place index vs co
lor, and add the color table | |
255 //FIXME: what is the tradeoff in size? | |
256 //if the andbitmap (mask) is all zeroes, then we can easily do an index bitm
ap | |
257 //however, with small images with large colortables, maybe it's better to st
ill do argb_8888 | |
258 | |
259 bm->setConfig(SkBitmap::kARGB_8888_Config, w, h, calculateRowBytesFor8888(w,
bitCount)); | |
260 | |
261 if (SkImageDecoder::kDecodeBounds_Mode == mode) { | |
262 delete[] colors; | |
263 return true; | |
264 } | |
265 | |
266 if (!this->allocPixelRef(bm, NULL)) | |
267 { | |
268 delete[] colors; | |
269 return false; | |
270 } | |
271 | |
272 SkAutoLockPixels alp(*bm); | |
273 | |
274 for (int y = 0; y < h; y++) | |
275 { | |
276 for (int x = 0; x < w; x++) | |
277 { | |
278 //U32* address = bm->getAddr32(x, y); | |
279 | |
280 //check the alpha bit first, but pass it along to the function to fi
gure out how to deal with it | |
281 int andPixelNo = andLineWidth*(h-y-1)+x; | |
282 //only need to get a new alphaByte when x %8 == 0 | |
283 //but that introduces an if and a mod - probably much slower | |
284 //that's ok, it's just a read of an array, not a stream | |
285 int alphaByte = readByte(buf, andOffset + (andPixelNo >> 3)); | |
286 int shift = 7 - (andPixelNo & 0x7); | |
287 int m = 1 << shift; | |
288 | |
289 int pixelNo = lineWidth*(h-y-1)+x; | |
290 placePixel(pixelNo, buf, xorOffset, x, y, w, bm, alphaByte, m, shift
, colors); | |
291 | |
292 } | |
293 } | |
294 | |
295 delete [] colors; | |
296 //ensure we haven't read off the end? | |
297 //of course this doesn't help us if the andOffset was a lie... | |
298 //return andOffset + (andLineWidth >> 3) <= length; | |
299 return true; | |
300 } //onDecode | |
301 | |
302 //function to place the pixel, determined by the bitCount | |
303 static void editPixelBit1(const int pixelNo, const unsigned char* buf, | |
304 const int xorOffset, int& x, int y, const int w, | |
305 SkBitmap* bm, int alphaByte, int m, int shift, SkPMColor* colors) | |
306 { | |
307 // note that this should be the same as/similar to the AND bitmap | |
308 SkPMColor* address = bm->getAddr32(x,y); | |
309 int byte = readByte(buf, xorOffset + (pixelNo >> 3)); | |
310 int colorBit; | |
311 int alphaBit; | |
312 // Read all of the bits in this byte. | |
313 int i = x + 8; | |
314 // Pin to the width so we do not write outside the bounds of | |
315 // our color table. | |
316 i = i > w ? w : i; | |
317 // While loop to check all 8 bits individually. | |
318 while (x < i) | |
319 { | |
320 | |
321 colorBit = (byte & m) >> shift; | |
322 alphaBit = (alphaByte & m) >> shift; | |
323 *address = (alphaBit-1)&(colors[colorBit]); | |
324 x++; | |
325 // setup for the next pixel | |
326 address = address + 1; | |
327 m = m >> 1; | |
328 shift -= 1; | |
329 } | |
330 x--; | |
331 } | |
332 static void editPixelBit4(const int pixelNo, const unsigned char* buf, | |
333 const int xorOffset, int& x, int y, const int w, | |
334 SkBitmap* bm, int alphaByte, int m, int shift, SkPMColor* colors) | |
335 { | |
336 SkPMColor* address = bm->getAddr32(x, y); | |
337 int byte = readByte(buf, xorOffset + (pixelNo >> 1)); | |
338 int pixel = (byte >> 4) & 0xF; | |
339 int alphaBit = (alphaByte & m) >> shift; | |
340 *address = (alphaBit-1)&(colors[pixel]); | |
341 x++; | |
342 //if w is odd, x may be the same as w, which means we are writing to an unus
ed portion of the bitmap | |
343 //but that's okay, since i've added an extra rowByte for just this purpose | |
344 address = address + 1; | |
345 pixel = byte & 0xF; | |
346 m = m >> 1; | |
347 alphaBit = (alphaByte & m) >> (shift-1); | |
348 //speed up trick here | |
349 *address = (alphaBit-1)&(colors[pixel]); | |
350 } | |
351 | |
352 static void editPixelBit8(const int pixelNo, const unsigned char* buf, | |
353 const int xorOffset, int& x, int y, const int w, | |
354 SkBitmap* bm, int alphaByte, int m, int shift, SkPMColor* colors) | |
355 { | |
356 SkPMColor* address = bm->getAddr32(x, y); | |
357 int pixel = readByte(buf, xorOffset + pixelNo); | |
358 int alphaBit = (alphaByte & m) >> shift; | |
359 *address = (alphaBit-1)&(colors[pixel]); | |
360 } | |
361 | |
362 static void editPixelBit24(const int pixelNo, const unsigned char* buf, | |
363 const int xorOffset, int& x, int y, const int w, | |
364 SkBitmap* bm, int alphaByte, int m, int shift, SkPMColor* colors) | |
365 { | |
366 SkPMColor* address = bm->getAddr32(x, y); | |
367 int blue = readByte(buf, xorOffset + 3*pixelNo); | |
368 int green = readByte(buf, xorOffset + 3*pixelNo + 1); | |
369 int red = readByte(buf, xorOffset + 3*pixelNo + 2); | |
370 int alphaBit = (alphaByte & m) >> shift; | |
371 //alphaBit == 1 => alpha = 0 | |
372 int alpha = (alphaBit-1) & 0xFF; | |
373 *address = SkPackARGB32(alpha, red & alpha, green & alpha, blue & alpha);
| |
374 } | |
375 | |
376 static void editPixelBit32(const int pixelNo, const unsigned char* buf, | |
377 const int xorOffset, int& x, int y, const int w, | |
378 SkBitmap* bm, int alphaByte, int m, int shift, SkPMColor* colors) | |
379 { | |
380 SkPMColor* address = bm->getAddr32(x, y); | |
381 int blue = readByte(buf, xorOffset + 4*pixelNo); | |
382 int green = readByte(buf, xorOffset + 4*pixelNo + 1); | |
383 int red = readByte(buf, xorOffset + 4*pixelNo + 2); | |
384 int alphaBit = (alphaByte & m) >> shift; | |
385 int alpha = readByte(buf, xorOffset + 4*pixelNo + 3) & ((alphaBit-1)&0xFF); | |
386 *address = SkPackARGB32(alpha, red & alpha, green & alpha, blue & alpha); | |
387 } | |
388 | |
OLD | NEW |