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