[canvaskit] Add option for readPixels to use pre-malloc'd data
Bug: skia:10565 Change-Id: I777f887794cd0524ced4d65e86bd285a854386e5 Reviewed-on: https://skia-review.googlesource.com/c/skia/+/331858 Reviewed-by: Nathaniel Nifong <nifong@google.com>
This commit is contained in:
parent
9fe83916e0
commit
c4ab08710d
@ -11,7 +11,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
`CanvasKit.Shader`.
|
||||
- `MakeRasterDirectSurface` for giving the user direct access to drawn pixels.
|
||||
- `getLineMetrics` to Paragraph.
|
||||
- `Canvas.saveLayerPaint` as an experimental, undocumented "fast path" if one only needs to pass the paint.
|
||||
- `Canvas.saveLayerPaint` as an experimental, undocumented "fast path" if one only needs to pass
|
||||
the paint.
|
||||
|
||||
### Breaking
|
||||
- `CanvasKit.MakePathFromSVGString` was renamed to `CanvasKit.Path.MakeFromSVGString`
|
||||
@ -23,6 +24,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
- `CanvasKit.Shader.Blend`, `...Color`, and `...Lerp` have been renamed to
|
||||
`CanvasKit.Shader.MakeBlend`, `...MakeColor` and `...MakeLerp` to align with naming conventions.
|
||||
The old names will be removed in an upcoming release.
|
||||
- `readPixels` now takes a malloc'd object as the last parameter. If provided, the data will be
|
||||
copied into there instead of allocating a new buffer.
|
||||
|
||||
### Removed
|
||||
- `CanvasKit.MakePathFromCmds`; Was deprecated in favor of `CanvasKit.Path.MakeFromCmds`.
|
||||
|
@ -141,6 +141,9 @@ function canvasTests(CK: CanvasKit, canvas?: Canvas, paint?: Paint, path?: Path,
|
||||
const pixels = canvas.readPixels(0, 1, 2, 3); // $ExpectType Uint8Array
|
||||
const pixelsTwo = canvas.readPixels(4, 5, 6, 7, CK.AlphaType.Opaque, CK.ColorType.RGBA_1010102,
|
||||
CK.ColorSpace.DISPLAY_P3, 16);
|
||||
const m = CK.Malloc(Uint8Array, 20);
|
||||
canvas.readPixels(4, 5, 6, 7, CK.AlphaType.Opaque, CK.ColorType.RGBA_1010102,
|
||||
CK.ColorSpace.DISPLAY_P3, 16, m);
|
||||
canvas.restore();
|
||||
canvas.restoreToCount(2);
|
||||
canvas.rotate(1, 2, 3);
|
||||
@ -239,6 +242,14 @@ function imageTests(CK: CanvasKit, imgElement?: HTMLImageElement) {
|
||||
alphaType: CK.AlphaType.Unpremul,
|
||||
colorSpace: CK.ColorSpace.SRGB,
|
||||
}, 85, 1000);
|
||||
const m = CK.Malloc(Uint8Array, 10);
|
||||
img.readPixels({
|
||||
width: 79,
|
||||
height: 205,
|
||||
colorType: CK.ColorType.RGBA_8888,
|
||||
alphaType: CK.AlphaType.Unpremul,
|
||||
colorSpace: CK.ColorSpace.SRGB,
|
||||
}, 85, 1000, m);
|
||||
img.delete();
|
||||
}
|
||||
|
||||
|
13
modules/canvaskit/canvaskit/types/index.d.ts
vendored
13
modules/canvaskit/canvaskit/types/index.d.ts
vendored
@ -1241,10 +1241,13 @@ export interface Canvas extends EmbindObject<Canvas> {
|
||||
* @param alphaType - defaults to Unpremul
|
||||
* @param colorType - defaults to RGBA_8888
|
||||
* @param colorSpace - defaults to SRGB
|
||||
* @param dest - If provided, the pixels will be copied into the allocated buffer allowing access to the
|
||||
* pixels without allocating a new TypedArray.
|
||||
* @param dstRowBytes
|
||||
*/
|
||||
readPixels(x: number, y: number, w: number, h: number, alphaType?: AlphaType,
|
||||
colorType?: ColorType, colorSpace?: ColorSpace, dstRowBytes?: number): Uint8Array;
|
||||
colorType?: ColorType, colorSpace?: ColorSpace, dstRowBytes?: number,
|
||||
dest?: MallocObj): Uint8Array;
|
||||
|
||||
/**
|
||||
* Removes changes to the current matrix and clip since Canvas state was
|
||||
@ -1566,9 +1569,13 @@ export interface Image extends EmbindObject<Image> {
|
||||
* @param imageInfo - describes the destination format of the pixels.
|
||||
* @param srcX
|
||||
* @param srcY
|
||||
* @returns a Uint8Array if RGB_8888 was requested, Float32Array if RGBA_F32 was requested.
|
||||
* @param dest - If provided, the pixels will be copied into the allocated buffer allowing access to the
|
||||
* pixels without allocating a new TypedArray.
|
||||
* @returns a Uint8Array if RGB_8888 was requested, Float32Array if RGBA_F32 was requested. null will be returned
|
||||
* on any error.
|
||||
*
|
||||
*/
|
||||
readPixels(imageInfo: ImageInfo, srcX: number, srcY: number): Uint8Array | Float32Array | null;
|
||||
readPixels(imageInfo: ImageInfo, srcX: number, srcY: number, dest?: MallocObj): Uint8Array | Float32Array | null;
|
||||
|
||||
/**
|
||||
* Return the width in pixels of the image.
|
||||
|
@ -920,7 +920,7 @@ CanvasKit.onRuntimeInitialized = function() {
|
||||
return this._makeShader(xTileMode, yTileMode, localMatrixPtr);
|
||||
};
|
||||
|
||||
CanvasKit.Image.prototype.readPixels = function(imageInfo, srcX, srcY) {
|
||||
CanvasKit.Image.prototype.readPixels = function(imageInfo, srcX, srcY, destMallocObj) {
|
||||
var rowBytes;
|
||||
// Important to use ['string'] notation here, otherwise the closure compiler will
|
||||
// minify away the colorType.
|
||||
@ -936,13 +936,26 @@ CanvasKit.onRuntimeInitialized = function() {
|
||||
return;
|
||||
}
|
||||
var pBytes = rowBytes * imageInfo.height;
|
||||
var pPtr = CanvasKit._malloc(pBytes);
|
||||
var pPtr;
|
||||
if (destMallocObj) {
|
||||
pPtr = destMallocObj['byteOffset'];
|
||||
} else {
|
||||
pPtr = CanvasKit._malloc(pBytes);
|
||||
}
|
||||
|
||||
if (!this._readPixels(imageInfo, pPtr, rowBytes, srcX, srcY)) {
|
||||
Debug('Could not read pixels with the given inputs');
|
||||
if (!destMallocObj) {
|
||||
CanvasKit._free(pPtr);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// If the user provided us a buffer to copy into, we don't need to allocate a new TypedArray.
|
||||
if (destMallocObj) {
|
||||
return destMallocObj['toTypedArray'](); // Return the typed array wrapper w/o allocating.
|
||||
}
|
||||
|
||||
// Put those pixels into a typed array of the right format and then
|
||||
// make a copy with slice() that we can return.
|
||||
var retVal = null;
|
||||
@ -1163,9 +1176,10 @@ CanvasKit.onRuntimeInitialized = function() {
|
||||
return rv;
|
||||
};
|
||||
|
||||
// returns Uint8Array
|
||||
// TODO(kjlubick) align this API with Image.readPixels
|
||||
CanvasKit.Canvas.prototype.readPixels = function(x, y, w, h, alphaType,
|
||||
colorType, colorSpace, dstRowBytes) {
|
||||
colorType, colorSpace, dstRowBytes,
|
||||
destMallocObj) {
|
||||
// supply defaults (which are compatible with HTMLCanvas's getImageData)
|
||||
alphaType = alphaType || CanvasKit.AlphaType.Unpremul;
|
||||
colorType = colorType || CanvasKit.ColorType.RGBA_8888;
|
||||
@ -1176,24 +1190,37 @@ CanvasKit.onRuntimeInitialized = function() {
|
||||
}
|
||||
dstRowBytes = dstRowBytes || (pixBytes * w);
|
||||
|
||||
var len = h * dstRowBytes
|
||||
var pptr = CanvasKit._malloc(len);
|
||||
var len = h * dstRowBytes;
|
||||
var pPtr;
|
||||
if (destMallocObj) {
|
||||
pPtr = destMallocObj['byteOffset'];
|
||||
} else {
|
||||
pPtr = CanvasKit._malloc(len);
|
||||
}
|
||||
|
||||
var ok = this._readPixels({
|
||||
'width': w,
|
||||
'height': h,
|
||||
'colorType': colorType,
|
||||
'alphaType': alphaType,
|
||||
'colorSpace': colorSpace,
|
||||
}, pptr, dstRowBytes, x, y);
|
||||
}, pPtr, dstRowBytes, x, y);
|
||||
if (!ok) {
|
||||
CanvasKit._free(pptr);
|
||||
if (!destMallocObj) {
|
||||
CanvasKit._free(pPtr);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// If the user provided us a buffer to copy into, we don't need to allocate a new TypedArray.
|
||||
if (destMallocObj) {
|
||||
return destMallocObj['toTypedArray'](); // Return the typed array wrapper w/o allocating.
|
||||
}
|
||||
|
||||
// The first typed array is just a view into memory. Because we will
|
||||
// be free-ing that, we call slice to make a persistent copy.
|
||||
var pixels = new Uint8Array(CanvasKit.HEAPU8.buffer, pptr, len).slice();
|
||||
CanvasKit._free(pptr);
|
||||
var pixels = new Uint8Array(CanvasKit.HEAPU8.buffer, pPtr, len).slice();
|
||||
CanvasKit._free(pPtr);
|
||||
return pixels;
|
||||
};
|
||||
|
||||
|
@ -152,7 +152,15 @@ describe('Core canvas behavior', () => {
|
||||
// requires 4 bytes (R, G, B, A).
|
||||
expect(pixels.length).toEqual(512 * 512 * 4);
|
||||
|
||||
// Make enough space for a 5x5 8888 surface (4 bytes for R, G, B, A)
|
||||
const rdsData = CanvasKit.Malloc(Uint8Array, 512 * 5*512 * 4);
|
||||
const pixels2 = rdsData.toTypedArray();
|
||||
pixels2[0] = 127; // sentinel value, should be overwritten by readPixels.
|
||||
img.readPixels(imageInfo, 0, 0, rdsData);
|
||||
expect(rdsData.toTypedArray()[0]).toEqual(pixels[0]);
|
||||
|
||||
img.delete();
|
||||
CanvasKit.Free(rdsData);
|
||||
done();
|
||||
})();
|
||||
});
|
||||
@ -888,9 +896,17 @@ describe('Core canvas behavior', () => {
|
||||
expect(CanvasKit.ColorSpace.Equals(info.colorSpace, colorSpace))
|
||||
.toBeTruthy("Surface not created with correct color space.");
|
||||
|
||||
const pixels = surface.getCanvas().readPixels(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT,
|
||||
CanvasKit.AlphaType.Unpremul, CanvasKit.ColorType.RGBA_8888, colorSpace);
|
||||
const mObj = CanvasKit.Malloc(Uint8Array, CANVAS_WIDTH * CANVAS_HEIGHT * 4);
|
||||
mObj.toTypedArray()[0] = 127; // sentinel value. Should be overwritten by readPixels.
|
||||
const canvas = surface.getCanvas();
|
||||
canvas.clear(CanvasKit.TRANSPARENT);
|
||||
const pixels = canvas.readPixels(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT,
|
||||
CanvasKit.AlphaType.Unpremul, CanvasKit.ColorType.RGBA_8888, colorSpace, null, mObj);
|
||||
expect(pixels).toBeTruthy('Could not read pixels from surface');
|
||||
expect(pixels[0] !== 127).toBeTruthy();
|
||||
expect(pixels[0]).toEqual(mObj.toTypedArray()[0]);
|
||||
CanvasKit.Free(mObj);
|
||||
surface.delete();
|
||||
});
|
||||
it('Can create a Display P3 surface', () => {
|
||||
const colorSpace = CanvasKit.ColorSpace.DISPLAY_P3;
|
||||
|
Loading…
Reference in New Issue
Block a user