1 /* 2 * Copyright 2007, 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 // Author: cevans (at) google.com (Chris Evans) 17 18 #include "bmpdecoderhelper.h" 19 20 namespace image_codec { 21 22 static const int kBmpHeaderSize = 14; 23 static const int kBmpInfoSize = 40; 24 static const int kBmpOS2InfoSize = 12; 25 static const int kMaxDim = SHRT_MAX / 2; 26 27 bool BmpDecoderHelper::DecodeImage(const char* p, 28 int len, 29 int max_pixels, 30 BmpDecoderCallback* callback) { 31 data_ = reinterpret_cast<const uint8*>(p); 32 pos_ = 0; 33 len_ = len; 34 inverted_ = true; 35 // Parse the header structure. 36 if (len < kBmpHeaderSize + 4) { 37 return false; 38 } 39 GetShort(); // Signature. 40 GetInt(); // Size. 41 GetInt(); // Reserved. 42 int offset = GetInt(); 43 // Parse the info structure. 44 int infoSize = GetInt(); 45 if (infoSize != kBmpOS2InfoSize && infoSize < kBmpInfoSize) { 46 return false; 47 } 48 int cols = 0; 49 int comp = 0; 50 int colLen = 4; 51 if (infoSize >= kBmpInfoSize) { 52 if (len < kBmpHeaderSize + kBmpInfoSize) { 53 return false; 54 } 55 width_ = GetInt(); 56 height_ = GetInt(); 57 GetShort(); // Planes. 58 bpp_ = GetShort(); 59 comp = GetInt(); 60 GetInt(); // Size. 61 GetInt(); // XPPM. 62 GetInt(); // YPPM. 63 cols = GetInt(); 64 GetInt(); // Important colours. 65 } else { 66 if (len < kBmpHeaderSize + kBmpOS2InfoSize) { 67 return false; 68 } 69 colLen = 3; 70 width_ = GetShort(); 71 height_ = GetShort(); 72 GetShort(); // Planes. 73 bpp_ = GetShort(); 74 } 75 if (height_ < 0) { 76 height_ = -height_; 77 inverted_ = false; 78 } 79 if (width_ <= 0 || width_ > kMaxDim || height_ <= 0 || height_ > kMaxDim) { 80 return false; 81 } 82 if (width_ * height_ > max_pixels) { 83 return false; 84 } 85 if (cols < 0 || cols > 256) { 86 return false; 87 } 88 // Allocate then read in the colour map. 89 if (cols == 0 && bpp_ <= 8) { 90 cols = 1 << bpp_; 91 } 92 if (bpp_ <= 8 || cols > 0) { 93 uint8* colBuf = new uint8[256 * 3]; 94 memset(colBuf, '\0', 256 * 3); 95 colTab_.reset(colBuf); 96 } 97 if (cols > 0) { 98 if (pos_ + (cols * colLen) > len_) { 99 return false; 100 } 101 for (int i = 0; i < cols; ++i) { 102 int base = i * 3; 103 colTab_[base + 2] = GetByte(); 104 colTab_[base + 1] = GetByte(); 105 colTab_[base] = GetByte(); 106 if (colLen == 4) { 107 GetByte(); 108 } 109 } 110 } 111 // Read in the compression data if necessary. 112 redBits_ = 0x7c00; 113 greenBits_ = 0x03e0; 114 blueBits_ = 0x001f; 115 bool rle = false; 116 if (comp == 1 || comp == 2) { 117 rle = true; 118 } else if (comp == 3) { 119 if (pos_ + 12 > len_) { 120 return false; 121 } 122 redBits_ = GetInt() & 0xffff; 123 greenBits_ = GetInt() & 0xffff; 124 blueBits_ = GetInt() & 0xffff; 125 } 126 redShiftRight_ = CalcShiftRight(redBits_); 127 greenShiftRight_ = CalcShiftRight(greenBits_); 128 blueShiftRight_ = CalcShiftRight(blueBits_); 129 redShiftLeft_ = CalcShiftLeft(redBits_); 130 greenShiftLeft_ = CalcShiftLeft(greenBits_); 131 blueShiftLeft_ = CalcShiftLeft(blueBits_); 132 rowPad_ = 0; 133 pixelPad_ = 0; 134 int rowLen; 135 if (bpp_ == 32) { 136 rowLen = width_ * 4; 137 pixelPad_ = 1; 138 } else if (bpp_ == 24) { 139 rowLen = width_ * 3; 140 } else if (bpp_ == 16) { 141 rowLen = width_ * 2; 142 } else if (bpp_ == 8) { 143 rowLen = width_; 144 } else if (bpp_ == 4) { 145 rowLen = width_ / 2; 146 if (width_ & 1) { 147 rowLen++; 148 } 149 } else if (bpp_ == 1) { 150 rowLen = width_ / 8; 151 if (width_ & 7) { 152 rowLen++; 153 } 154 } else { 155 return false; 156 } 157 // Round the rowLen up to a multiple of 4. 158 if (rowLen % 4 != 0) { 159 rowPad_ = 4 - (rowLen % 4); 160 rowLen += rowPad_; 161 } 162 163 if (offset > 0 && offset > pos_ && offset < len_) { 164 pos_ = offset; 165 } 166 // Deliberately off-by-one; a load of BMPs seem to have their last byte 167 // missing. 168 if (!rle && (pos_ + (rowLen * height_) > len_ + 1)) { 169 return false; 170 } 171 172 output_ = callback->SetSize(width_, height_); 173 if (NULL == output_) { 174 return true; // meaning we succeeded, but they want us to stop now 175 } 176 177 if (rle && (bpp_ == 4 || bpp_ == 8)) { 178 DoRLEDecode(); 179 } else { 180 DoStandardDecode(); 181 } 182 return true; 183 } 184 185 void BmpDecoderHelper::DoRLEDecode() { 186 static const uint8 RLE_ESCAPE = 0; 187 static const uint8 RLE_EOL = 0; 188 static const uint8 RLE_EOF = 1; 189 static const uint8 RLE_DELTA = 2; 190 int x = 0; 191 int y = height_ - 1; 192 while (pos_ < len_ - 1) { 193 uint8 cmd = GetByte(); 194 if (cmd != RLE_ESCAPE) { 195 uint8 pixels = GetByte(); 196 int num = 0; 197 uint8 col = pixels; 198 while (cmd-- && x < width_) { 199 if (bpp_ == 4) { 200 if (num & 1) { 201 col = pixels & 0xf; 202 } else { 203 col = pixels >> 4; 204 } 205 } 206 PutPixel(x++, y, col); 207 num++; 208 } 209 } else { 210 cmd = GetByte(); 211 if (cmd == RLE_EOF) { 212 return; 213 } else if (cmd == RLE_EOL) { 214 x = 0; 215 y--; 216 if (y < 0) { 217 return; 218 } 219 } else if (cmd == RLE_DELTA) { 220 if (pos_ < len_ - 1) { 221 uint8 dx = GetByte(); 222 uint8 dy = GetByte(); 223 x += dx; 224 if (x > width_) { 225 x = width_; 226 } 227 y -= dy; 228 if (y < 0) { 229 return; 230 } 231 } 232 } else { 233 int num = 0; 234 int bytesRead = 0; 235 uint8 val = 0; 236 while (cmd-- && pos_ < len_) { 237 if (bpp_ == 8 || !(num & 1)) { 238 val = GetByte(); 239 bytesRead++; 240 } 241 uint8 col = val; 242 if (bpp_ == 4) { 243 if (num & 1) { 244 col = col & 0xf; 245 } else { 246 col >>= 4; 247 } 248 } 249 if (x < width_) { 250 PutPixel(x++, y, col); 251 } 252 num++; 253 } 254 // All pixel runs must be an even number of bytes - skip a byte if we 255 // read an odd number. 256 if ((bytesRead & 1) && pos_ < len_) { 257 GetByte(); 258 } 259 } 260 } 261 } 262 } 263 264 void BmpDecoderHelper::PutPixel(int x, int y, uint8 col) { 265 CHECK(x >= 0 && x < width_); 266 CHECK(y >= 0 && y < height_); 267 if (!inverted_) { 268 y = height_ - (y + 1); 269 } 270 271 int base = ((y * width_) + x) * 3; 272 int colBase = col * 3; 273 output_[base] = colTab_[colBase]; 274 output_[base + 1] = colTab_[colBase + 1]; 275 output_[base + 2] = colTab_[colBase + 2]; 276 } 277 278 void BmpDecoderHelper::DoStandardDecode() { 279 int row = 0; 280 uint8 currVal = 0; 281 for (int h = height_ - 1; h >= 0; h--, row++) { 282 int realH = h; 283 if (!inverted_) { 284 realH = height_ - (h + 1); 285 } 286 uint8* line = output_ + (3 * width_ * realH); 287 for (int w = 0; w < width_; w++) { 288 if (bpp_ >= 24) { 289 line[2] = GetByte(); 290 line[1] = GetByte(); 291 line[0] = GetByte(); 292 } else if (bpp_ == 16) { 293 uint32 val = GetShort(); 294 line[0] = ((val & redBits_) >> redShiftRight_) << redShiftLeft_; 295 line[1] = ((val & greenBits_) >> greenShiftRight_) << greenShiftLeft_; 296 line[2] = ((val & blueBits_) >> blueShiftRight_) << blueShiftLeft_; 297 } else if (bpp_ <= 8) { 298 uint8 col; 299 if (bpp_ == 8) { 300 col = GetByte(); 301 } else if (bpp_ == 4) { 302 if ((w % 2) == 0) { 303 currVal = GetByte(); 304 col = currVal >> 4; 305 } else { 306 col = currVal & 0xf; 307 } 308 } else { 309 if ((w % 8) == 0) { 310 currVal = GetByte(); 311 } 312 int bit = w & 7; 313 col = ((currVal >> (7 - bit)) & 1); 314 } 315 int base = col * 3; 316 line[0] = colTab_[base]; 317 line[1] = colTab_[base + 1]; 318 line[2] = colTab_[base + 2]; 319 } 320 line += 3; 321 for (int i = 0; i < pixelPad_; ++i) { 322 GetByte(); 323 } 324 } 325 for (int i = 0; i < rowPad_; ++i) { 326 GetByte(); 327 } 328 } 329 } 330 331 int BmpDecoderHelper::GetInt() { 332 uint8 b1 = GetByte(); 333 uint8 b2 = GetByte(); 334 uint8 b3 = GetByte(); 335 uint8 b4 = GetByte(); 336 return b1 | (b2 << 8) | (b3 << 16) | (b4 << 24); 337 } 338 339 int BmpDecoderHelper::GetShort() { 340 uint8 b1 = GetByte(); 341 uint8 b2 = GetByte(); 342 return b1 | (b2 << 8); 343 } 344 345 uint8 BmpDecoderHelper::GetByte() { 346 CHECK(pos_ >= 0 && pos_ <= len_); 347 // We deliberately allow this off-by-one access to cater for BMPs with their 348 // last byte missing. 349 if (pos_ == len_) { 350 return 0; 351 } 352 return data_[pos_++]; 353 } 354 355 int BmpDecoderHelper::CalcShiftRight(uint32 mask) { 356 int ret = 0; 357 while (mask != 0 && !(mask & 1)) { 358 mask >>= 1; 359 ret++; 360 } 361 return ret; 362 } 363 364 int BmpDecoderHelper::CalcShiftLeft(uint32 mask) { 365 int ret = 0; 366 while (mask != 0 && !(mask & 1)) { 367 mask >>= 1; 368 } 369 while (mask != 0 && !(mask & 0x80)) { 370 mask <<= 1; 371 ret++; 372 } 373 return ret; 374 } 375 376 } // namespace image_codec 377