Home | History | Annotate | Download | only in images
      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 
     17 #include "bmpdecoderhelper.h"
     18 #include "SkImageDecoder.h"
     19 #include "SkScaledBitmapSampler.h"
     20 #include "SkStream.h"
     21 #include "SkColorPriv.h"
     22 #include "SkTDArray.h"
     23 #include "SkTRegistry.h"
     24 
     25 class SkBMPImageDecoder : public SkImageDecoder {
     26 public:
     27     SkBMPImageDecoder() {}
     28 
     29     virtual Format getFormat() const {
     30         return kBMP_Format;
     31     }
     32 
     33 protected:
     34     virtual bool onDecode(SkStream* stream, SkBitmap* bm, Mode mode);
     35 };
     36 
     37 static SkImageDecoder* Factory(SkStream* stream) {
     38     static const char kBmpMagic[] = { 'B', 'M' };
     39 
     40     size_t len = stream->getLength();
     41     char buffer[sizeof(kBmpMagic)];
     42 
     43     if (len > sizeof(kBmpMagic) &&
     44             stream->read(buffer, sizeof(kBmpMagic)) == sizeof(kBmpMagic) &&
     45             !memcmp(buffer, kBmpMagic, sizeof(kBmpMagic))) {
     46         return SkNEW(SkBMPImageDecoder);
     47     }
     48     return NULL;
     49 }
     50 
     51 static SkTRegistry<SkImageDecoder*, SkStream*> gReg(Factory);
     52 
     53 ///////////////////////////////////////////////////////////////////////////////
     54 
     55 class SkBmpDecoderCallback : public image_codec::BmpDecoderCallback {
     56 public:
     57     // we don't copy the bitmap, just remember the pointer
     58     SkBmpDecoderCallback(bool justBounds) : fJustBounds(justBounds) {}
     59 
     60     // override from BmpDecoderCallback
     61     virtual uint8* SetSize(int width, int height) {
     62         fWidth = width;
     63         fHeight = height;
     64         if (fJustBounds) {
     65             return NULL;
     66         }
     67 
     68         fRGB.setCount(width * height * 3);  // 3 == r, g, b
     69         return fRGB.begin();
     70     }
     71 
     72     int width() const { return fWidth; }
     73     int height() const { return fHeight; }
     74     uint8_t* rgb() const { return fRGB.begin(); }
     75 
     76 private:
     77     SkTDArray<uint8_t> fRGB;
     78     int fWidth;
     79     int fHeight;
     80     bool fJustBounds;
     81 };
     82 
     83 bool SkBMPImageDecoder::onDecode(SkStream* stream, SkBitmap* bm, Mode mode) {
     84 
     85     size_t length = stream->getLength();
     86     SkAutoMalloc storage(length);
     87 
     88     if (stream->read(storage.get(), length) != length) {
     89         return false;
     90     }
     91 
     92     const bool justBounds = SkImageDecoder::kDecodeBounds_Mode == mode;
     93     SkBmpDecoderCallback callback(justBounds);
     94 
     95     // Now decode the BMP into callback's rgb() array [r,g,b, r,g,b, ...]
     96     {
     97         image_codec::BmpDecoderHelper helper;
     98         const int max_pixels = 16383*16383; // max width*height
     99         if (!helper.DecodeImage((const char*)storage.get(), length,
    100                                 max_pixels, &callback)) {
    101             return false;
    102         }
    103     }
    104 
    105     // we don't need this anymore, so free it now (before we try to allocate
    106     // the bitmap's pixels) rather than waiting for its destructor
    107     storage.free();
    108 
    109     int width = callback.width();
    110     int height = callback.height();
    111     SkBitmap::Config config = this->getPrefConfig(k32Bit_SrcDepth, false);
    112 
    113     // only accept prefConfig if it makes sense for us
    114     if (SkBitmap::kARGB_4444_Config != config &&
    115             SkBitmap::kRGB_565_Config != config) {
    116         config = SkBitmap::kARGB_8888_Config;
    117     }
    118 
    119     SkScaledBitmapSampler sampler(width, height, getSampleSize());
    120 
    121     bm->setConfig(config, sampler.scaledWidth(), sampler.scaledHeight());
    122     bm->setIsOpaque(true);
    123     if (justBounds) {
    124         return true;
    125     }
    126 
    127     if (!this->allocPixelRef(bm, NULL)) {
    128         return false;
    129     }
    130 
    131     SkAutoLockPixels alp(*bm);
    132 
    133     if (!sampler.begin(bm, SkScaledBitmapSampler::kRGB, getDitherImage())) {
    134         return false;
    135     }
    136 
    137     const int srcRowBytes = width * 3;
    138     const int dstHeight = sampler.scaledHeight();
    139     const uint8_t* srcRow = callback.rgb();
    140 
    141     srcRow += sampler.srcY0() * srcRowBytes;
    142     for (int y = 0; y < dstHeight; y++) {
    143         sampler.next(srcRow);
    144         srcRow += sampler.srcDY() * srcRowBytes;
    145     }
    146     return true;
    147 }
    148