180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru/* 380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru * Copyright 2007 The Android Open Source Project 480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru * 580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru * Use of this source code is governed by a BSD-style license that can be 680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru * found in the LICENSE file. 780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru */ 880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru// Author: cevans@google.com (Chris Evans) 1080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 1180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru#include "bmpdecoderhelper.h" 1280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 1380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Querunamespace image_codec { 1480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 1580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Querustatic const int kBmpHeaderSize = 14; 1680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Querustatic const int kBmpInfoSize = 40; 1780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Querustatic const int kBmpOS2InfoSize = 12; 1880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Querustatic const int kMaxDim = SHRT_MAX / 2; 1980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 2080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Querubool BmpDecoderHelper::DecodeImage(const char* p, 21910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger size_t len, 2280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru int max_pixels, 2380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru BmpDecoderCallback* callback) { 2480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru data_ = reinterpret_cast<const uint8*>(p); 2580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru pos_ = 0; 2680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru len_ = len; 2780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru inverted_ = true; 2880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru // Parse the header structure. 2980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru if (len < kBmpHeaderSize + 4) { 3080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru return false; 3180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 3280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru GetShort(); // Signature. 3380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru GetInt(); // Size. 3480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru GetInt(); // Reserved. 3580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru int offset = GetInt(); 3680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru // Parse the info structure. 3780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru int infoSize = GetInt(); 3880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru if (infoSize != kBmpOS2InfoSize && infoSize < kBmpInfoSize) { 3980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru return false; 4080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 4180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru int cols = 0; 4280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru int comp = 0; 4380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru int colLen = 4; 4480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru if (infoSize >= kBmpInfoSize) { 4580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru if (len < kBmpHeaderSize + kBmpInfoSize) { 4680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru return false; 4780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 4880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru width_ = GetInt(); 4980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru height_ = GetInt(); 5080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru GetShort(); // Planes. 5180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru bpp_ = GetShort(); 5280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru comp = GetInt(); 5380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru GetInt(); // Size. 5480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru GetInt(); // XPPM. 5580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru GetInt(); // YPPM. 5680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru cols = GetInt(); 5780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru GetInt(); // Important colours. 5880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } else { 5980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru if (len < kBmpHeaderSize + kBmpOS2InfoSize) { 6080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru return false; 6180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 6280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru colLen = 3; 6380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru width_ = GetShort(); 6480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru height_ = GetShort(); 6580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru GetShort(); // Planes. 6680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru bpp_ = GetShort(); 6780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 6880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru if (height_ < 0) { 6980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru height_ = -height_; 7080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru inverted_ = false; 7180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 7280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru if (width_ <= 0 || width_ > kMaxDim || height_ <= 0 || height_ > kMaxDim) { 7380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru return false; 7480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 7580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru if (width_ * height_ > max_pixels) { 7680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru return false; 7780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 7880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru if (cols < 0 || cols > 256) { 7980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru return false; 8080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 8180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru // Allocate then read in the colour map. 8280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru if (cols == 0 && bpp_ <= 8) { 8380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru cols = 1 << bpp_; 8480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 8580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru if (bpp_ <= 8 || cols > 0) { 8680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru uint8* colBuf = new uint8[256 * 3]; 8780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru memset(colBuf, '\0', 256 * 3); 8880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru colTab_.reset(colBuf); 8980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 9080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru if (cols > 0) { 9180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru if (pos_ + (cols * colLen) > len_) { 9280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru return false; 9380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 9480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru for (int i = 0; i < cols; ++i) { 9580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru int base = i * 3; 9680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru colTab_[base + 2] = GetByte(); 9780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru colTab_[base + 1] = GetByte(); 9880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru colTab_[base] = GetByte(); 9980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru if (colLen == 4) { 10080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru GetByte(); 10180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 10280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 10380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 10480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru // Read in the compression data if necessary. 10580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru redBits_ = 0x7c00; 10680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru greenBits_ = 0x03e0; 10780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru blueBits_ = 0x001f; 10880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru bool rle = false; 10980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru if (comp == 1 || comp == 2) { 11080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru rle = true; 11180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } else if (comp == 3) { 11280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru if (pos_ + 12 > len_) { 11380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru return false; 11480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 11580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru redBits_ = GetInt() & 0xffff; 11680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru greenBits_ = GetInt() & 0xffff; 11780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru blueBits_ = GetInt() & 0xffff; 11880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 11980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru redShiftRight_ = CalcShiftRight(redBits_); 12080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru greenShiftRight_ = CalcShiftRight(greenBits_); 12180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru blueShiftRight_ = CalcShiftRight(blueBits_); 12280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru redShiftLeft_ = CalcShiftLeft(redBits_); 12380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru greenShiftLeft_ = CalcShiftLeft(greenBits_); 12480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru blueShiftLeft_ = CalcShiftLeft(blueBits_); 12580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru rowPad_ = 0; 12680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru pixelPad_ = 0; 12780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru int rowLen; 12880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru if (bpp_ == 32) { 12980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru rowLen = width_ * 4; 13080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru pixelPad_ = 1; 13180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } else if (bpp_ == 24) { 13280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru rowLen = width_ * 3; 13380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } else if (bpp_ == 16) { 13480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru rowLen = width_ * 2; 13580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } else if (bpp_ == 8) { 13680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru rowLen = width_; 13780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } else if (bpp_ == 4) { 13880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru rowLen = width_ / 2; 13980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru if (width_ & 1) { 14080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru rowLen++; 14180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 14280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } else if (bpp_ == 1) { 14380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru rowLen = width_ / 8; 14480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru if (width_ & 7) { 14580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru rowLen++; 14680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 14780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } else { 14880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru return false; 14980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 15080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru // Round the rowLen up to a multiple of 4. 15180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru if (rowLen % 4 != 0) { 15280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru rowPad_ = 4 - (rowLen % 4); 15380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru rowLen += rowPad_; 15480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 15580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 156910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger if (offset > 0 && (size_t)offset > pos_ && (size_t)offset < len_) { 15780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru pos_ = offset; 15880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 15980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru // Deliberately off-by-one; a load of BMPs seem to have their last byte 16080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru // missing. 16180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru if (!rle && (pos_ + (rowLen * height_) > len_ + 1)) { 16280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru return false; 16380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 16480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 16580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru output_ = callback->SetSize(width_, height_); 16680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru if (NULL == output_) { 16780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru return true; // meaning we succeeded, but they want us to stop now 16880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 16980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 17080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru if (rle && (bpp_ == 4 || bpp_ == 8)) { 17180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru DoRLEDecode(); 17280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } else { 17380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru DoStandardDecode(); 17480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 17580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru return true; 17680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru} 17780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 17880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queruvoid BmpDecoderHelper::DoRLEDecode() { 17980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru static const uint8 RLE_ESCAPE = 0; 18080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru static const uint8 RLE_EOL = 0; 18180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru static const uint8 RLE_EOF = 1; 18280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru static const uint8 RLE_DELTA = 2; 18380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru int x = 0; 18480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru int y = height_ - 1; 185910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger while (pos_ + 1 < len_) { 18680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru uint8 cmd = GetByte(); 18780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru if (cmd != RLE_ESCAPE) { 18880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru uint8 pixels = GetByte(); 18980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru int num = 0; 19080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru uint8 col = pixels; 19180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru while (cmd-- && x < width_) { 19280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru if (bpp_ == 4) { 19380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru if (num & 1) { 19480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru col = pixels & 0xf; 19580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } else { 19680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru col = pixels >> 4; 19780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 19880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 19980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru PutPixel(x++, y, col); 20080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru num++; 20180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 20280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } else { 20380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru cmd = GetByte(); 20480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru if (cmd == RLE_EOF) { 20580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru return; 20680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } else if (cmd == RLE_EOL) { 20780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru x = 0; 20880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru y--; 20980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru if (y < 0) { 21080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru return; 21180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 21280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } else if (cmd == RLE_DELTA) { 213910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger if (pos_ + 1 < len_) { 21480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru uint8 dx = GetByte(); 21580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru uint8 dy = GetByte(); 21680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru x += dx; 21780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru if (x > width_) { 21880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru x = width_; 21980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 22080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru y -= dy; 22180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru if (y < 0) { 22280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru return; 22380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 22480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 22580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } else { 22680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru int num = 0; 22780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru int bytesRead = 0; 22880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru uint8 val = 0; 22980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru while (cmd-- && pos_ < len_) { 23080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru if (bpp_ == 8 || !(num & 1)) { 23180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru val = GetByte(); 23280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru bytesRead++; 23380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 23480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru uint8 col = val; 23580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru if (bpp_ == 4) { 23680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru if (num & 1) { 23780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru col = col & 0xf; 23880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } else { 23980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru col >>= 4; 24080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 24180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 24280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru if (x < width_) { 24380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru PutPixel(x++, y, col); 24480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 24580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru num++; 24680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 24780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru // All pixel runs must be an even number of bytes - skip a byte if we 24880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru // read an odd number. 24980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru if ((bytesRead & 1) && pos_ < len_) { 25080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru GetByte(); 25180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 25280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 25380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 25480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 25580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru} 25680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 25780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queruvoid BmpDecoderHelper::PutPixel(int x, int y, uint8 col) { 25880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru CHECK(x >= 0 && x < width_); 25980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru CHECK(y >= 0 && y < height_); 26080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru if (!inverted_) { 26180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru y = height_ - (y + 1); 26280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 26380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 26480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru int base = ((y * width_) + x) * 3; 26580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru int colBase = col * 3; 26680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru output_[base] = colTab_[colBase]; 26780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru output_[base + 1] = colTab_[colBase + 1]; 26880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru output_[base + 2] = colTab_[colBase + 2]; 26980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru} 27080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 27180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queruvoid BmpDecoderHelper::DoStandardDecode() { 27280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru int row = 0; 27380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru uint8 currVal = 0; 27480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru for (int h = height_ - 1; h >= 0; h--, row++) { 27580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru int realH = h; 27680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru if (!inverted_) { 27780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru realH = height_ - (h + 1); 27880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 27980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru uint8* line = output_ + (3 * width_ * realH); 28080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru for (int w = 0; w < width_; w++) { 28180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru if (bpp_ >= 24) { 28280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru line[2] = GetByte(); 28380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru line[1] = GetByte(); 28480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru line[0] = GetByte(); 28580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } else if (bpp_ == 16) { 28680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru uint32 val = GetShort(); 28780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru line[0] = ((val & redBits_) >> redShiftRight_) << redShiftLeft_; 28880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru line[1] = ((val & greenBits_) >> greenShiftRight_) << greenShiftLeft_; 28980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru line[2] = ((val & blueBits_) >> blueShiftRight_) << blueShiftLeft_; 29080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } else if (bpp_ <= 8) { 29180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru uint8 col; 29280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru if (bpp_ == 8) { 29380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru col = GetByte(); 29480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } else if (bpp_ == 4) { 29580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru if ((w % 2) == 0) { 29680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru currVal = GetByte(); 29780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru col = currVal >> 4; 29880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } else { 29980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru col = currVal & 0xf; 30080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 30180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } else { 30280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru if ((w % 8) == 0) { 30380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru currVal = GetByte(); 30480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 30580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru int bit = w & 7; 30680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru col = ((currVal >> (7 - bit)) & 1); 30780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 30880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru int base = col * 3; 30980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru line[0] = colTab_[base]; 31080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru line[1] = colTab_[base + 1]; 31180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru line[2] = colTab_[base + 2]; 31280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 31380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru line += 3; 31480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru for (int i = 0; i < pixelPad_; ++i) { 31580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru GetByte(); 31680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 31780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 31880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru for (int i = 0; i < rowPad_; ++i) { 31980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru GetByte(); 32080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 32180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 32280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru} 32380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 32480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queruint BmpDecoderHelper::GetInt() { 32580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru uint8 b1 = GetByte(); 32680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru uint8 b2 = GetByte(); 32780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru uint8 b3 = GetByte(); 32880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru uint8 b4 = GetByte(); 32980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru return b1 | (b2 << 8) | (b3 << 16) | (b4 << 24); 33080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru} 33180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 33280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queruint BmpDecoderHelper::GetShort() { 33380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru uint8 b1 = GetByte(); 33480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru uint8 b2 = GetByte(); 33580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru return b1 | (b2 << 8); 33680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru} 33780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 33880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queruuint8 BmpDecoderHelper::GetByte() { 339910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger CHECK(pos_ <= len_); 34080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru // We deliberately allow this off-by-one access to cater for BMPs with their 34180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru // last byte missing. 34280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru if (pos_ == len_) { 34380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru return 0; 34480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 34580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru return data_[pos_++]; 34680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru} 34780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 34880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queruint BmpDecoderHelper::CalcShiftRight(uint32 mask) { 34980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru int ret = 0; 35080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru while (mask != 0 && !(mask & 1)) { 35180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru mask >>= 1; 35280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru ret++; 35380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 35480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru return ret; 35580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru} 35680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 35780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queruint BmpDecoderHelper::CalcShiftLeft(uint32 mask) { 35880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru int ret = 0; 35980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru while (mask != 0 && !(mask & 1)) { 36080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru mask >>= 1; 36180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 36280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru while (mask != 0 && !(mask & 0x80)) { 36380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru mask <<= 1; 36480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru ret++; 36580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 36680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru return ret; 36780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru} 36880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 36980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru} // namespace image_codec 370