Extend drawAtlas with optional sampling parameter

Change-Id: Id26f0d9ca5381da807b072c8b59745f2afd8df60
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/386860
Reviewed-by: Kevin Lubick <kjlubick@google.com>
Reviewed-by: Yegor Jbanov <yjbanov@google.com>
Commit-Queue: Mike Reed <reed@google.com>
This commit is contained in:
Mike Reed 2021-03-25 13:13:23 -04:00
parent c98b2afc7b
commit 5514431d0e
9 changed files with 102 additions and 22 deletions

View File

@ -8,6 +8,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Added
- Skottie accessors for dynamic text properties (text string, font size).
- Optional sampling parameter to drawAtlas (paint filter-quality is ignored/deprecated)
## [0.25.0] - 2021-03-02

View File

@ -838,19 +838,32 @@ EMSCRIPTEN_BINDINGS(Skia) {
const SkRect* oval = reinterpret_cast<const SkRect*>(fPtr);
self.drawArc(*oval, startAngle, sweepAngle, useCenter, paint);
}))
// _drawAtlas takes an array of SkColor. There is no SkColor4f override.
// TODO: take sampling as an explicit parameter from the caller
.function("_drawAtlas", optional_override([](SkCanvas& self,
.function("_drawAtlasOptions", optional_override([](SkCanvas& self,
const sk_sp<SkImage>& atlas, uintptr_t /* SkRSXform* */ xptr,
uintptr_t /* SkRect* */ rptr, uintptr_t /* SkColor* */ cptr, int count,
SkBlendMode mode, const SkPaint* paint)->void {
SkBlendMode mode, SkFilterMode filter, SkMipmapMode mipmap,
const SkPaint* paint)->void {
const SkRSXform* dstXforms = reinterpret_cast<const SkRSXform*>(xptr);
const SkRect* srcRects = reinterpret_cast<const SkRect*>(rptr);
const SkColor* colors = nullptr;
if (cptr) {
colors = reinterpret_cast<const SkColor*>(cptr);
}
SkSamplingOptions sampling(SkFilterMode::kLinear);
SkSamplingOptions sampling(filter, mipmap);
self.drawAtlas(atlas.get(), dstXforms, srcRects, colors, count, mode, sampling,
nullptr, paint);
}), allow_raw_pointers())
.function("_drawAtlasCubic", optional_override([](SkCanvas& self,
const sk_sp<SkImage>& atlas, uintptr_t /* SkRSXform* */ xptr,
uintptr_t /* SkRect* */ rptr, uintptr_t /* SkColor* */ cptr, int count,
SkBlendMode mode, float B, float C, const SkPaint* paint)->void {
const SkRSXform* dstXforms = reinterpret_cast<const SkRSXform*>(xptr);
const SkRect* srcRects = reinterpret_cast<const SkRect*>(rptr);
const SkColor* colors = nullptr;
if (cptr) {
colors = reinterpret_cast<const SkColor*>(cptr);
}
SkSamplingOptions sampling({B, C});
self.drawAtlas(atlas.get(), dstXforms, srcRects, colors, count, mode, sampling,
nullptr, paint);
}), allow_raw_pointers())

View File

@ -261,7 +261,8 @@ var CanvasKit = {
_clipRect: function() {},
_concat: function() {},
_drawArc: function() {},
_drawAtlas: function() {},
_drawAtlasOptions: function() {},
_drawAtlasCubic: function() {},
_drawColor: function() {},
_drawDRRect: function() {},
_drawImageNine: function() {},

View File

@ -479,7 +479,8 @@ CanvasKit.onRuntimeInitialized = function() {
// a Flat Float32Array of float colors or a 2d Array of Float32Array(4) (deprecated)
// TODO(kjlubick) remove Builders - no longer needed now that Malloc is a thing.
CanvasKit.Canvas.prototype.drawAtlas = function(atlas, srcRects, dstXforms, paint,
/*optional*/ blendMode, colors) {
/* optional */ blendMode, /* optional */ colors,
/* optional */ sampling) {
if (!atlas || !paint || !srcRects || !dstXforms) {
Debug('Doing nothing since missing a required input');
return;
@ -523,7 +524,28 @@ CanvasKit.onRuntimeInitialized = function() {
}
}
this._drawAtlas(atlas, dstXformPtr, srcRectPtr, colorPtr, count, blendMode, paint);
// We require one of these:
// 1. sampling is null (we default to linear/none)
// 2. sampling.B and sampling.C --> CubicResampler
// 3. sampling.filter [and sampling.mipmap] --> FilterOptions
//
// Thus if all fields are available, we will choose cubic (since we search for B,C first)
if (sampling && ('B' in sampling) && ('C' in sampling)) {
this._drawAtlasCubic(atlas, dstXformPtr, srcRectPtr, colorPtr, count, blendMode,
sampling['B'], sampling['C'], paint);
} else {
let filter = CanvasKit.FilterMode.Linear;
let mipmap = CanvasKit.MipmapMode.None;
if (sampling) {
filter = sampling['filter']; // 'filter' is a required field
if ('mipmap' in sampling) { // 'mipmap' is optional
mipmap = sampling['mipmap'];
}
}
this._drawAtlasOptions(atlas, dstXformPtr, srcRectPtr, colorPtr, count, blendMode,
filter, mipmap, paint);
}
if (srcRectPtr && !srcRects.build) {
freeArraysThatAreNotMallocedByUsers(srcRectPtr, srcRects);

View File

@ -1065,7 +1065,8 @@
dsts.set(0, 0.5, 0, (2*i)%200, (5*Math.round(i/200)) % 200);
dsts.set(1, scale*Math.sin(i/20), scale*Math.cos(i/20), 200, 100);
canvas.drawAtlas(img, srcs, dsts, paint, CanvasKit.BlendMode.Plus, colors);
canvas.drawAtlas(img, srcs, dsts, paint, CanvasKit.BlendMode.Plus, colors,
{filter: CanvasKit.FilterMode.Nearest});
surface.requestAnimationFrame(drawFrame);
}
surface.requestAnimationFrame(drawFrame);

View File

@ -97,7 +97,11 @@ function canvasTests(CK: CanvasKit, canvas?: Canvas, paint?: Paint, path?: Path,
canvas.drawAtlas(img, [1, 2, 3, 4, 5, 6, 7, 8], [8, 7, 6, 5, 4, 3, 2, 1], paint,
CK.BlendMode.Darken,
[CK.ColorAsInt(100, 110, 120), CK.ColorAsInt(130, 140, 150)]);
canvas.drawCircle(20, 20, 20, paint);
canvas.drawAtlas(img, [1, 2, 3, 4, 5, 6, 7, 8], [8, 7, 6, 5, 4, 3, 2, 1], paint,
null, null, {B: 0, C: 0.5});
canvas.drawAtlas(img, [1, 2, 3, 4, 5, 6, 7, 8], [8, 7, 6, 5, 4, 3, 2, 1], paint,
null, null, {filter: CK.FilterMode.Linear, mipmap: CK.MipmapMode.Nearest});
canvas.drawCircle(20, 20, 20, paint);
canvas.drawColor(someColor);
canvas.drawColor(someColor, CK.BlendMode.ColorDodge);
canvas.drawColorComponents(0.2, 1.0, -0.02, 0.5);

View File

@ -1054,10 +1054,12 @@ export interface Canvas extends EmbindObject<Canvas> {
* @param paint
* @param blendMode - BlendMode combining colors and sprites
* @param colors - If provided, will be blended with sprite using blendMode.
* @param sampling - Specifies sampling options. If null, bilinear is used.
*/
drawAtlas(atlas: Image, srcRects: InputFlattenedRectangleArray,
dstXforms: InputFlattenedRSXFormArray, paint: Paint,
blendMode?: BlendMode, colors?: ColorIntArray): void;
blendMode?: BlendMode, colors?: ColorIntArray,
sampling?: CubicResampler | FilterOptions): void;
/**
* Draws a circle at (cx, cy) with the given radius.
@ -1765,6 +1767,22 @@ export interface PartialImageInfo {
width: number;
}
/*
* Specifies sampling with bicubic coefficients
*/
export interface CubicResampler {
B: number; // 0..1
C: number; // 0..1
}
/**
* Specifies sampling using filter and mipmap options
*/
export interface FilterOptions {
filter: FilterMode;
mipmap?: MipmapMode; // defaults to None if not specified
}
/**
* See SkMaskFilter.h for more on this class. The objects are opaque.
*/

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

View File

@ -296,31 +296,51 @@ describe('Core canvas behavior', () => {
paint.setColor(CanvasKit.Color(0, 0, 0, 0.8));
const srcs = [
0, 0, 256, 256,
256, 0, 512, 256,
0, 256, 256, 512,
256, 256, 512, 512,
0, 0, 8, 8,
8, 0, 16, 8,
0, 8, 8, 16,
8, 8, 16, 16,
];
const dsts = [
0.5, 0, 20, 20,
0.5, 0, 300, 20,
0.5, 0, 20, 300,
0.5, 0, 300, 300,
10, 0, 0, 0,
10, 0, 100, 0,
10, 0, 0, 100,
10, 0, 100, 100,
];
const colors = Uint32Array.of(
CanvasKit.ColorAsInt( 85, 170, 10, 128), // light green
CanvasKit.ColorAsInt( 51, 51, 191, 128), // light blue
CanvasKit.ColorAsInt( 0, 0, 0, 128),
CanvasKit.ColorAsInt(256, 256, 256, 128),
CanvasKit.ColorAsInt(255, 255, 255, 128),
);
canvas.drawAtlas(atlas, srcs, dsts, paint, CanvasKit.BlendMode.Modulate, colors);
// sampling for each of the 4 instances
const sampling = [
null,
{B: 0, C: 0.5},
{filter: CanvasKit.FilterMode.Nearest, mipmap: CanvasKit.MipmapMode.None},
{filter: CanvasKit.FilterMode.Linear, mipmap: CanvasKit.MipmapMode.Nearest},
];
// positioning for each of the 4 instances
const offset = [
[0, 0], [256, 0], [0, 256], [256, 256]
];
canvas.translate(20, 20);
for (let i = 0; i < 4; ++i) {
canvas.save();
canvas.translate(offset[i][0], offset[i][1]);
canvas.drawAtlas(atlas, srcs, dsts, paint, CanvasKit.BlendMode.SrcOver, colors,
sampling[i]);
canvas.restore();
}
atlas.delete();
paint.delete();
}, '/assets/mandrill_512.png');
}, '/assets/mandrill_16.png');
gm('image_decoding_methods', async (canvas) => {
canvas.clear(CanvasKit.WHITE);