aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar Mike Reed <reed@google.com>2018-05-29 15:41:27 -0400
committerGravatar Skia Commit-Bot <skia-commit-bot@chromium.org>2018-05-29 20:42:17 +0000
commitf2c736400f03f8fe7fe356962c979f23df4d5f6b (patch)
tree809d21837d0701569cccd0e21f23e2ac5574007a
parent4f078f7cfac6580dce6e213c022708922739ac6d (diff)
support image-subsets in serialization
A follow-on API change *could* be to extend the SerialProcs to pass subset information up to the client, in case they want to handle the subsetting step themselves. Bug: skia:7983 Change-Id: I36d3f1ce439886384495485c3be3c591d611a135 Reviewed-on: https://skia-review.googlesource.com/130543 Reviewed-by: Mike Klein <mtklein@google.com> Commit-Queue: Mike Reed <reed@google.com>
-rw-r--r--gm/image.cpp33
-rw-r--r--include/core/SkPicture.h3
-rw-r--r--src/core/SkImagePriv.h6
-rw-r--r--src/core/SkReadBuffer.cpp23
-rw-r--r--src/core/SkReadBuffer.h1
-rw-r--r--src/core/SkWriteBuffer.cpp10
-rw-r--r--src/image/SkImage.cpp5
-rw-r--r--src/image/SkImage_Base.h4
-rw-r--r--src/image/SkImage_Lazy.cpp4
9 files changed, 84 insertions, 5 deletions
diff --git a/gm/image.cpp b/gm/image.cpp
index fc91d6b7f1..2c1b8d8458 100644
--- a/gm/image.cpp
+++ b/gm/image.cpp
@@ -399,3 +399,36 @@ DEF_SIMPLE_GM(scalepixels_unpremul, canvas, 1080, 280) {
canvas->translate(pm2.width() + 10.0f, 0);
}
}
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+static sk_sp<SkImage> make_lazy_image(SkSurface* surf) {
+ surf->getCanvas()->drawCircle(100, 100, 100, SkPaint());
+ auto data = surf->makeImageSnapshot()->encodeToData();
+ return SkImage::MakeFromEncoded(data);
+}
+
+#include "SkWriteBuffer.h"
+#include "SkReadBuffer.h"
+static sk_sp<SkImage> serial_deserial(SkImage* img) {
+ SkBinaryWriteBuffer writer;
+ writer.writeImage(img);
+ size_t length = writer.bytesWritten();
+ auto data = SkData::MakeUninitialized(length);
+ writer.writeToMemory(data->writable_data());
+
+ SkReadBuffer reader(data->data(), length);
+ return reader.readImage();
+}
+
+DEF_SIMPLE_GM(image_subset, canvas, 440, 220) {
+ SkImageInfo info = SkImageInfo::MakeN32Premul(200, 200, nullptr);
+ auto surf = sk_tool_utils::makeSurface(canvas, info, nullptr);
+ auto img = make_lazy_image(surf.get());
+
+ canvas->drawImage(img, 10, 10, nullptr);
+ auto sub = img->makeSubset({100, 100, 200, 200});
+ canvas->drawImage(sub, 220, 10);
+ sub = serial_deserial(sub.get());
+ canvas->drawImage(sub, 220+110, 10);
+}
diff --git a/include/core/SkPicture.h b/include/core/SkPicture.h
index f0e9e0e731..3693a45d8a 100644
--- a/include/core/SkPicture.h
+++ b/include/core/SkPicture.h
@@ -169,10 +169,11 @@ private:
// V60: Remove flags in picture header
// V61: Change SkDrawPictureRec to take two colors rather than two alphas
// V62: Don't negate size of custom encoded images (don't write origin x,y either)
+ // V63: Store image bounds (including origin) instead of just width/height to support subsets
// Only SKPs within the min/current picture version range (inclusive) can be read.
static const uint32_t MIN_PICTURE_VERSION = 56; // august 2017
- static const uint32_t CURRENT_PICTURE_VERSION = 62;
+ static const uint32_t CURRENT_PICTURE_VERSION = 63;
static_assert(MIN_PICTURE_VERSION <= 62, "Remove kFontAxes_bad from SkFontDescriptor.cpp");
diff --git a/src/core/SkImagePriv.h b/src/core/SkImagePriv.h
index 7848bf4035..9172dd4c2c 100644
--- a/src/core/SkImagePriv.h
+++ b/src/core/SkImagePriv.h
@@ -77,6 +77,12 @@ bool SkImage_pinAsTexture(const SkImage*, GrContext*);
void SkImage_unpinAsTexture(const SkImage*, GrContext*);
/**
+ * Returns the bounds of the image relative to its encoded buffer. For all non-lazy images,
+ * this returns (0,0,width,height). For a lazy-image, it may return a subset of that rect.
+ */
+SkIRect SkImage_getSubset(const SkImage*);
+
+/**
* Returns a new image containing the same pixel values as the source, but with a different color
* space assigned. This performs no color space conversion. Primarily used in tests, to visualize
* the results of rendering in wide or narrow gamuts.
diff --git a/src/core/SkReadBuffer.cpp b/src/core/SkReadBuffer.cpp
index 0c2edf622d..3491428658 100644
--- a/src/core/SkReadBuffer.cpp
+++ b/src/core/SkReadBuffer.cpp
@@ -282,14 +282,28 @@ uint32_t SkReadBuffer::getArrayCount() {
return fError ? 0 : *(uint32_t*)fReader.peek();
}
+/* Format:
+ * (subset) width, height
+ * (subset) origin x, y
+ * size (31bits)
+ * data [ encoded, with raw width/height ]
+ */
sk_sp<SkImage> SkReadBuffer::readImage() {
if (fInflator) {
SkImage* img = fInflator->getImage(this->read32());
return img ? sk_ref_sp(img) : nullptr;
}
- int width = this->read32();
- int height = this->read32();
+ SkIRect bounds;
+ if (this->isVersionLT(kStoreImageBounds_Version)) {
+ bounds.fLeft = bounds.fTop = 0;
+ bounds.fRight = this->read32();
+ bounds.fBottom = this->read32();
+ } else {
+ this->readIRect(&bounds);
+ }
+ const int width = bounds.width();
+ const int height = bounds.height();
if (width <= 0 || height <= 0) { // SkImage never has a zero dimension
this->validate(false);
return nullptr;
@@ -338,6 +352,11 @@ sk_sp<SkImage> SkReadBuffer::readImage() {
if (!image) {
image = SkImage::MakeFromEncoded(std::move(data));
}
+ if (image) {
+ if (bounds.x() || bounds.y() || width < image->width() || height < image->height()) {
+ image = image->makeSubset(bounds);
+ }
+ }
// Question: are we correct to return an "empty" image instead of nullptr, if the decoder
// failed for some reason?
return image ? image : MakeEmptyImage(width, height);
diff --git a/src/core/SkReadBuffer.h b/src/core/SkReadBuffer.h
index 48a7aedf89..5f459cecef 100644
--- a/src/core/SkReadBuffer.h
+++ b/src/core/SkReadBuffer.h
@@ -78,6 +78,7 @@ public:
kRemoveHeaderFlags_Version = 60,
kTwoColorDrawShadow_Version = 61,
kDontNegateImageSize_Version = 62,
+ kStoreImageBounds_Version = 63,
};
/**
diff --git a/src/core/SkWriteBuffer.cpp b/src/core/SkWriteBuffer.cpp
index cb752c491f..b793dbf2dc 100644
--- a/src/core/SkWriteBuffer.cpp
+++ b/src/core/SkWriteBuffer.cpp
@@ -9,6 +9,7 @@
#include "SkBitmap.h"
#include "SkData.h"
#include "SkDeduper.h"
+#include "SkImagePriv.h"
#include "SkPaintPriv.h"
#include "SkPixelRef.h"
#include "SkPtrRecorder.h"
@@ -133,14 +134,19 @@ bool SkBinaryWriteBuffer::writeToStream(SkWStream* stream) {
return fWriter.writeToStream(stream);
}
+/* Format:
+ * (subset) bounds
+ * size (31bits)
+ * data [ encoded, with raw width/height ]
+ */
void SkBinaryWriteBuffer::writeImage(const SkImage* image) {
if (fDeduper) {
this->write32(fDeduper->findOrDefineImage(const_cast<SkImage*>(image)));
return;
}
- this->writeInt(image->width());
- this->writeInt(image->height());
+ const SkIRect bounds = SkImage_getSubset(image);
+ this->writeIRect(bounds);
sk_sp<SkData> data;
if (fProcs.fImageProc) {
diff --git a/src/image/SkImage.cpp b/src/image/SkImage.cpp
index 72285bd698..cc4419a904 100644
--- a/src/image/SkImage.cpp
+++ b/src/image/SkImage.cpp
@@ -411,6 +411,11 @@ void SkImage_unpinAsTexture(const SkImage* image, GrContext* ctx) {
as_IB(image)->onUnpinAsTexture(ctx);
}
+SkIRect SkImage_getSubset(const SkImage* image) {
+ SkASSERT(image);
+ return as_IB(image)->onGetSubset();
+}
+
///////////////////////////////////////////////////////////////////////////////////////////////////
sk_sp<SkImage> SkImageMakeRasterCopyAndAssignColorSpace(const SkImage* src,
diff --git a/src/image/SkImage_Base.h b/src/image/SkImage_Base.h
index 2049fb3561..0d54a39471 100644
--- a/src/image/SkImage_Base.h
+++ b/src/image/SkImage_Base.h
@@ -38,6 +38,10 @@ public:
virtual SkColorType onColorType() const = 0;
virtual SkAlphaType onAlphaType() const = 0;
+ virtual SkIRect onGetSubset() const {
+ return { 0, 0, this->width(), this->height() };
+ }
+
virtual bool onPeekPixels(SkPixmap*) const { return false; }
virtual const SkBitmap* onPeekBitmap() const { return nullptr; }
diff --git a/src/image/SkImage_Lazy.cpp b/src/image/SkImage_Lazy.cpp
index 82d573d708..7914f58d3c 100644
--- a/src/image/SkImage_Lazy.cpp
+++ b/src/image/SkImage_Lazy.cpp
@@ -77,6 +77,10 @@ public:
return fInfo.alphaType();
}
+ SkIRect onGetSubset() const override {
+ return SkIRect::MakeXYWH(fOrigin.fX, fOrigin.fY, fInfo.width(), fInfo.height());
+ }
+
bool onReadPixels(const SkImageInfo&, void*, size_t, int srcX, int srcY,
CachingHint) const override;
#if SK_SUPPORT_GPU