Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
SkRescaleAndReadPixels.cpp
Go to the documentation of this file.
1/*
2 * Copyright 2020 Google LLC
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
9
18#include "include/core/SkRect.h"
22
23#include <cmath>
24#include <cstddef>
25#include <memory>
26#include <utility>
27
29 const SkImageInfo& resultInfo,
30 const SkIRect& srcRect,
31 SkImage::RescaleGamma rescaleGamma,
32 SkImage::RescaleMode rescaleMode,
35 int srcW = srcRect.width();
36 int srcH = srcRect.height();
37
38 float sx = (float)resultInfo.width() / srcW;
39 float sy = (float)resultInfo.height() / srcH;
40 // How many bilerp/bicubic steps to do in X and Y. + means upscaling, - means downscaling.
41 int stepsX;
42 int stepsY;
43 if (rescaleMode != SkImage::RescaleMode::kNearest) {
44 stepsX = static_cast<int>((sx > 1.f) ? std::ceil(std::log2f(sx))
45 : std::floor(std::log2f(sx)));
46 stepsY = static_cast<int>((sy > 1.f) ? std::ceil(std::log2f(sy))
47 : std::floor(std::log2f(sy)));
48 } else {
49 stepsX = sx != 1.f;
50 stepsY = sy != 1.f;
51 }
52
54 paint.setBlendMode(SkBlendMode::kSrc);
55 if (stepsX < 0 || stepsY < 0) {
56 // Don't trigger MIP generation. We don't currently have a way to trigger bicubic for
57 // downscaling draws.
58
59 // TODO: should we trigger cubic now that we can?
60 if (rescaleMode != SkImage::RescaleMode::kNearest) {
61 rescaleMode = SkImage::RescaleMode::kRepeatedLinear;
62 }
63 }
64
65 auto rescaling_to_sampling = [](SkImage::RescaleMode rescaleMode) {
66 SkSamplingOptions sampling;
67 if (rescaleMode == SkImage::RescaleMode::kRepeatedLinear) {
69 } else if (rescaleMode == SkImage::RescaleMode::kRepeatedCubic) {
70 sampling = SkSamplingOptions({1.0f/3, 1.0f/3});
71 }
72 return sampling;
73 };
74 SkSamplingOptions sampling = rescaling_to_sampling(rescaleMode);
75
76 sk_sp<SkSurface> tempSurf;
77 sk_sp<SkImage> srcImage;
78 int srcX = srcRect.fLeft;
79 int srcY = srcRect.fTop;
81 // Assume we should ignore the rescale linear request if the surface has no color space since
82 // it's unclear how we'd linearize from an unknown color space.
83 if (rescaleGamma == SkSurface::RescaleGamma::kLinear && bmp.info().colorSpace() &&
84 !bmp.info().colorSpace()->gammaIsLinear()) {
85 auto cs = bmp.info().colorSpace()->makeLinearGamma();
86 // Promote to F16 color type to preserve precision.
87 auto ii = SkImageInfo::Make(srcW, srcH, kRGBA_F16_SkColorType, bmp.info().alphaType(),
88 std::move(cs));
89 auto linearSurf = SkSurfaces::Raster(ii);
90 if (!linearSurf) {
91 callback(context, nullptr);
92 return;
93 }
94 linearSurf->getCanvas()->drawImage(bmp.asImage().get(), -srcX, -srcY, sampling, &paint);
95 tempSurf = std::move(linearSurf);
96 srcImage = tempSurf->makeImageSnapshot();
97 srcX = 0;
98 srcY = 0;
100 } else {
101 // MakeFromBitmap would trigger a copy if bmp is mutable.
102 srcImage = SkImages::RasterFromPixmap(bmp.pixmap(), nullptr, nullptr);
103 }
104 while (stepsX || stepsY) {
105 int nextW = resultInfo.width();
106 int nextH = resultInfo.height();
107 if (stepsX < 0) {
108 nextW = resultInfo.width() << (-stepsX - 1);
109 stepsX++;
110 } else if (stepsX != 0) {
111 if (stepsX > 1) {
112 nextW = srcW * 2;
113 }
114 --stepsX;
115 }
116 if (stepsY < 0) {
117 nextH = resultInfo.height() << (-stepsY - 1);
118 stepsY++;
119 } else if (stepsY != 0) {
120 if (stepsY > 1) {
121 nextH = srcH * 2;
122 }
123 --stepsY;
124 }
125 auto ii = srcImage->imageInfo().makeWH(nextW, nextH);
126 if (!stepsX && !stepsY) {
127 // Might as well fold conversion to final info in the last step.
128 ii = resultInfo;
129 }
130 auto next = SkSurfaces::Raster(ii);
131 if (!next) {
132 callback(context, nullptr);
133 return;
134 }
135 next->getCanvas()->drawImageRect(
136 srcImage.get(), SkRect::Make(SkIRect::MakeXYWH(srcX, srcY, srcW, srcH)),
137 SkRect::MakeIWH(nextW, nextH), sampling, &paint, constraint);
138 tempSurf = std::move(next);
139 srcImage = tempSurf->makeImageSnapshot();
140 srcX = srcY = 0;
141 srcW = nextW;
142 srcH = nextH;
144 }
145
146 size_t rowBytes = resultInfo.minRowBytes();
147 std::unique_ptr<char[]> data(new char[resultInfo.height() * rowBytes]);
148 SkPixmap pm(resultInfo, data.get(), rowBytes);
149 if (srcImage->readPixels(nullptr, pm, srcX, srcY)) {
150 class Result : public SkImage::AsyncReadResult {
151 public:
152 Result(std::unique_ptr<const char[]> data, size_t rowBytes)
153 : fData(std::move(data)), fRowBytes(rowBytes) {}
154 int count() const override { return 1; }
155 const void* data(int i) const override { return fData.get(); }
156 size_t rowBytes(int i) const override { return fRowBytes; }
157
158 private:
159 std::unique_ptr<const char[]> fData;
160 size_t fRowBytes;
161 };
162 callback(context, std::make_unique<Result>(std::move(data), rowBytes));
163 } else {
164 callback(context, nullptr);
165 }
166}
static float next(float f)
@ kRGBA_F16_SkColorType
pixel with half floats for red, green, blue, alpha;
Definition SkColorType.h:38
void SkRescaleAndReadPixels(SkBitmap bmp, const SkImageInfo &resultInfo, const SkIRect &srcRect, SkImage::RescaleGamma rescaleGamma, SkImage::RescaleMode rescaleMode, SkImage::ReadPixelsCallback callback, SkImage::ReadPixelsContext context)
sk_sp< SkImage > asImage() const
Definition SkBitmap.cpp:645
const SkPixmap & pixmap() const
Definition SkBitmap.h:133
const SkImageInfo & info() const
Definition SkBitmap.h:139
SrcRectConstraint
Definition SkCanvas.h:1541
@ kStrict_SrcRectConstraint
sample only inside bounds; slower
Definition SkCanvas.h:1542
@ kFast_SrcRectConstraint
sample outside bounds; faster
Definition SkCanvas.h:1543
bool gammaIsLinear() const
sk_sp< SkColorSpace > makeLinearGamma() const
virtual size_t rowBytes(int i) const =0
virtual int count() const =0
virtual const void * data(int i) const =0
void * ReadPixelsContext
Definition SkImage.h:578
RescaleMode
Definition SkImage.h:587
RescaleGamma
Definition SkImage.h:585
void(ReadPixelsContext, std::unique_ptr< const AsyncReadResult >) ReadPixelsCallback
Definition SkImage.h:583
T * get() const
Definition SkRefCnt.h:303
const Paint & paint
FlKeyEvent uint64_t FlKeyResponderAsyncCallback callback
SK_API sk_sp< SkImage > RasterFromPixmap(const SkPixmap &pixmap, RasterReleaseProc rasterReleaseProc, ReleaseContext releaseContext)
SK_API sk_sp< SkSurface > Raster(const SkImageInfo &imageInfo, size_t rowBytes, const SkSurfaceProps *surfaceProps)
constexpr int32_t height() const
Definition SkRect.h:165
int32_t fTop
smaller y-axis bounds
Definition SkRect.h:34
constexpr int32_t width() const
Definition SkRect.h:158
static constexpr SkIRect MakeXYWH(int32_t x, int32_t y, int32_t w, int32_t h)
Definition SkRect.h:104
int32_t fLeft
smaller x-axis bounds
Definition SkRect.h:33
size_t minRowBytes() const
SkColorSpace * colorSpace() const
int width() const
static SkImageInfo Make(int width, int height, SkColorType ct, SkAlphaType at)
SkAlphaType alphaType() const
int height() const
static SkRect Make(const SkISize &size)
Definition SkRect.h:669
static SkRect MakeIWH(int w, int h)
Definition SkRect.h:623