| Index: src/codec/SkCodec_wbmp.cpp
|
| diff --git a/src/codec/SkCodec_wbmp.cpp b/src/codec/SkCodec_wbmp.cpp
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..465c76d4dce109ed81d8c5c599ce7551d296b3c8
|
| --- /dev/null
|
| +++ b/src/codec/SkCodec_wbmp.cpp
|
| @@ -0,0 +1,165 @@
|
| +/*
|
| + * Copyright 2015 Google Inc.
|
| + *
|
| + * Use of this source code is governed by a BSD-style license that can be
|
| + * found in the LICENSE file.
|
| + */
|
| +
|
| +#include "SkCodec.h"
|
| +#include "SkColorPriv.h"
|
| +#include "SkStream.h"
|
| +#include "SkCodec_wbmp.h"
|
| +
|
| +// http://en.wikipedia.org/wiki/Variable-length_quantity
|
| +static bool read_mbf(SkStream* stream, uint64_t* value) {
|
| + uint64_t n = 0;
|
| + uint8_t data;
|
| + const uint64_t kLimit = 0xFE00000000000000;
|
| + SkASSERT(kLimit == ~((~static_cast<uint64_t>(0)) >> 7));
|
| + do {
|
| + if (n & kLimit) { // Will overflow on shift by 7.
|
| + return false;
|
| + }
|
| + if (stream->read(&data, 1) != 1) {
|
| + return false;
|
| + }
|
| + n = (n << 7) | (data & 0x7F);
|
| + } while (data & 0x80);
|
| + *value = n;
|
| + return true;
|
| +}
|
| +
|
| +static bool read_header(SkStream* stream, SkISize* size) {
|
| + uint64_t width, height;
|
| + uint16_t data;
|
| + if (stream->read(&data, 2) != 2 || data != 0) {
|
| + return false;
|
| + }
|
| + if (!read_mbf(stream, &width) || width > 0xFFFF || !width) {
|
| + return false;
|
| + }
|
| + if (!read_mbf(stream, &height) || width > 0xFFFF || !height) {
|
| + return false;
|
| + }
|
| + if (size) {
|
| + *size = SkISize::Make(SkToS32(width), SkToS32(height));
|
| + }
|
| + return true;
|
| +}
|
| +
|
| +#define BLACK SkPackARGB32NoCheck(0xFF, 0, 0, 0)
|
| +#define WHITE SkPackARGB32NoCheck(0xFF, 0xFF, 0xFF, 0xFF)
|
| +
|
| +#define GRAYSCALE_BLACK 0
|
| +#define GRAYSCALE_WHITE 0xFF
|
| +
|
| +#define RGB565_BLACK 0
|
| +#define RGB565_WHITE 0xFFFF
|
| +
|
| +static SkPMColor bit_to_pmcolor(U8CPU bit) { return bit ? WHITE : BLACK; }
|
| +
|
| +static uint8_t bit_to_bit(U8CPU bit) { return bit; }
|
| +
|
| +static uint8_t bit_to_grayscale(U8CPU bit) {
|
| + return bit ? GRAYSCALE_WHITE : GRAYSCALE_BLACK;
|
| +}
|
| +
|
| +static uint16_t bit_to_rgb565(U8CPU bit) {
|
| + return bit ? RGB565_WHITE : RGB565_BLACK;
|
| +}
|
| +
|
| +typedef void (*ExpandProc)(uint8_t*, const uint8_t*, int);
|
| +
|
| +// TODO(halcanary): Add this functionality (grayscale and indexed output) to
|
| +// SkSwizzler and use it here.
|
| +template <typename T, T (*TRANSFORM)(U8CPU)>
|
| +static void expand_bits_to_T(uint8_t* dstptr, const uint8_t* src, int bits) {
|
| + T* dst = reinterpret_cast<T*>(dstptr);
|
| + int bytes = bits >> 3;
|
| + for (int i = 0; i < bytes; i++) {
|
| + U8CPU mask = *src++;
|
| + for (int j = 0; j < 8; j++) {
|
| + dst[j] = TRANSFORM((mask >> (7 - j)) & 1);
|
| + }
|
| + dst += 8;
|
| + }
|
| + bits &= 7;
|
| + if (bits > 0) {
|
| + U8CPU mask = *src;
|
| + do {
|
| + *dst++ = TRANSFORM((mask >> 7) & 1);
|
| + mask <<= 1;
|
| + } while (--bits != 0);
|
| + }
|
| +}
|
| +
|
| +SkWbmpCodec::SkWbmpCodec(const SkImageInfo& info, SkStream* stream)
|
| + : INHERITED(info, stream) {}
|
| +
|
| +SkEncodedFormat SkWbmpCodec::onGetEncodedFormat() const {
|
| + return kWBMP_SkEncodedFormat;
|
| +}
|
| +
|
| +SkImageGenerator::Result SkWbmpCodec::onGetPixels(const SkImageInfo& info,
|
| + void* pixels,
|
| + size_t rowBytes,
|
| + const Options&,
|
| + SkPMColor ctable[],
|
| + int* ctableCount) {
|
| + SkCodec::RewindState rewindState = this->rewindIfNeeded();
|
| + if (rewindState == kCouldNotRewind_RewindState) {
|
| + return SkImageGenerator::kCouldNotRewind;
|
| + } else if (rewindState == kRewound_RewindState) {
|
| + (void)read_header(this->stream(), NULL);
|
| + }
|
| + if (info.dimensions() != this->getInfo().dimensions()) {
|
| + return SkImageGenerator::kInvalidScale;
|
| + }
|
| + ExpandProc proc = NULL;
|
| + switch (info.colorType()) {
|
| + case kGray_8_SkColorType:
|
| + proc = expand_bits_to_T<uint8_t, bit_to_grayscale>;
|
| + break;
|
| + case kN32_SkColorType:
|
| + proc = expand_bits_to_T<SkPMColor, bit_to_pmcolor>;
|
| + break;
|
| + case kIndex_8_SkColorType:
|
| + ctable[0] = BLACK;
|
| + ctable[1] = WHITE;
|
| + *ctableCount = 2;
|
| + proc = expand_bits_to_T<uint8_t, bit_to_bit>;
|
| + break;
|
| + case kRGB_565_SkColorType:
|
| + proc = expand_bits_to_T<uint16_t, bit_to_rgb565>;
|
| + break;
|
| + default:
|
| + return SkImageGenerator::kInvalidConversion;
|
| + }
|
| + SkISize size = info.dimensions();
|
| + uint8_t* dst = static_cast<uint8_t*>(pixels);
|
| + size_t srcRowBytes = SkAlign8(size.width()) >> 3;
|
| + SkAutoTMalloc<uint8_t> src(srcRowBytes);
|
| + for (int y = 0; y < size.height(); ++y) {
|
| + if (this->stream()->read(src.get(), srcRowBytes) != srcRowBytes) {
|
| + return SkImageGenerator::kIncompleteInput;
|
| + }
|
| + proc(dst, src.get(), size.width());
|
| + dst += rowBytes;
|
| + }
|
| + return SkImageGenerator::kSuccess;
|
| +}
|
| +
|
| +bool SkWbmpCodec::IsWbmp(SkStream* stream) {
|
| + return read_header(stream, NULL);
|
| +}
|
| +
|
| +SkCodec* SkWbmpCodec::NewFromStream(SkStream* stream) {
|
| + SkISize size;
|
| + if (!read_header(stream, &size)) {
|
| + return NULL;
|
| + }
|
| + SkImageInfo info =
|
| + SkImageInfo::Make(size.width(), size.height(), kGray_8_SkColorType,
|
| + kOpaque_SkAlphaType);
|
| + return SkNEW_ARGS(SkWbmpCodec, (info, stream));
|
| +}
|
|
|