expose direct methods for decoding to an image
These are meant to contrast MakeFromEncoded(), and emphasize that it is deferred/cached,
while the new methods are not.
Change-Id: I83ac22394cb14cdc84ff8507a514bf708734b84f
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/234476
Reviewed-by: Brian Osman <brianosman@google.com>
Commit-Queue: Mike Reed <reed@google.com>
diff --git a/RELEASE_NOTES.txt b/RELEASE_NOTES.txt
index 98892fd..6a833c6 100644
--- a/RELEASE_NOTES.txt
+++ b/RELEASE_NOTES.txt
@@ -10,6 +10,8 @@
* SkDrawLooper is no longer supported in SkPaint or SkCanvas.
+ * SkImage: new factories: DecodeToRaster, DecodeToTexture
+
* SkImageFilter API refactor started:
- Provide new factory API in include/effects/SkImageFilters
- Consolidated enum types to use SkTileMode and SkColorChannel
diff --git a/include/core/SkImage.h b/include/core/SkImage.h
index 96809fd..fef0021 100644
--- a/include/core/SkImage.h
+++ b/include/core/SkImage.h
@@ -154,19 +154,77 @@
static sk_sp<SkImage> MakeFromGenerator(std::unique_ptr<SkImageGenerator> imageGenerator,
const SkIRect* subset = nullptr);
- /** Creates SkImage from encoded data.
- subset allows selecting a portion of the full image. Pass nullptr to select the entire
- image; otherwise, subset must be contained by image bounds.
-
- SkImage is returned if format of the encoded data is recognized and supported.
- Recognized formats vary by platform.
-
- @param encoded data of SkImage to decode
- @param subset bounds of returned SkImage; may be nullptr
- @return created SkImage, or nullptr
+ /**
+ * Return an image backed by the encoded data, but attempt to defer decoding until the image
+ * is actually used/drawn. This deferral allows the system to cache the result, either on the
+ * CPU or on the GPU, depending on where the image is drawn. If memory is low, the cache may
+ * be purged, causing the next draw of the image to have to re-decode.
+ *
+ * The subset parameter specifies a area within the decoded image to create the image from.
+ * If subset is null, then the entire image is returned.
+ *
+ * This is similar to DecodeTo[Raster,Texture], but this method will attempt to defer the
+ * actual decode, while the DecodeTo... method explicitly decode and allocate the backend
+ * when the call is made.
+ *
+ * If the encoded format is not supported, or subset is outside of the bounds of the decoded
+ * image, nullptr is returned.
+ *
+ * @param encoded the encoded data
+ * @param length the number of bytes of encoded data
+ * @param subset the bounds of the pixels within the decoded image to return. may be null.
+ * @return created SkImage, or nullptr
*/
static sk_sp<SkImage> MakeFromEncoded(sk_sp<SkData> encoded, const SkIRect* subset = nullptr);
+ /**
+ * Decode the data in encoded/length into a raster image.
+ *
+ * The subset parameter specifies a area within the decoded image to create the image from.
+ * If subset is null, then the entire image is returned.
+ *
+ * This is similar to MakeFromEncoded, but this method will always decode immediately, and
+ * allocate the memory for the pixels for the lifetime of the returned image.
+ *
+ * If the encoded format is not supported, or subset is outside of the bounds of the decoded
+ * image, nullptr is returned.
+ *
+ * @param encoded the encoded data
+ * @param length the number of bytes of encoded data
+ * @param subset the bounds of the pixels within the decoded image to return. may be null.
+ * @return created SkImage, or nullptr
+ */
+ static sk_sp<SkImage> DecodeToRaster(const void* encoded, size_t length,
+ const SkIRect* subset = nullptr);
+ static sk_sp<SkImage> DecodeToRaster(const sk_sp<SkData>& data,
+ const SkIRect* subset = nullptr) {
+ return DecodeToRaster(data->data(), data->size(), subset);
+ }
+
+ /**
+ * Decode the data in encoded/length into a texture-backed image.
+ *
+ * The subset parameter specifies a area within the decoded image to create the image from.
+ * If subset is null, then the entire image is returned.
+ *
+ * This is similar to MakeFromEncoded, but this method will always decode immediately, and
+ * allocate the texture for the pixels for the lifetime of the returned image.
+ *
+ * If the encoded format is not supported, or subset is outside of the bounds of the decoded
+ * image, nullptr is returned.
+ *
+ * @param encoded the encoded data
+ * @param length the number of bytes of encoded data
+ * @param subset the bounds of the pixels within the decoded image to return. may be null.
+ * @return created SkImage, or nullptr
+ */
+ static sk_sp<SkImage> DecodeToTexture(GrContext* ctx, const void* encoded, size_t length,
+ const SkIRect* subset = nullptr);
+ static sk_sp<SkImage> DecodeToTexture(GrContext* ctx, const sk_sp<SkData>& data,
+ const SkIRect* subset = nullptr) {
+ return DecodeToTexture(ctx, data->data(), data->size(), subset);
+ }
+
// Experimental
enum CompressionType {
kETC1_CompressionType,
diff --git a/src/image/SkImage.cpp b/src/image/SkImage.cpp
index 079992a..ae0998c 100644
--- a/src/image/SkImage.cpp
+++ b/src/image/SkImage.cpp
@@ -410,6 +410,10 @@
#if !SK_SUPPORT_GPU
+sk_sp<SkImage> SkImage::DecodeToTexture(GrContext*, const void*, size_t, const SkIRect*) {
+ return nullptr;
+}
+
sk_sp<SkImage> SkImage::MakeFromTexture(GrContext* ctx,
const GrBackendTexture& tex, GrSurfaceOrigin origin,
SkColorType ct, SkAlphaType at, sk_sp<SkColorSpace> cs,
diff --git a/src/image/SkImage_Lazy.cpp b/src/image/SkImage_Lazy.cpp
index fbccdc2..5a9c9b2 100644
--- a/src/image/SkImage_Lazy.cpp
+++ b/src/image/SkImage_Lazy.cpp
@@ -287,6 +287,44 @@
return validator ? sk_make_sp<SkImage_Lazy>(&validator) : nullptr;
}
+sk_sp<SkImage> SkImage::DecodeToRaster(const void* encoded, size_t length, const SkIRect* subset) {
+ // The generator will not outlive this function, so we can wrap the encoded data without copy
+ auto gen = SkImageGenerator::MakeFromEncoded(SkData::MakeWithoutCopy(encoded, length));
+ if (!gen) {
+ return nullptr;
+ }
+ SkImageInfo info = gen->getInfo();
+ if (info.isEmpty()) {
+ return nullptr;
+ }
+
+ SkIPoint origin = {0, 0};
+ if (subset) {
+ if (!SkIRect::MakeWH(info.width(), info.height()).contains(*subset)) {
+ return nullptr;
+ }
+ info = info.makeWH(subset->width(), subset->height());
+ origin = {subset->x(), subset->y()};
+ }
+
+ size_t rb = info.minRowBytes();
+ if (rb == 0) {
+ return nullptr; // rb was too big
+ }
+ size_t size = info.computeByteSize(rb);
+ if (size == SIZE_MAX) {
+ return nullptr;
+ }
+ auto data = SkData::MakeUninitialized(size);
+
+ SkPixmap pmap(info, data->writable_data(), rb);
+ if (!generate_pixels(gen.get(), pmap, origin.x(), origin.y())) {
+ return nullptr;
+ }
+
+ return SkImage::MakeRasterData(info, data, rb);
+}
+
//////////////////////////////////////////////////////////////////////////////////////////////////
#if SK_SUPPORT_GPU
@@ -498,4 +536,14 @@
///////////////////////////////////////////////////////////////////////////////////////////////////
+sk_sp<SkImage> SkImage::DecodeToTexture(GrContext* ctx, const void* encoded, size_t length,
+ const SkIRect* subset) {
+ // img will not survive this function, so we don't need to copy/own the encoded data,
+ auto img = MakeFromEncoded(SkData::MakeWithoutCopy(encoded, length), subset);
+ if (!img) {
+ return nullptr;
+ }
+ return img->makeTextureImage(ctx, nullptr);
+}
+
#endif