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