SkImageDecoder.cpp revision 62900b4c64401bc80ae85f6f5c87309a273cae10
18a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com/* libs/graphics/images/SkImageDecoder.cpp
28a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com**
38a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com** Copyright 2006, The Android Open Source Project
48a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com**
58a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com** Licensed under the Apache License, Version 2.0 (the "License");
68a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com** you may not use this file except in compliance with the License.
78a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com** You may obtain a copy of the License at
88a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com**
98a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com**     http://www.apache.org/licenses/LICENSE-2.0
108a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com**
118a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com** Unless required by applicable law or agreed to in writing, software
128a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com** distributed under the License is distributed on an "AS IS" BASIS,
138a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
148a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com** See the License for the specific language governing permissions and
158a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com** limitations under the License.
168a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com*/
178a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
188a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkImageDecoder.h"
198a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkBitmap.h"
208a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkPixelRef.h"
218a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkStream.h"
228a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkTemplates.h"
238a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
248a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comstatic SkBitmap::Config gDeviceConfig = SkBitmap::kNo_Config;
258a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
268a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comSkBitmap::Config SkImageDecoder::GetDeviceConfig()
278a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com{
288a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return gDeviceConfig;
298a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
308a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
318a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comvoid SkImageDecoder::SetDeviceConfig(SkBitmap::Config config)
328a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com{
338a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    gDeviceConfig = config;
348a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
358a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
368a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com///////////////////////////////////////////////////////////////////////////////
378a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
388a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comSkImageDecoder::SkImageDecoder()
398a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    : fPeeker(NULL), fChooser(NULL), fAllocator(NULL), fSampleSize(1),
408a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com      fDitherImage(true) {
418a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
428a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
438a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comSkImageDecoder::~SkImageDecoder() {
448a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fPeeker->safeUnref();
458a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fChooser->safeUnref();
468a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fAllocator->safeUnref();
478a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
488a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
498a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comSkImageDecoder::Format SkImageDecoder::getFormat() const {
508a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return kUnknown_Format;
518a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
528a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
538a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comSkImageDecoder::Peeker* SkImageDecoder::setPeeker(Peeker* peeker) {
548a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkRefCnt_SafeAssign(fPeeker, peeker);
558a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return peeker;
568a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
578a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
588a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comSkImageDecoder::Chooser* SkImageDecoder::setChooser(Chooser* chooser) {
598a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkRefCnt_SafeAssign(fChooser, chooser);
608a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return chooser;
618a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
628a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
638a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comSkBitmap::Allocator* SkImageDecoder::setAllocator(SkBitmap::Allocator* alloc) {
648a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkRefCnt_SafeAssign(fAllocator, alloc);
658a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return alloc;
668a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
678a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
688a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comvoid SkImageDecoder::setSampleSize(int size) {
698a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (size < 1) {
708a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        size = 1;
718a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
728a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fSampleSize = size;
738a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
748a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
758a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.combool SkImageDecoder::chooseFromOneChoice(SkBitmap::Config config, int width,
768a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                                         int height) const {
778a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    Chooser* chooser = fChooser;
788a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
798a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (NULL == chooser) {    // no chooser, we just say YES to decoding :)
808a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        return true;
818a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
828a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    chooser->begin(1);
838a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    chooser->inspect(0, config, width, height);
848a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return chooser->choose() == 0;
858a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
868a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
878a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.combool SkImageDecoder::allocPixelRef(SkBitmap* bitmap,
888a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                                   SkColorTable* ctable) const {
898a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return bitmap->allocPixels(fAllocator, ctable);
908a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
918a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
928a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com///////////////////////////////////////////////////////////////////////////////
938a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
9462900b4c64401bc80ae85f6f5c87309a273cae10reed@android.com/*  Technically, this should be 342, since that is the cutoff point between
9562900b4c64401bc80ae85f6f5c87309a273cae10reed@android.com    an index and 32bit bitmap (they take equal ram), but since 32bit is almost
9662900b4c64401bc80ae85f6f5c87309a273cae10reed@android.com    always faster, I bump up the value a bit.
9762900b4c64401bc80ae85f6f5c87309a273cae10reed@android.com*/
9862900b4c64401bc80ae85f6f5c87309a273cae10reed@android.com#define MIN_SIZE_FOR_INDEX  (512)
9962900b4c64401bc80ae85f6f5c87309a273cae10reed@android.com
10062900b4c64401bc80ae85f6f5c87309a273cae10reed@android.com/*  Return the "optimal" config for this bitmap. In this case, we just look to
10162900b4c64401bc80ae85f6f5c87309a273cae10reed@android.com    promote index bitmaps to full-color, since those are a little faster to
10262900b4c64401bc80ae85f6f5c87309a273cae10reed@android.com    draw (fewer memory lookups).
10362900b4c64401bc80ae85f6f5c87309a273cae10reed@android.com
10462900b4c64401bc80ae85f6f5c87309a273cae10reed@android.com    Seems like we could expose this to the caller through some exising or new
10562900b4c64401bc80ae85f6f5c87309a273cae10reed@android.com    proxy object, allowing them to decide (after sniffing some aspect of the
10662900b4c64401bc80ae85f6f5c87309a273cae10reed@android.com    original bitmap) what config they really want.
10762900b4c64401bc80ae85f6f5c87309a273cae10reed@android.com */
10862900b4c64401bc80ae85f6f5c87309a273cae10reed@android.comstatic SkBitmap::Config optimal_config(const SkBitmap& bm,
10962900b4c64401bc80ae85f6f5c87309a273cae10reed@android.com                                       SkBitmap::Config pref) {
11062900b4c64401bc80ae85f6f5c87309a273cae10reed@android.com    if (bm.config() != pref) {
11162900b4c64401bc80ae85f6f5c87309a273cae10reed@android.com        if (bm.config() == SkBitmap::kIndex8_Config) {
11262900b4c64401bc80ae85f6f5c87309a273cae10reed@android.com            Sk64 size64 = bm.getSize64();
11362900b4c64401bc80ae85f6f5c87309a273cae10reed@android.com            if (size64.is32()) {
11462900b4c64401bc80ae85f6f5c87309a273cae10reed@android.com                int32_t size = size64.get32();
11562900b4c64401bc80ae85f6f5c87309a273cae10reed@android.com                if (size < MIN_SIZE_FOR_INDEX) {
11662900b4c64401bc80ae85f6f5c87309a273cae10reed@android.com                    return SkBitmap::kARGB_8888_Config;
11762900b4c64401bc80ae85f6f5c87309a273cae10reed@android.com                }
11862900b4c64401bc80ae85f6f5c87309a273cae10reed@android.com            }
11962900b4c64401bc80ae85f6f5c87309a273cae10reed@android.com        }
12062900b4c64401bc80ae85f6f5c87309a273cae10reed@android.com    }
12162900b4c64401bc80ae85f6f5c87309a273cae10reed@android.com    return bm.config();
12262900b4c64401bc80ae85f6f5c87309a273cae10reed@android.com}
12362900b4c64401bc80ae85f6f5c87309a273cae10reed@android.com
1248a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.combool SkImageDecoder::decode(SkStream* stream, SkBitmap* bm,
1258a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                            SkBitmap::Config pref, Mode mode) {
12662900b4c64401bc80ae85f6f5c87309a273cae10reed@android.com    // pass a temporary bitmap, so that if we return false, we are assured of
12762900b4c64401bc80ae85f6f5c87309a273cae10reed@android.com    // leaving the caller's bitmap untouched.
1288a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkBitmap    tmp;
1298a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1308a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    // we reset this to false before calling onDecode
1318a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fShouldCancelDecode = false;
1328a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
13362900b4c64401bc80ae85f6f5c87309a273cae10reed@android.com    if (!this->onDecode(stream, &tmp, pref, mode)) {
13462900b4c64401bc80ae85f6f5c87309a273cae10reed@android.com        return false;
13562900b4c64401bc80ae85f6f5c87309a273cae10reed@android.com    }
13662900b4c64401bc80ae85f6f5c87309a273cae10reed@android.com
13762900b4c64401bc80ae85f6f5c87309a273cae10reed@android.com    SkBitmap::Config c = optimal_config(tmp, pref);
13862900b4c64401bc80ae85f6f5c87309a273cae10reed@android.com    if (c != tmp.config()) {
13962900b4c64401bc80ae85f6f5c87309a273cae10reed@android.com        if (mode == kDecodeBounds_Mode) {
14062900b4c64401bc80ae85f6f5c87309a273cae10reed@android.com            tmp.setConfig(c, tmp.width(), tmp.height());
14162900b4c64401bc80ae85f6f5c87309a273cae10reed@android.com        } else {
14262900b4c64401bc80ae85f6f5c87309a273cae10reed@android.com            SkBitmap tmp2;
14362900b4c64401bc80ae85f6f5c87309a273cae10reed@android.com            if (tmp.copyTo(&tmp2, c, this->getAllocator())) {
14462900b4c64401bc80ae85f6f5c87309a273cae10reed@android.com                tmp.swap(tmp2);
14562900b4c64401bc80ae85f6f5c87309a273cae10reed@android.com            }
14662900b4c64401bc80ae85f6f5c87309a273cae10reed@android.com        }
1478a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
14862900b4c64401bc80ae85f6f5c87309a273cae10reed@android.com    bm->swap(tmp);
14962900b4c64401bc80ae85f6f5c87309a273cae10reed@android.com    return true;
1508a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
1518a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1528a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com///////////////////////////////////////////////////////////////////////////////
1538a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1548a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.combool SkImageDecoder::DecodeFile(const char file[], SkBitmap* bm,
1558a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                                SkBitmap::Config pref,  Mode mode) {
1568a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkASSERT(file);
1578a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkASSERT(bm);
1588a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1598a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkFILEStream    stream(file);
1608a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (stream.isValid()) {
1618a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        if (SkImageDecoder::DecodeStream(&stream, bm, pref, mode)) {
1628a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            bm->pixelRef()->setURI(file);
1638a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        }
1648a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        return true;
1658a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
1668a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return false;
1678a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
1688a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1698a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.combool SkImageDecoder::DecodeMemory(const void* buffer, size_t size, SkBitmap* bm,
1708a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                                  SkBitmap::Config pref, Mode mode) {
1718a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (0 == size) {
1728a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        return false;
1738a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
1748a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkASSERT(buffer);
1758a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1768a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkMemoryStream  stream(buffer, size);
1778a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return SkImageDecoder::DecodeStream(&stream, bm, pref, mode);
1788a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
1798a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1808a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.combool SkImageDecoder::DecodeStream(SkStream* stream, SkBitmap* bm,
1818a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                                  SkBitmap::Config pref, Mode mode) {
1828a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkASSERT(stream);
1838a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkASSERT(bm);
1848a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1858a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    bool success = false;
1868a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkImageDecoder* codec = SkImageDecoder::Factory(stream);
1878a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1888a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (NULL != codec) {
1898a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        success = codec->decode(stream, bm, pref, mode);
1908a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        delete codec;
1918a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
1928a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return success;
1938a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
1948a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
195