2a1208017d
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
174 lines
4.3 KiB
C++
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);
|