Home | History | Annotate | Download | only in images
      1 /**
      2 ** Copyright 2006, The Android Open Source Project
      3 **
      4 ** Licensed under the Apache License, Version 2.0 (the "License");
      5 ** you may not use this file except in compliance with the License.
      6 ** You may obtain a copy of the License at
      7 **
      8 **     http://www.apache.org/licenses/LICENSE-2.0
      9 **
     10 ** Unless required by applicable law or agreed to in writing, software
     11 ** distributed under the License is distributed on an "AS IS" BASIS,
     12 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13 ** See the License for the specific language governing permissions and
     14 ** limitations under the License.
     15 */
     16 
     17 #include "SkImageDecoder.h"
     18 #include "SkColor.h"
     19 #include "SkColorPriv.h"
     20 #include "SkMath.h"
     21 #include "SkStream.h"
     22 #include "SkTemplates.h"
     23 #include "SkUtils.h"
     24 
     25 class SkWBMPImageDecoder : public SkImageDecoder {
     26 public:
     27     virtual Format getFormat() const {
     28         return kWBMP_Format;
     29     }
     30 
     31 protected:
     32     virtual bool onDecode(SkStream* stream, SkBitmap* bm, Mode);
     33 };
     34 
     35 static bool read_byte(SkStream* stream, uint8_t* data)
     36 {
     37     return stream->read(data, 1) == 1;
     38 }
     39 
     40 static bool read_mbf(SkStream* stream, int* value)
     41 {
     42     int n = 0;
     43     uint8_t data;
     44     do {
     45         if (!read_byte(stream, &data)) {
     46             return false;
     47         }
     48         n = (n << 7) | (data & 0x7F);
     49     } while (data & 0x80);
     50 
     51     *value = n;
     52     return true;
     53 }
     54 
     55 struct wbmp_head {
     56     int fWidth;
     57     int fHeight;
     58 
     59     bool init(SkStream* stream)
     60     {
     61         uint8_t data;
     62 
     63         if (!read_byte(stream, &data) || data != 0) { // unknown type
     64             return false;
     65         }
     66         if (!read_byte(stream, &data) || (data & 0x9F)) { // skip fixed header
     67             return false;
     68         }
     69         if (!read_mbf(stream, &fWidth) || (unsigned)fWidth > 0xFFFF) {
     70             return false;
     71         }
     72         if (!read_mbf(stream, &fHeight) || (unsigned)fHeight > 0xFFFF) {
     73             return false;
     74         }
     75         return fWidth != 0 && fHeight != 0;
     76     }
     77 };
     78 
     79 static void expand_bits_to_bytes(uint8_t dst[], const uint8_t src[], int bits)
     80 {
     81     int bytes = bits >> 3;
     82 
     83     for (int i = 0; i < bytes; i++) {
     84         unsigned mask = *src++;
     85         dst[0] = (mask >> 7) & 1;
     86         dst[1] = (mask >> 6) & 1;
     87         dst[2] = (mask >> 5) & 1;
     88         dst[3] = (mask >> 4) & 1;
     89         dst[4] = (mask >> 3) & 1;
     90         dst[5] = (mask >> 2) & 1;
     91         dst[6] = (mask >> 1) & 1;
     92         dst[7] = (mask >> 0) & 1;
     93         dst += 8;
     94     }
     95 
     96     bits &= 7;
     97     if (bits > 0) {
     98         unsigned mask = *src;
     99         do {
    100             *dst++ = (mask >> 7) & 1;;
    101             mask <<= 1;
    102         } while (--bits != 0);
    103     }
    104 }
    105 
    106 #define SkAlign8(x)     (((x) + 7) & ~7)
    107 
    108 bool SkWBMPImageDecoder::onDecode(SkStream* stream, SkBitmap* decodedBitmap,
    109                                   Mode mode)
    110 {
    111     wbmp_head   head;
    112 
    113     if (!head.init(stream)) {
    114         return false;
    115     }
    116 
    117     int width = head.fWidth;
    118     int height = head.fHeight;
    119 
    120     // assign these directly, in case we return kDimensions_Result
    121     decodedBitmap->setConfig(SkBitmap::kIndex8_Config, width, height);
    122     decodedBitmap->setIsOpaque(true);
    123 
    124     if (SkImageDecoder::kDecodeBounds_Mode == mode)
    125         return true;
    126 
    127     const SkPMColor colors[] = { SK_ColorBLACK, SK_ColorWHITE };
    128     SkColorTable* ct = SkNEW_ARGS(SkColorTable, (colors, 2));
    129     SkAutoUnref   aur(ct);
    130 
    131     if (!this->allocPixelRef(decodedBitmap, ct)) {
    132         return false;
    133     }
    134 
    135     SkAutoLockPixels alp(*decodedBitmap);
    136 
    137     uint8_t* dst = decodedBitmap->getAddr8(0, 0);
    138     // store the 1-bit valuess at the end of our pixels, so we won't stomp
    139     // on them before we're read them. Just trying to avoid a temp allocation
    140     size_t srcRB = SkAlign8(width) >> 3;
    141     size_t srcSize = height * srcRB;
    142     uint8_t* src = dst + decodedBitmap->getSize() - srcSize;
    143     if (stream->read(src, srcSize) != srcSize) {
    144         return false;
    145     }
    146 
    147     for (int y = 0; y < height; y++)
    148     {
    149         expand_bits_to_bytes(dst, src, width);
    150         dst += decodedBitmap->rowBytes();
    151         src += srcRB;
    152     }
    153 
    154     return true;
    155 }
    156 
    157 ///////////////////////////////////////////////////////////////////////////////
    158 
    159 #include "SkTRegistry.h"
    160 
    161 static SkImageDecoder* Factory(SkStream* stream) {
    162     wbmp_head   head;
    163 
    164     if (head.init(stream)) {
    165         return SkNEW(SkWBMPImageDecoder);
    166     }
    167     return NULL;
    168 }
    169 
    170 static SkTRegistry<SkImageDecoder*, SkStream*> gReg(Factory);
    171 
    172