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