// SkCodec's wbmp decoder was initially more restrictive than SkImageDecoder. // It required the second byte to be zero. But SkImageDecoder allowed a couple // of bits to be 1 (so long as they do not overlap with 0x9F). Test that // SkCodec now supports an image with these bits set. DEF_TEST(Codec_wbmp, r) { const char* path = "mandrill.wbmp"; SkAutoTDelete<SkStream> stream(resource(path)); if (!stream) { SkDebugf("Missing resource '%s'\n", path); return; } // Modify the stream to contain a second byte with some bits set. SkAutoTUnref<SkData> data(SkCopyStreamToData(stream)); uint8_t* writeableData = static_cast<uint8_t*>(data->writable_data()); writeableData[1] = static_cast<uint8_t>(~0x9F); // SkImageDecoder supports this. SkBitmap bitmap; REPORTER_ASSERT(r, SkImageDecoder::DecodeMemory(data->data(), data->size(), &bitmap)); // So SkCodec should, too. SkAutoTDelete<SkCodec> codec(SkCodec::NewFromData(data)); REPORTER_ASSERT(r, codec); if (!codec) { return; } test_info(r, codec.get(), codec->getInfo(), SkCodec::kSuccess, nullptr); }
SkImageDecoder::Result SkBMPImageDecoder::onDecode(SkStream* stream, SkBitmap* bm, Mode mode) { // First read the entire stream, so that all of the data can be passed to // the BmpDecoderHelper. auto data = SkCopyStreamToData(stream); if (!data) { return kFailure; } // Byte length of all of the data. const size_t length = data->size(); if (0 == length) { return kFailure; } const bool justBounds = SkImageDecoder::kDecodeBounds_Mode == mode; SkBmpDecoderCallback callback(justBounds); // Now decode the BMP into callback's rgb() array [r,g,b, r,g,b, ...] { image_codec::BmpDecoderHelper helper; const int max_pixels = 16383*16383; // max width*height if (!helper.DecodeImage((const char*) data->data(), length, max_pixels, &callback)) { return kFailure; } } // we don't need this anymore, so free it now (before we try to allocate // the bitmap's pixels) rather than waiting for its destructor data.reset(nullptr); int width = callback.width(); int height = callback.height(); SkColorType colorType = this->getPrefColorType(k32Bit_SrcDepth, false); // only accept prefConfig if it makes sense for us if (kARGB_4444_SkColorType != colorType && kRGB_565_SkColorType != colorType) { colorType = kN32_SkColorType; } SkScaledBitmapSampler sampler(width, height, getSampleSize()); bm->setInfo(SkImageInfo::Make(sampler.scaledWidth(), sampler.scaledHeight(), colorType, kOpaque_SkAlphaType)); if (justBounds) { return kSuccess; } if (!this->allocPixelRef(bm, nullptr)) { return kFailure; } SkAutoLockPixels alp(*bm); if (!sampler.begin(bm, SkScaledBitmapSampler::kRGB, *this)) { return kFailure; } const int srcRowBytes = width * 3; const int dstHeight = sampler.scaledHeight(); const uint8_t* srcRow = callback.rgb(); srcRow += sampler.srcY0() * srcRowBytes; for (int y = 0; y < dstHeight; y++) { sampler.next(srcRow); srcRow += sampler.srcDY() * srcRowBytes; } return kSuccess; }