gfx/skia/trunk/src/images/bmpdecoderhelper.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/gfx/skia/trunk/src/images/bmpdecoderhelper.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,369 @@
     1.4 +
     1.5 +/*
     1.6 + * Copyright 2007 The Android Open Source Project
     1.7 + *
     1.8 + * Use of this source code is governed by a BSD-style license that can be
     1.9 + * found in the LICENSE file.
    1.10 + */
    1.11 +
    1.12 +// Author: cevans@google.com (Chris Evans)
    1.13 +
    1.14 +#include "bmpdecoderhelper.h"
    1.15 +
    1.16 +namespace image_codec {
    1.17 +
    1.18 +static const int kBmpHeaderSize = 14;
    1.19 +static const int kBmpInfoSize = 40;
    1.20 +static const int kBmpOS2InfoSize = 12;
    1.21 +static const int kMaxDim = SHRT_MAX / 2;
    1.22 +
    1.23 +bool BmpDecoderHelper::DecodeImage(const char* p,
    1.24 +                                   size_t len,
    1.25 +                                   int max_pixels,
    1.26 +                                   BmpDecoderCallback* callback) {
    1.27 +  data_ = reinterpret_cast<const uint8*>(p);
    1.28 +  pos_ = 0;
    1.29 +  len_ = len;
    1.30 +  inverted_ = true;
    1.31 +  // Parse the header structure.
    1.32 +  if (len < kBmpHeaderSize + 4) {
    1.33 +    return false;
    1.34 +  }
    1.35 +  GetShort();  // Signature.
    1.36 +  GetInt();  // Size.
    1.37 +  GetInt();  // Reserved.
    1.38 +  int offset = GetInt();
    1.39 +  // Parse the info structure.
    1.40 +  int infoSize = GetInt();
    1.41 +  if (infoSize != kBmpOS2InfoSize && infoSize < kBmpInfoSize) {
    1.42 +    return false;
    1.43 +  }
    1.44 +  int cols = 0;
    1.45 +  int comp = 0;
    1.46 +  int colLen = 4;
    1.47 +  if (infoSize >= kBmpInfoSize) {
    1.48 +    if (len < kBmpHeaderSize + kBmpInfoSize) {
    1.49 +      return false;
    1.50 +    }
    1.51 +    width_ = GetInt();
    1.52 +    height_ = GetInt();
    1.53 +    GetShort();  // Planes.
    1.54 +    bpp_ = GetShort();
    1.55 +    comp = GetInt();
    1.56 +    GetInt();  // Size.
    1.57 +    GetInt();  // XPPM.
    1.58 +    GetInt();  // YPPM.
    1.59 +    cols = GetInt();
    1.60 +    GetInt();  // Important colours.
    1.61 +  } else {
    1.62 +    if (len < kBmpHeaderSize + kBmpOS2InfoSize) {
    1.63 +      return false;
    1.64 +    }
    1.65 +    colLen = 3;
    1.66 +    width_ = GetShort();
    1.67 +    height_ = GetShort();
    1.68 +    GetShort();  // Planes.
    1.69 +    bpp_ = GetShort();
    1.70 +  }
    1.71 +  if (height_ < 0) {
    1.72 +    height_ = -height_;
    1.73 +    inverted_ = false;
    1.74 +  }
    1.75 +  if (width_ <= 0 || width_ > kMaxDim || height_ <= 0 || height_ > kMaxDim) {
    1.76 +    return false;
    1.77 +  }
    1.78 +  if (width_ * height_ > max_pixels) {
    1.79 +    return false;
    1.80 +  }
    1.81 +  if (cols < 0 || cols > 256) {
    1.82 +    return false;
    1.83 +  }
    1.84 +  // Allocate then read in the colour map.
    1.85 +  if (cols == 0 && bpp_ <= 8) {
    1.86 +    cols = 1 << bpp_;
    1.87 +  }
    1.88 +  if (bpp_ <= 8 || cols > 0) {
    1.89 +    uint8* colBuf = new uint8[256 * 3];
    1.90 +    memset(colBuf, '\0', 256 * 3);
    1.91 +    colTab_.reset(colBuf);
    1.92 +  }
    1.93 +  if (cols > 0) {
    1.94 +    if (pos_ + (cols * colLen) > len_) {
    1.95 +      return false;
    1.96 +    }
    1.97 +    for (int i = 0; i < cols; ++i) {
    1.98 +      int base = i * 3;
    1.99 +      colTab_[base + 2] = GetByte();
   1.100 +      colTab_[base + 1] = GetByte();
   1.101 +      colTab_[base] = GetByte();
   1.102 +      if (colLen == 4) {
   1.103 +        GetByte();
   1.104 +      }
   1.105 +    }
   1.106 +  }
   1.107 +  // Read in the compression data if necessary.
   1.108 +  redBits_ = 0x7c00;
   1.109 +  greenBits_ = 0x03e0;
   1.110 +  blueBits_ = 0x001f;
   1.111 +  bool rle = false;
   1.112 +  if (comp == 1 || comp == 2) {
   1.113 +    rle = true;
   1.114 +  } else if (comp == 3) {
   1.115 +    if (pos_ + 12 > len_) {
   1.116 +      return false;
   1.117 +    }
   1.118 +    redBits_ = GetInt() & 0xffff;
   1.119 +    greenBits_ = GetInt() & 0xffff;
   1.120 +    blueBits_ = GetInt() & 0xffff;
   1.121 +  }
   1.122 +  redShiftRight_ = CalcShiftRight(redBits_);
   1.123 +  greenShiftRight_ = CalcShiftRight(greenBits_);
   1.124 +  blueShiftRight_ = CalcShiftRight(blueBits_);
   1.125 +  redShiftLeft_ = CalcShiftLeft(redBits_);
   1.126 +  greenShiftLeft_ = CalcShiftLeft(greenBits_);
   1.127 +  blueShiftLeft_ = CalcShiftLeft(blueBits_);
   1.128 +  rowPad_ = 0;
   1.129 +  pixelPad_ = 0;
   1.130 +  int rowLen;
   1.131 +  if (bpp_ == 32) {
   1.132 +    rowLen = width_ * 4;
   1.133 +    pixelPad_ = 1;
   1.134 +  } else if (bpp_ == 24) {
   1.135 +    rowLen = width_ * 3;
   1.136 +  } else if (bpp_ == 16) {
   1.137 +    rowLen = width_ * 2;
   1.138 +  } else if (bpp_ == 8) {
   1.139 +    rowLen = width_;
   1.140 +  } else if (bpp_ == 4) {
   1.141 +    rowLen = width_ / 2;
   1.142 +    if (width_ & 1) {
   1.143 +      rowLen++;
   1.144 +    }
   1.145 +  } else if (bpp_ == 1) {
   1.146 +    rowLen = width_ / 8;
   1.147 +    if (width_ & 7) {
   1.148 +      rowLen++;
   1.149 +    }
   1.150 +  } else {
   1.151 +    return false;
   1.152 +  }
   1.153 +  // Round the rowLen up to a multiple of 4.
   1.154 +  if (rowLen % 4 != 0) {
   1.155 +    rowPad_ = 4 - (rowLen % 4);
   1.156 +    rowLen += rowPad_;
   1.157 +  }
   1.158 +
   1.159 +  if (offset > 0 && (size_t)offset > pos_ && (size_t)offset < len_) {
   1.160 +    pos_ = offset;
   1.161 +  }
   1.162 +  // Deliberately off-by-one; a load of BMPs seem to have their last byte
   1.163 +  // missing.
   1.164 +  if (!rle && (pos_ + (rowLen * height_) > len_ + 1)) {
   1.165 +    return false;
   1.166 +  }
   1.167 +
   1.168 +  output_ = callback->SetSize(width_, height_);
   1.169 +  if (NULL == output_) {
   1.170 +    return true;  // meaning we succeeded, but they want us to stop now
   1.171 +  }
   1.172 +
   1.173 +  if (rle && (bpp_ == 4 || bpp_ == 8)) {
   1.174 +    DoRLEDecode();
   1.175 +  } else {
   1.176 +    DoStandardDecode();
   1.177 +  }
   1.178 +  return true;
   1.179 +}
   1.180 +
   1.181 +void BmpDecoderHelper::DoRLEDecode() {
   1.182 +  static const uint8 RLE_ESCAPE = 0;
   1.183 +  static const uint8 RLE_EOL = 0;
   1.184 +  static const uint8 RLE_EOF = 1;
   1.185 +  static const uint8 RLE_DELTA = 2;
   1.186 +  int x = 0;
   1.187 +  int y = height_ - 1;
   1.188 +  while (pos_ + 1 < len_) {
   1.189 +    uint8 cmd = GetByte();
   1.190 +    if (cmd != RLE_ESCAPE) {
   1.191 +      uint8 pixels = GetByte();
   1.192 +      int num = 0;
   1.193 +      uint8 col = pixels;
   1.194 +      while (cmd-- && x < width_) {
   1.195 +        if (bpp_ == 4) {
   1.196 +          if (num & 1) {
   1.197 +            col = pixels & 0xf;
   1.198 +          } else {
   1.199 +            col = pixels >> 4;
   1.200 +          }
   1.201 +        }
   1.202 +        PutPixel(x++, y, col);
   1.203 +        num++;
   1.204 +      }
   1.205 +    } else {
   1.206 +      cmd = GetByte();
   1.207 +      if (cmd == RLE_EOF) {
   1.208 +        return;
   1.209 +      } else if (cmd == RLE_EOL) {
   1.210 +        x = 0;
   1.211 +        y--;
   1.212 +        if (y < 0) {
   1.213 +          return;
   1.214 +        }
   1.215 +      } else if (cmd == RLE_DELTA) {
   1.216 +        if (pos_ + 1 < len_) {
   1.217 +          uint8 dx = GetByte();
   1.218 +          uint8 dy = GetByte();
   1.219 +          x += dx;
   1.220 +          if (x > width_) {
   1.221 +            x = width_;
   1.222 +          }
   1.223 +          y -= dy;
   1.224 +          if (y < 0) {
   1.225 +            return;
   1.226 +          }
   1.227 +        }
   1.228 +      } else {
   1.229 +        int num = 0;
   1.230 +        int bytesRead = 0;
   1.231 +        uint8 val = 0;
   1.232 +        while (cmd-- && pos_ < len_) {
   1.233 +          if (bpp_ == 8 || !(num & 1)) {
   1.234 +            val = GetByte();
   1.235 +            bytesRead++;
   1.236 +          }
   1.237 +          uint8 col = val;
   1.238 +          if (bpp_ == 4) {
   1.239 +            if (num & 1) {
   1.240 +              col = col & 0xf;
   1.241 +            } else {
   1.242 +              col >>= 4;
   1.243 +            }
   1.244 +          }
   1.245 +          if (x < width_) {
   1.246 +            PutPixel(x++, y, col);
   1.247 +          }
   1.248 +          num++;
   1.249 +        }
   1.250 +        // All pixel runs must be an even number of bytes - skip a byte if we
   1.251 +        // read an odd number.
   1.252 +        if ((bytesRead & 1) && pos_ < len_) {
   1.253 +          GetByte();
   1.254 +        }
   1.255 +      }
   1.256 +    }
   1.257 +  }
   1.258 +}
   1.259 +
   1.260 +void BmpDecoderHelper::PutPixel(int x, int y, uint8 col) {
   1.261 +  CHECK(x >= 0 && x < width_);
   1.262 +  CHECK(y >= 0 && y < height_);
   1.263 +  if (!inverted_) {
   1.264 +    y = height_ - (y + 1);
   1.265 +  }
   1.266 +
   1.267 +  int base = ((y * width_) + x) * 3;
   1.268 +  int colBase = col * 3;
   1.269 +  output_[base] = colTab_[colBase];
   1.270 +  output_[base + 1] = colTab_[colBase + 1];
   1.271 +  output_[base + 2] = colTab_[colBase + 2];
   1.272 +}
   1.273 +
   1.274 +void BmpDecoderHelper::DoStandardDecode() {
   1.275 +  int row = 0;
   1.276 +  uint8 currVal = 0;
   1.277 +  for (int h = height_ - 1; h >= 0; h--, row++) {
   1.278 +    int realH = h;
   1.279 +    if (!inverted_) {
   1.280 +      realH = height_ - (h + 1);
   1.281 +    }
   1.282 +    uint8* line = output_ + (3 * width_ * realH);
   1.283 +    for (int w = 0; w < width_; w++) {
   1.284 +      if (bpp_ >= 24) {
   1.285 +        line[2] = GetByte();
   1.286 +        line[1] = GetByte();
   1.287 +        line[0] = GetByte();
   1.288 +      } else if (bpp_ == 16) {
   1.289 +        uint32 val = GetShort();
   1.290 +        line[0] = ((val & redBits_) >> redShiftRight_) << redShiftLeft_;
   1.291 +        line[1] = ((val & greenBits_) >> greenShiftRight_) << greenShiftLeft_;
   1.292 +        line[2] = ((val & blueBits_) >> blueShiftRight_) << blueShiftLeft_;
   1.293 +      } else if (bpp_ <= 8) {
   1.294 +        uint8 col;
   1.295 +        if (bpp_ == 8) {
   1.296 +          col = GetByte();
   1.297 +        } else if (bpp_ == 4) {
   1.298 +          if ((w % 2) == 0) {
   1.299 +            currVal = GetByte();
   1.300 +            col = currVal >> 4;
   1.301 +          } else {
   1.302 +            col = currVal & 0xf;
   1.303 +          }
   1.304 +        } else {
   1.305 +          if ((w % 8) == 0) {
   1.306 +            currVal = GetByte();
   1.307 +          }
   1.308 +          int bit = w & 7;
   1.309 +          col = ((currVal >> (7 - bit)) & 1);
   1.310 +        }
   1.311 +        int base = col * 3;
   1.312 +        line[0] = colTab_[base];
   1.313 +        line[1] = colTab_[base + 1];
   1.314 +        line[2] = colTab_[base + 2];
   1.315 +      }
   1.316 +      line += 3;
   1.317 +      for (int i = 0; i < pixelPad_; ++i) {
   1.318 +        GetByte();
   1.319 +      }
   1.320 +    }
   1.321 +    for (int i = 0; i < rowPad_; ++i) {
   1.322 +      GetByte();
   1.323 +    }
   1.324 +  }
   1.325 +}
   1.326 +
   1.327 +int BmpDecoderHelper::GetInt() {
   1.328 +  uint8 b1 = GetByte();
   1.329 +  uint8 b2 = GetByte();
   1.330 +  uint8 b3 = GetByte();
   1.331 +  uint8 b4 = GetByte();
   1.332 +  return b1 | (b2 << 8) | (b3 << 16) | (b4 << 24);
   1.333 +}
   1.334 +
   1.335 +int BmpDecoderHelper::GetShort() {
   1.336 +  uint8 b1 = GetByte();
   1.337 +  uint8 b2 = GetByte();
   1.338 +  return b1 | (b2 << 8);
   1.339 +}
   1.340 +
   1.341 +uint8 BmpDecoderHelper::GetByte() {
   1.342 +  CHECK(pos_ <= len_);
   1.343 +  // We deliberately allow this off-by-one access to cater for BMPs with their
   1.344 +  // last byte missing.
   1.345 +  if (pos_ == len_) {
   1.346 +    return 0;
   1.347 +  }
   1.348 +  return data_[pos_++];
   1.349 +}
   1.350 +
   1.351 +int BmpDecoderHelper::CalcShiftRight(uint32 mask) {
   1.352 +  int ret = 0;
   1.353 +  while (mask != 0 && !(mask & 1)) {
   1.354 +    mask >>= 1;
   1.355 +    ret++;
   1.356 +  }
   1.357 +  return ret;
   1.358 +}
   1.359 +
   1.360 +int BmpDecoderHelper::CalcShiftLeft(uint32 mask) {
   1.361 +  int ret = 0;
   1.362 +  while (mask != 0 && !(mask & 1)) {
   1.363 +    mask >>= 1;
   1.364 +  }
   1.365 +  while (mask != 0 && !(mask & 0x80)) {
   1.366 +    mask <<= 1;
   1.367 +    ret++;
   1.368 +  }
   1.369 +  return ret;
   1.370 +}
   1.371 +
   1.372 +}  // namespace image_codec

mercurial