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     Format getFormat() const override {
     21         return kWBMP_Format;
     22     }
     23 
     24 protected:
     25     Result onDecode(SkStream* stream, SkBitmap* bm, Mode) override;
     26 
     27 private:
     28     typedef SkImageDecoder INHERITED;
     29 };
     30 
     31 static bool read_byte(SkStream* stream, uint8_t* data)
     32 {
     33     return stream->read(data, 1) == 1;
     34 }
     35 
     36 static bool read_mbf(SkStream* stream, int* value)
     37 {
     38     int n = 0;
     39     uint8_t data;
     40     do {
     41         if (!read_byte(stream, &data)) {
     42             return false;
     43         }
     44         n = (n << 7) | (data & 0x7F);
     45     } while (data & 0x80);
     46 
     47     *value = n;
     48     return true;
     49 }
     50 
     51 struct wbmp_head {
     52     int fWidth;
     53     int fHeight;
     54 
     55     bool init(SkStream* stream)
     56     {
     57         uint8_t data;
     58 
     59         if (!read_byte(stream, &data) || data != 0) { // unknown type
     60             return false;
     61         }
     62         if (!read_byte(stream, &data) || (data & 0x9F)) { // skip fixed header
     63             return false;
     64         }
     65         if (!read_mbf(stream, &fWidth) || (unsigned)fWidth > 0xFFFF) {
     66             return false;
     67         }
     68         if (!read_mbf(stream, &fHeight) || (unsigned)fHeight > 0xFFFF) {
     69             return false;
     70         }
     71         return fWidth != 0 && fHeight != 0;
     72     }
     73 };
     74 
     75 static void expand_bits_to_bytes(uint8_t dst[], const uint8_t src[], int bits)
     76 {
     77     int bytes = bits >> 3;
     78 
     79     for (int i = 0; i < bytes; i++) {
     80         unsigned mask = *src++;
     81         dst[0] = (mask >> 7) & 1;
     82         dst[1] = (mask >> 6) & 1;
     83         dst[2] = (mask >> 5) & 1;
     84         dst[3] = (mask >> 4) & 1;
     85         dst[4] = (mask >> 3) & 1;
     86         dst[5] = (mask >> 2) & 1;
     87         dst[6] = (mask >> 1) & 1;
     88         dst[7] = (mask >> 0) & 1;
     89         dst += 8;
     90     }
     91 
     92     bits &= 7;
     93     if (bits > 0) {
     94         unsigned mask = *src;
     95         do {
     96             *dst++ = (mask >> 7) & 1;
     97             mask <<= 1;
     98         } while (--bits != 0);
     99     }
    100 }
    101 
    102 SkImageDecoder::Result SkWBMPImageDecoder::onDecode(SkStream* stream, SkBitmap* decodedBitmap,
    103                                                     Mode mode)
    104 {
    105     wbmp_head   head;
    106 
    107     if (!head.init(stream)) {
    108         return kFailure;
    109     }
    110 
    111     int width = head.fWidth;
    112     int height = head.fHeight;
    113 
    114     decodedBitmap->setInfo(SkImageInfo::Make(width, height,
    115                                              kIndex_8_SkColorType, kOpaque_SkAlphaType));
    116 
    117     if (SkImageDecoder::kDecodeBounds_Mode == mode) {
    118         return kSuccess;
    119     }
    120 
    121     const SkPMColor colors[] = { SK_ColorBLACK, SK_ColorWHITE };
    122     SkColorTable* ct = new SkColorTable(colors, 2);
    123     SkAutoUnref   aur(ct);
    124 
    125     if (!this->allocPixelRef(decodedBitmap, ct)) {
    126         return kFailure;
    127     }
    128 
    129     SkAutoLockPixels alp(*decodedBitmap);
    130 
    131     uint8_t* dst = decodedBitmap->getAddr8(0, 0);
    132     // store the 1-bit valuess at the end of our pixels, so we won't stomp
    133     // on them before we're read them. Just trying to avoid a temp allocation
    134     size_t srcRB = SkAlign8(width) >> 3;
    135     size_t srcSize = height * srcRB;
    136     uint8_t* src = dst + decodedBitmap->getSize() - srcSize;
    137     if (stream->read(src, srcSize) != srcSize) {
    138         return kFailure;
    139     }
    140 
    141     for (int y = 0; y < height; y++)
    142     {
    143         expand_bits_to_bytes(dst, src, width);
    144         dst += decodedBitmap->rowBytes();
    145         src += srcRB;
    146     }
    147 
    148     return kSuccess;
    149 }
    150 
    151 ///////////////////////////////////////////////////////////////////////////////
    152 DEFINE_DECODER_CREATOR(WBMPImageDecoder);
    153 ///////////////////////////////////////////////////////////////////////////////
    154 
    155 static SkImageDecoder* sk_wbmp_dfactory(SkStreamRewindable* stream) {
    156     wbmp_head   head;
    157 
    158     if (head.init(stream)) {
    159         return new SkWBMPImageDecoder;
    160     }
    161     return nullptr;
    162 }
    163 
    164 static SkImageDecoder::Format get_format_wbmp(SkStreamRewindable* stream) {
    165     wbmp_head head;
    166     if (head.init(stream)) {
    167         return SkImageDecoder::kWBMP_Format;
    168     }
    169     return SkImageDecoder::kUnknown_Format;
    170 }
    171 
    172 static SkImageDecoder_DecodeReg gDReg(sk_wbmp_dfactory);
    173 static SkImageDecoder_FormatReg gFormatReg(get_format_wbmp);
    174