Skip to content

Commit 15b95d6

Browse files
reed-at-googleSkia Commit-Bot
authored andcommitted
Move image sampling options into their own header
Experimenting with a single struct for everything, to simplify the number of API changes/additions needed. e.g. makeShader(...) Idea is to use SkSampleOptions to augment drawBitmap calls, so we can remove SkFilterQuality enum from SkPaint. Change-Id: I9045ff483f58af29148d7dc21d30b294c4a718a1 Reviewed-on: https://skia-review.googlesource.com/c/skia/+/332739 Reviewed-by: Brian Salomon <bsalomon@google.com> Commit-Queue: Mike Reed <reed@google.com>
1 parent 7990e03 commit 15b95d6

File tree

6 files changed

+109
-109
lines changed

6 files changed

+109
-109
lines changed

include/core/SkImage.h

Lines changed: 3 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#include "include/core/SkImageInfo.h"
1414
#include "include/core/SkM44.h"
1515
#include "include/core/SkRefCnt.h"
16+
#include "include/core/SkSamplingOptions.h"
1617
#include "include/core/SkScalar.h"
1718
#include "include/core/SkShader.h"
1819
#include "include/core/SkTileMode.h"
@@ -41,22 +42,6 @@ class GrYUVABackendTextures;
4142

4243
struct SkYUVAIndex;
4344

44-
enum class SkSamplingMode {
45-
kNearest, // single sample point (nearest neighbor)
46-
kLinear, // interporate between 2x2 sample points (bilinear interpolation)
47-
};
48-
49-
enum class SkMipmapMode {
50-
kNone, // ignore mipmap levels, sample from the "base"
51-
kNearest, // sample from the nearest level
52-
kLinear, // interpolate between the two nearest levels
53-
};
54-
55-
struct SkFilterOptions {
56-
SkSamplingMode fSampling;
57-
SkMipmapMode fMipmap;
58-
};
59-
6045
class SkMipmapBuilder {
6146
public:
6247
SkMipmapBuilder(const SkImageInfo&);
@@ -731,36 +716,10 @@ class SK_API SkImage : public SkRefCnt {
731716
/**
732717
* Make a shader with the specified tiling and mipmap sampling.
733718
*/
734-
sk_sp<SkShader> makeShader(SkTileMode tmx, SkTileMode tmy, const SkFilterOptions&,
719+
sk_sp<SkShader> makeShader(SkTileMode tmx, SkTileMode tmy, const SkSamplingOptions&,
735720
const SkMatrix* localMatrix = nullptr) const;
736721

737-
/*
738-
* Specify B and C (each between 0...1) to create a shader that applies the corresponding
739-
* cubic reconstruction filter to the image.
740-
*
741-
* Example values:
742-
* B = 1/3, C = 1/3 "Mitchell" filter
743-
* B = 0, C = 1/2 "Catmull-Rom" filter
744-
*
745-
* See "Reconstruction Filters in Computer Graphics"
746-
* Don P. Mitchell
747-
* Arun N. Netravali
748-
* 1988
749-
* https://www.cs.utexas.edu/~fussell/courses/cs384g-fall2013/lectures/mitchell/Mitchell.pdf
750-
*
751-
* Desmos worksheet https://www.desmos.com/calculator/aghdpicrvr
752-
* Nice overview https://entropymine.com/imageworsener/bicubic/
753-
*/
754-
struct CubicResampler {
755-
float B, C;
756-
};
757-
758-
/**
759-
* Make a shader with the specified tiling and CubicResampler parameters.
760-
* Returns nullptr if the resampler values are outside of [0...1]
761-
*/
762-
sk_sp<SkShader> makeShader(SkTileMode tmx, SkTileMode tmy, CubicResampler,
763-
const SkMatrix* localMatrix = nullptr) const;
722+
using CubicResampler = SkCubicResampler;
764723

765724
/** Creates SkShader from SkImage. SkShader dimensions are taken from SkImage. SkShader uses
766725
SkTileMode rules to fill drawn area outside SkImage. localMatrix permits

include/core/SkSamplingOptions.h

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
/*
2+
* Copyright 2020 Google Inc.
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+
8+
#ifndef SkImageSampling_DEFINED
9+
#define SkImageSampling_DEFINED
10+
11+
#include "include/core/SkTypes.h"
12+
13+
enum class SkSamplingMode {
14+
kNearest, // single sample point (nearest neighbor)
15+
kLinear, // interporate between 2x2 sample points (bilinear interpolation)
16+
};
17+
18+
enum class SkMipmapMode {
19+
kNone, // ignore mipmap levels, sample from the "base"
20+
kNearest, // sample from the nearest level
21+
kLinear, // interpolate between the two nearest levels
22+
};
23+
24+
/*
25+
* Specify B and C (each between 0...1) to create a shader that applies the corresponding
26+
* cubic reconstruction filter to the image.
27+
*
28+
* Example values:
29+
* B = 1/3, C = 1/3 "Mitchell" filter
30+
* B = 0, C = 1/2 "Catmull-Rom" filter
31+
*
32+
* See "Reconstruction Filters in Computer Graphics"
33+
* Don P. Mitchell
34+
* Arun N. Netravali
35+
* 1988
36+
* https://www.cs.utexas.edu/~fussell/courses/cs384g-fall2013/lectures/mitchell/Mitchell.pdf
37+
*
38+
* Desmos worksheet https://www.desmos.com/calculator/aghdpicrvr
39+
* Nice overview https://entropymine.com/imageworsener/bicubic/
40+
*/
41+
struct SkCubicResampler {
42+
float B, C;
43+
};
44+
45+
struct SkFilterOptions {
46+
SkSamplingMode fSampling;
47+
SkMipmapMode fMipmap;
48+
};
49+
50+
struct SkSamplingOptions {
51+
bool fUseCubic;
52+
SkCubicResampler fCubic; //!< use if fUseCubic is true
53+
SkFilterOptions fFilter; //!< use if fUseCubic is false
54+
55+
SkSamplingOptions()
56+
: fUseCubic(false)
57+
, fCubic({0,0})
58+
, fFilter({SkSamplingMode::kNearest, SkMipmapMode::kNone})
59+
{}
60+
61+
SkSamplingOptions(const SkFilterOptions& filter)
62+
: fUseCubic(false)
63+
, fCubic({0,0}) // ignored
64+
, fFilter(filter)
65+
{}
66+
67+
SkSamplingOptions(const SkCubicResampler& cubic)
68+
: fUseCubic(true)
69+
, fCubic(cubic)
70+
, fFilter({SkSamplingMode::kNearest, SkMipmapMode::kNone}) // ignored
71+
{}
72+
};
73+
74+
#endif

samplecode/SampleXfer.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -206,7 +206,7 @@ class CubicResamplerDemo : public Sample {
206206
sk_sp<SkImage> fImage;
207207
SkRect fBounds;
208208

209-
void draw(SkCanvas* canvas, SkImage::CubicResampler cubic) const {
209+
void draw(SkCanvas* canvas, SkCubicResampler cubic) const {
210210
SkRect r = fBounds;
211211
SkPaint paint;
212212

@@ -219,7 +219,8 @@ class CubicResamplerDemo : public Sample {
219219
lm.postTranslate(r.width() + 10, 0);
220220

221221
paint.setShader(fImage->makeShader(SkTileMode::kClamp, SkTileMode::kClamp,
222-
{SkSamplingMode::kLinear, SkMipmapMode::kNone},
222+
SkFilterOptions{ SkSamplingMode::kLinear,
223+
SkMipmapMode::kNone },
223224
&lm));
224225
canvas->drawRect(r, paint);
225226

src/image/SkImage.cpp

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,7 @@ sk_sp<SkShader> SkImage::makeShader(SkTileMode tmx, SkTileMode tmy,
141141
}
142142

143143
sk_sp<SkShader> SkImage::makeShader(SkTileMode tmx, SkTileMode tmy,
144-
const SkFilterOptions& options,
144+
const SkSamplingOptions& options,
145145
const SkMatrix* localMatrix) const {
146146
return SkImageShader::Make(sk_ref_sp(const_cast<SkImage*>(this)), tmx, tmy,
147147
options, localMatrix);
@@ -153,12 +153,6 @@ sk_sp<SkShader> SkImage::makeShader(SkTileMode tmx, SkTileMode tmy,
153153
SkImageShader::FilterEnum(filtering));
154154
}
155155

156-
sk_sp<SkShader> SkImage::makeShader(SkTileMode tmx, SkTileMode tmy, CubicResampler cubic,
157-
const SkMatrix* localMatrix) const {
158-
return SkImageShader::Make(sk_ref_sp(const_cast<SkImage*>(this)), tmx, tmy, cubic,
159-
localMatrix);
160-
}
161-
162156
sk_sp<SkData> SkImage::encodeToData(SkEncodedImageFormat type, int quality) const {
163157
// Context TODO: Elevate GrDirectContext requirement to public API.
164158
auto dContext = as_IB(this)->directContext();

src/shaders/SkImageShader.cpp

Lines changed: 25 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -79,29 +79,17 @@ SkImageShader::SkImageShader(sk_sp<SkImage> img,
7979

8080
SkImageShader::SkImageShader(sk_sp<SkImage> img,
8181
SkTileMode tmx, SkTileMode tmy,
82-
const SkFilterOptions& options,
82+
const SkSamplingOptions& options,
8383
const SkMatrix* localMatrix)
8484
: INHERITED(localMatrix)
8585
, fImage(std::move(img))
8686
, fTileModeX(optimize(tmx, fImage->width()))
8787
, fTileModeY(optimize(tmy, fImage->height()))
88-
, fFilterEnum(FilterEnum::kUseFilterOptions)
88+
, fFilterEnum(options.fUseCubic ? FilterEnum::kUseCubicResampler
89+
: FilterEnum::kUseFilterOptions)
8990
, fClampAsIfUnpremul(false)
90-
, fFilterOptions(options)
91-
{}
92-
93-
SkImageShader::SkImageShader(sk_sp<SkImage> img,
94-
SkTileMode tmx, SkTileMode tmy,
95-
SkImage::CubicResampler cubic,
96-
const SkMatrix* localMatrix)
97-
: INHERITED(localMatrix)
98-
, fImage(std::move(img))
99-
, fTileModeX(optimize(tmx, fImage->width()))
100-
, fTileModeY(optimize(tmy, fImage->height()))
101-
, fFilterEnum(FilterEnum::kUseCubicResampler)
102-
, fClampAsIfUnpremul(false)
103-
, fFilterOptions({}) // ignored
104-
, fCubic(cubic)
91+
, fFilterOptions(options.fFilter)
92+
, fCubic(options.fCubic)
10593
{}
10694

10795
// fClampAsIfUnpremul is always false when constructed through public APIs,
@@ -116,23 +104,25 @@ sk_sp<SkFlattenable> SkImageShader::CreateProc(SkReadBuffer& buffer) {
116104
fe = buffer.read32LE<FilterEnum>(kLast);
117105
}
118106

119-
SkFilterOptions fo{ SkSamplingMode::kNearest, SkMipmapMode::kNone };
120-
SkImage::CubicResampler cubic{};
107+
SkSamplingOptions op;
121108

122109
if (buffer.isVersionLT(SkPicturePriv::kCubicResamplerImageShader_Version)) {
123110
if (!buffer.isVersionLT(SkPicturePriv::kFilterOptionsInImageShader_Version)) {
124-
fo.fSampling = buffer.read32LE<SkSamplingMode>(SkSamplingMode::kLinear);
125-
fo.fMipmap = buffer.read32LE<SkMipmapMode>(SkMipmapMode::kLinear);
111+
op.fUseCubic = false;
112+
op.fFilter.fSampling = buffer.read32LE<SkSamplingMode>(SkSamplingMode::kLinear);
113+
op.fFilter.fMipmap = buffer.read32LE<SkMipmapMode>(SkMipmapMode::kLinear);
126114
}
127115
} else {
128116
switch (fe) {
129117
case kUseFilterOptions:
130-
fo.fSampling = buffer.read32LE<SkSamplingMode>(SkSamplingMode::kLinear);
131-
fo.fMipmap = buffer.read32LE<SkMipmapMode>(SkMipmapMode::kLinear);
118+
op.fUseCubic = false;
119+
op.fFilter.fSampling = buffer.read32LE<SkSamplingMode>(SkSamplingMode::kLinear);
120+
op.fFilter.fMipmap = buffer.read32LE<SkMipmapMode>(SkMipmapMode::kLinear);
132121
break;
133122
case kUseCubicResampler:
134-
cubic.B = buffer.readScalar();
135-
cubic.C = buffer.readScalar();
123+
op.fUseCubic = true;
124+
op.fCubic.B = buffer.readScalar();
125+
op.fCubic.C = buffer.readScalar();
136126
break;
137127
default:
138128
break;
@@ -148,9 +138,8 @@ sk_sp<SkFlattenable> SkImageShader::CreateProc(SkReadBuffer& buffer) {
148138

149139
switch (fe) {
150140
case kUseFilterOptions:
151-
return SkImageShader::Make(std::move(img), tmx, tmy, fo, &localMatrix);
152141
case kUseCubicResampler:
153-
return SkImageShader::Make(std::move(img), tmx, tmy, cubic, &localMatrix);
142+
return SkImageShader::Make(std::move(img), tmx, tmy, op, &localMatrix);
154143
default:
155144
break;
156145
}
@@ -297,27 +286,21 @@ sk_sp<SkShader> SkImageShader::Make(sk_sp<SkImage> image,
297286

298287
sk_sp<SkShader> SkImageShader::Make(sk_sp<SkImage> image,
299288
SkTileMode tmx, SkTileMode tmy,
300-
const SkFilterOptions& options,
289+
const SkSamplingOptions& options,
301290
const SkMatrix* localMatrix) {
302-
if (!image) {
303-
return sk_make_sp<SkEmptyShader>();
304-
}
305-
return sk_sp<SkShader>{
306-
new SkImageShader(image, tmx, tmy, options, localMatrix)
291+
auto is_unit = [](float x) {
292+
return x >= 0 && x <= 1;
307293
};
308-
}
309-
310-
sk_sp<SkShader> SkImageShader::Make(sk_sp<SkImage> image, SkTileMode tmx, SkTileMode tmy,
311-
SkImage::CubicResampler cubic, const SkMatrix* localMatrix) {
312-
if (!(cubic.B >= 0 && cubic.B <= 1 &&
313-
cubic.C >= 0 && cubic.C <= 1)) {
314-
return nullptr;
294+
if (options.fUseCubic) {
295+
if (!is_unit(options.fCubic.B) || !is_unit(options.fCubic.C)) {
296+
return nullptr;
297+
}
315298
}
316299
if (!image) {
317300
return sk_make_sp<SkEmptyShader>();
318301
}
319302
return sk_sp<SkShader>{
320-
new SkImageShader(image, tmx, tmy, cubic, localMatrix)
303+
new SkImageShader(image, tmx, tmy, options, localMatrix)
321304
};
322305
}
323306

@@ -393,7 +376,7 @@ std::unique_ptr<GrFragmentProcessor> SkImageShader::asFragmentProcessor(
393376
GrSamplerState::Filter fm;
394377
GrSamplerState::MipmapMode mm;
395378
bool bicubic;
396-
SkImage::CubicResampler kernel = GrBicubicEffect::gMitchell;
379+
SkCubicResampler kernel = GrBicubicEffect::gMitchell;
397380

398381
switch (fFilterEnum) {
399382
case FilterEnum::kUseFilterOptions:

src/shaders/SkImageShader.h

Lines changed: 3 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -42,13 +42,7 @@ class SkImageShader : public SkShaderBase {
4242
static sk_sp<SkShader> Make(sk_sp<SkImage>,
4343
SkTileMode tmx,
4444
SkTileMode tmy,
45-
const SkFilterOptions&,
46-
const SkMatrix* localMatrix);
47-
48-
static sk_sp<SkShader> Make(sk_sp<SkImage>,
49-
SkTileMode tmx,
50-
SkTileMode tmy,
51-
SkImage::CubicResampler,
45+
const SkSamplingOptions&,
5246
const SkMatrix* localMatrix);
5347

5448
bool isOpaque() const override;
@@ -71,12 +65,7 @@ class SkImageShader : public SkShaderBase {
7165
SkImageShader(sk_sp<SkImage>,
7266
SkTileMode tmx,
7367
SkTileMode tmy,
74-
const SkFilterOptions&,
75-
const SkMatrix* localMatrix);
76-
SkImageShader(sk_sp<SkImage>,
77-
SkTileMode tmx,
78-
SkTileMode tmy,
79-
SkImage::CubicResampler,
68+
const SkSamplingOptions&,
8069
const SkMatrix* localMatrix);
8170

8271
void flatten(SkWriteBuffer&) const override;
@@ -114,7 +103,7 @@ class SkImageShader : public SkShaderBase {
114103
// only use this if fFilterEnum == kUseFilterOptions
115104
SkFilterOptions fFilterOptions;
116105
// only use this if fFilterEnum == kUseCubicResampler or kHigh
117-
SkImage::CubicResampler fCubic = {1/3.0f, 1/3.0f}; // Default to Mitchell-Netravali.
106+
SkCubicResampler fCubic = {1/3.0f, 1/3.0f}; // Default to Mitchell-Netravali.
118107

119108
friend class SkShaderBase;
120109
using INHERITED = SkShaderBase;

0 commit comments

Comments
 (0)