From 20a7ecc49b9fe22b1a44629d717d1a51746773ef Mon Sep 17 00:00:00 2001 From: Leon Scroggins III Date: Mon, 19 Dec 2016 15:04:06 -0500 Subject: [PATCH] Implement scaling in SkCodecImageGenerator Plumb calls down to SkCodec. Add a gm Change-Id: I16da24eb739295ab72f487df02f19968151443f3 Reviewed-on: https://skia-review.googlesource.com/6287 Reviewed-by: Matt Sarett Commit-Queue: Leon Scroggins --- gm/codec_scaled.cpp | 124 ++++++++++++++++++++++++++++++++++++ gn/gm.gni | 1 + src/codec/SkCodecImageGenerator.cpp | 37 +++++++++++ src/codec/SkCodecImageGenerator.h | 6 ++ 4 files changed, 168 insertions(+) create mode 100644 gm/codec_scaled.cpp diff --git a/gm/codec_scaled.cpp b/gm/codec_scaled.cpp new file mode 100644 index 0000000..270de5d --- /dev/null +++ b/gm/codec_scaled.cpp @@ -0,0 +1,124 @@ +/* + * Copyright 2016 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "gm.h" +#include "SkCanvas.h" +#include "SkCodec.h" +#include "SkCodecImageGenerator.h" +#include "SkColor.h" +#include "SkCommandLineFlags.h" +#include "SkImageGenerator.h" +#include "SkString.h" +#include "Resources.h" + +DEFINE_string(codec_scaled, "brickwork-texture.jpg", "Image in resources/ to draw scaled."); + +class CodecScaledGM : public skiagm::GM { +private: + // FIXME: Once generateScaledPixels is plumbed to SkImage, store an SkImage + // and call SkImage::scalePixels. + std::unique_ptr fGenerator; + +public: + CodecScaledGM() + {} + +private: + SkString onShortName() override { + return SkString("codec_scaled"); + } + + SkISize onISize() override { + if (this->initCodec()) { + SkISize dim = fGenerator->getInfo().dimensions(); + // Wide enough to show 8 versions, corresponding to the options JPEG supports. + dim.fWidth *= 8; + // Tall enough to display 2 versions - one using computed dimensions, and one + // with scaling. + dim.fHeight *= 2; + return dim; + } + return SkISize::Make(640, 480); + } + + void onDrawBackground(SkCanvas* canvas) override { + canvas->clear(SK_ColorWHITE); + } + + bool initCodec() { + if (fGenerator) { + return true; + } + + if (FLAGS_codec_scaled.isEmpty()) { + SkDebugf("Nothing specified for --codec_scaled!"); + return false; + } + + SkString path = GetResourcePath(FLAGS_codec_scaled[0]); + sk_sp data(SkData::MakeFromFileName(path.c_str())); + if (!data) { + return false; + } + + fGenerator.reset(SkCodecImageGenerator::NewFromEncodedCodec(data)); + if (!fGenerator) { + SkDebugf("Could create codec from %s", FLAGS_codec_scaled[0]); + return false; + } + + return true; + } + + void onDraw(SkCanvas* canvas) override { + if (!this->initCodec()) { + return; + } + + SkPMColor colorStorage[256]; + int colorCount = 256; + sk_sp ctable(new SkColorTable(colorStorage, colorCount)); + + SkAutoCanvasRestore acr(canvas, true); + for (float scale : { 1.0f, .875f, .750f, .625f, .5f, .375f, .25f, .125f }) { + const auto info = fGenerator->getInfo(); + auto scaledInfo = info; + SkImageGenerator::SupportedSizes sizes; + if (fGenerator->computeScaledDimensions(scale, &sizes)) { + scaledInfo = info.makeWH(sizes.fSizes[0].fWidth, sizes.fSizes[0].fHeight); + } + + SkBitmap bm; + bm.setInfo(scaledInfo); + SkColorTable* ctablePtr = info.colorType() == kIndex_8_SkColorType ? ctable.get() + : nullptr; + bm.allocPixels(ctablePtr); + SkPixmap pixmap(scaledInfo, bm.getPixels(), bm.rowBytes(), ctablePtr); + if (fGenerator->generateScaledPixels(pixmap)) { + // If there's a color table, we need to use it. + SkBitmap bm2; + bm2.installPixels(pixmap); + canvas->drawBitmap(bm2, 0, 0); + } + + bm.setInfo(info); + bm.allocPixels(ctablePtr); + colorCount = 256; + if (fGenerator->getPixels(info, bm.getPixels(), bm.rowBytes(), + const_cast(ctable->readColors()), &colorCount)) { + SkAutoCanvasRestore acr2(canvas, true); + canvas->translate(0, SkIntToScalar(info.height())); + canvas->scale(SkFloatToScalar(scale), SkFloatToScalar(scale)); + canvas->drawBitmap(bm, 0, 0); + } + + canvas->translate(SkIntToScalar(info.width()), 0); + } + } +}; + +DEF_GM(return new CodecScaledGM); diff --git a/gn/gm.gni b/gn/gm.gni index a8e0eb4..8beb3e9 100644 --- a/gn/gm.gni +++ b/gn/gm.gni @@ -51,6 +51,7 @@ gm_sources = [ "$_gm/bug615686.cpp", "$_gm/cgm.c", "$_gm/cgms.cpp", + "$_gm/codec_scaled.cpp", "$_gm/circles.cpp", "$_gm/circulararcs.cpp", "$_gm/circularclips.cpp", diff --git a/src/codec/SkCodecImageGenerator.cpp b/src/codec/SkCodecImageGenerator.cpp index 447332b..fcbd7c3 100644 --- a/src/codec/SkCodecImageGenerator.cpp +++ b/src/codec/SkCodecImageGenerator.cpp @@ -47,6 +47,43 @@ bool SkCodecImageGenerator::onGetPixels(const SkImageInfo& info, void* pixels, s } } +bool SkCodecImageGenerator::onComputeScaledDimensions(SkScalar scale, SupportedSizes* sizes) { + SkASSERT(scale > 0 && scale <= 1); + const auto size = fCodec->getScaledDimensions(SkScalarToFloat(scale)); + if (size == this->getInfo().dimensions()) { + return false; + } + + // FIXME: Make SkCodec's API return two potential sizes, like this one. For now, set them both + // to be the same. + sizes->fSizes[0] = sizes->fSizes[1] = size; + return true; +} + +bool SkCodecImageGenerator::onGenerateScaledPixels(const SkPixmap& pixmap) { + SkPMColor colorStorage[256]; + int colorCount = 256; + const auto result = fCodec->getPixels(pixmap.info(), pixmap.writable_addr(), + pixmap.rowBytes(), nullptr, colorStorage, &colorCount); + switch (result) { + case SkCodec::kSuccess: + case SkCodec::kIncompleteInput: + break; + default: + return false; + } + + if (pixmap.colorType() == kIndex_8_SkColorType) { + // SkPixmap does not take ownership, so we need to hang onto this. + // FIXME: With a better API on SkCodec, the SkCodec could share its SkColorTable. + fColorTable.reset(new SkColorTable(colorStorage, colorCount)); + const_cast(pixmap).reset(pixmap.info(), pixmap.addr(), pixmap.rowBytes(), + fColorTable.get()); + } + return true; +} + + bool SkCodecImageGenerator::onQueryYUV8(SkYUVSizeInfo* sizeInfo, SkYUVColorSpace* colorSpace) const { return fCodec->queryYUV8(sizeInfo, colorSpace); diff --git a/src/codec/SkCodecImageGenerator.h b/src/codec/SkCodecImageGenerator.h index 222923b..e1aa220 100644 --- a/src/codec/SkCodecImageGenerator.h +++ b/src/codec/SkCodecImageGenerator.h @@ -6,6 +6,7 @@ */ #include "SkCodec.h" +#include "SkColorTable.h" #include "SkData.h" #include "SkImageGenerator.h" @@ -30,6 +31,10 @@ protected: bool onGetYUV8Planes(const SkYUVSizeInfo&, void* planes[3]) override; + bool onComputeScaledDimensions(SkScalar, SupportedSizes*) override; + + bool onGenerateScaledPixels(const SkPixmap&) override; + private: /* * Takes ownership of codec @@ -38,6 +43,7 @@ private: std::unique_ptr fCodec; sk_sp fData; + sk_sp fColorTable; typedef SkImageGenerator INHERITED; }; -- 2.7.4