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