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 bool SkWBMPImageDecoder::onDecode(SkStream* stream, SkBitmap* decodedBitmap,
    100                                   Mode mode)
    101 {
    102     wbmp_head   head;
    103 
    104     if (!head.init(stream)) {
    105         return false;
    106     }
    107 
    108     int width = head.fWidth;
    109     int height = head.fHeight;
    110 
    111     if (SkImageDecoder::kDecodeBounds_Mode == mode) {
    112         // assign these directly, in case we return kDimensions_Result
    113         decodedBitmap->setConfig(SkBitmap::kIndex8_Config, width, height);
    114         decodedBitmap->setIsOpaque(true);
    115         return true;
    116     }
    117 #ifdef SK_BUILD_FOR_ANDROID
    118     // No Bitmap reuse supported for this format
    119     if (!decodedBitmap->isNull()) {
    120         return false;
    121     }
    122 #endif
    123     // assign these directly, in case we return kDimensions_Result
    124     decodedBitmap->setConfig(SkBitmap::kIndex8_Config, width, height);
    125     decodedBitmap->setIsOpaque(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 DEFINE_DECODER_CREATOR(WBMPImageDecoder);
    159 ///////////////////////////////////////////////////////////////////////////////
    160 
    161 #include "SkTRegistry.h"
    162 
    163 static SkImageDecoder* sk_wbmp_dfactory(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(sk_wbmp_dfactory);
    173