skia2/src/images/SkImageDecoder_wbmp.cpp
scroggo 2a1208017d Qualify the return value of SkImageDecoder::decode
Add a new enum to differentiate between a complete decode and a
partial decode (with the third value being failure). Return this
value from SkImageDecoder::onDecode (in all subclasses, plus
SkImageDecoder_empty) and ::decode.

For convenience, if the enum is treated as a boolean, success and
partial success are both considered true.

Note that the static helper functions (DecodeFile etc) still return
true and false (for one thing, this allows us to continue to use
SkImageDecoder::DecodeMemory as an SkPicture::InstallPixelRefProc in
SkPicture::CreateFromStream).

Also correctly report failure in SkASTCImageDecoder::onDecode when
SkTextureCompressor::DecompressBufferFromFormat fails.

BUG=skia:3037
BUG:b/17419670

Review URL: https://codereview.chromium.org/647023006
2014-10-22 12:07:00 -07:00

174 lines
4.3 KiB
C++

/*
* Copyright 2006 The Android Open Source Project
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "SkImageDecoder.h"
#include "SkColor.h"
#include "SkColorPriv.h"
#include "SkMath.h"
#include "SkStream.h"
#include "SkTemplates.h"
#include "SkUtils.h"
class SkWBMPImageDecoder : public SkImageDecoder {
public:
virtual Format getFormat() const SK_OVERRIDE {
return kWBMP_Format;
}
protected:
virtual Result onDecode(SkStream* stream, SkBitmap* bm, Mode) SK_OVERRIDE;
private:
typedef SkImageDecoder INHERITED;
};
static bool read_byte(SkStream* stream, uint8_t* data)
{
return stream->read(data, 1) == 1;
}
static bool read_mbf(SkStream* stream, int* value)
{
int n = 0;
uint8_t data;
do {
if (!read_byte(stream, &data)) {
return false;
}
n = (n << 7) | (data & 0x7F);
} while (data & 0x80);
*value = n;
return true;
}
struct wbmp_head {
int fWidth;
int fHeight;
bool init(SkStream* stream)
{
uint8_t data;
if (!read_byte(stream, &data) || data != 0) { // unknown type
return false;
}
if (!read_byte(stream, &data) || (data & 0x9F)) { // skip fixed header
return false;
}
if (!read_mbf(stream, &fWidth) || (unsigned)fWidth > 0xFFFF) {
return false;
}
if (!read_mbf(stream, &fHeight) || (unsigned)fHeight > 0xFFFF) {
return false;
}
return fWidth != 0 && fHeight != 0;
}
};
static void expand_bits_to_bytes(uint8_t dst[], const uint8_t src[], int bits)
{
int bytes = bits >> 3;
for (int i = 0; i < bytes; i++) {
unsigned mask = *src++;
dst[0] = (mask >> 7) & 1;
dst[1] = (mask >> 6) & 1;
dst[2] = (mask >> 5) & 1;
dst[3] = (mask >> 4) & 1;
dst[4] = (mask >> 3) & 1;
dst[5] = (mask >> 2) & 1;
dst[6] = (mask >> 1) & 1;
dst[7] = (mask >> 0) & 1;
dst += 8;
}
bits &= 7;
if (bits > 0) {
unsigned mask = *src;
do {
*dst++ = (mask >> 7) & 1;;
mask <<= 1;
} while (--bits != 0);
}
}
SkImageDecoder::Result SkWBMPImageDecoder::onDecode(SkStream* stream, SkBitmap* decodedBitmap,
Mode mode)
{
wbmp_head head;
if (!head.init(stream)) {
return kFailure;
}
int width = head.fWidth;
int height = head.fHeight;
decodedBitmap->setInfo(SkImageInfo::Make(width, height,
kIndex_8_SkColorType, kOpaque_SkAlphaType));
if (SkImageDecoder::kDecodeBounds_Mode == mode) {
return kSuccess;
}
const SkPMColor colors[] = { SK_ColorBLACK, SK_ColorWHITE };
SkColorTable* ct = SkNEW_ARGS(SkColorTable, (colors, 2));
SkAutoUnref aur(ct);
if (!this->allocPixelRef(decodedBitmap, ct)) {
return kFailure;
}
SkAutoLockPixels alp(*decodedBitmap);
uint8_t* dst = decodedBitmap->getAddr8(0, 0);
// store the 1-bit valuess at the end of our pixels, so we won't stomp
// on them before we're read them. Just trying to avoid a temp allocation
size_t srcRB = SkAlign8(width) >> 3;
size_t srcSize = height * srcRB;
uint8_t* src = dst + decodedBitmap->getSize() - srcSize;
if (stream->read(src, srcSize) != srcSize) {
return kFailure;
}
for (int y = 0; y < height; y++)
{
expand_bits_to_bytes(dst, src, width);
dst += decodedBitmap->rowBytes();
src += srcRB;
}
return kSuccess;
}
///////////////////////////////////////////////////////////////////////////////
DEFINE_DECODER_CREATOR(WBMPImageDecoder);
///////////////////////////////////////////////////////////////////////////////
static SkImageDecoder* sk_wbmp_dfactory(SkStreamRewindable* stream) {
wbmp_head head;
if (head.init(stream)) {
return SkNEW(SkWBMPImageDecoder);
}
return NULL;
}
static SkImageDecoder::Format get_format_wbmp(SkStreamRewindable* stream) {
wbmp_head head;
if (head.init(stream)) {
return SkImageDecoder::kWBMP_Format;
}
return SkImageDecoder::kUnknown_Format;
}
static SkImageDecoder_DecodeReg gDReg(sk_wbmp_dfactory);
static SkImageDecoder_FormatReg gFormatReg(get_format_wbmp);