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