diff --git a/packages/canvas-extract/src/CanvasExtract.ts b/packages/canvas-extract/src/CanvasExtract.ts index 36c4e6ad6f..05f47cf5af 100644 --- a/packages/canvas-extract/src/CanvasExtract.ts +++ b/packages/canvas-extract/src/CanvasExtract.ts @@ -62,14 +62,14 @@ export class CanvasExtract * Creates a Canvas element, renders this target to it and then returns it. * @param target - A displayObject or renderTexture * to convert. If left empty will use the main renderer + * @param frame - The frame the extraction is restricted to. * @returns A Canvas element with the texture rendered on. */ - public canvas(target?: DisplayObject | RenderTexture): HTMLCanvasElement + public canvas(target?: DisplayObject | RenderTexture, frame?: Rectangle): HTMLCanvasElement { const renderer = this.renderer; let context; let resolution; - let frame; let renderTexture; if (target) @@ -88,22 +88,28 @@ export class CanvasExtract { context = (renderTexture.baseTexture as BaseRenderTexture)._canvasRenderTarget.context; resolution = (renderTexture.baseTexture as BaseRenderTexture)._canvasRenderTarget.resolution; - frame = renderTexture.frame; + frame = frame ?? renderTexture.frame; } else { context = renderer.rootContext; resolution = renderer.resolution; - frame = TEMP_RECT; - frame.width = this.renderer.width; - frame.height = this.renderer.height; + + if (!frame) + { + frame = TEMP_RECT; + frame.width = renderer.width; + frame.height = renderer.height; + } } - const width = Math.floor((frame.width * resolution) + 1e-4); - const height = Math.floor((frame.height * resolution) + 1e-4); + const x = Math.round(frame.x * resolution); + const y = Math.round(frame.y * resolution); + const width = Math.round(frame.width * resolution); + const height = Math.round(frame.height * resolution); const canvasBuffer = new CanvasRenderTarget(width, height, 1); - const canvasData = context.getImageData(frame.x * resolution, frame.y * resolution, width, height); + const canvasData = context.getImageData(x, y, width, height); canvasBuffer.context.putImageData(canvasData, 0, 0); @@ -116,14 +122,14 @@ export class CanvasExtract * order, with integer values between 0 and 255 (included). * @param target - A displayObject or renderTexture * to convert. If left empty will use the main renderer + * @param frame - The frame the extraction is restricted to. * @returns One-dimensional array containing the pixel data of the entire texture */ - public pixels(target?: DisplayObject | RenderTexture): Uint8ClampedArray + public pixels(target?: DisplayObject | RenderTexture, frame?: Rectangle): Uint8ClampedArray { const renderer = this.renderer; let context; let resolution; - let frame; let renderTexture; if (target) @@ -142,21 +148,25 @@ export class CanvasExtract { context = (renderTexture.baseTexture as BaseRenderTexture)._canvasRenderTarget.context; resolution = (renderTexture.baseTexture as BaseRenderTexture)._canvasRenderTarget.resolution; - frame = renderTexture.frame; + frame = frame ?? renderTexture.frame; } else { context = renderer.rootContext; resolution = renderer.resolution; - frame = TEMP_RECT; - frame.width = renderer.width; - frame.height = renderer.height; + + if (!frame) + { + frame = TEMP_RECT; + frame.width = renderer.width; + frame.height = renderer.height; + } } - const x = frame.x * resolution; - const y = frame.y * resolution; - const width = frame.width * resolution; - const height = frame.height * resolution; + const x = Math.round(frame.x * resolution); + const y = Math.round(frame.y * resolution); + const width = Math.round(frame.width * resolution); + const height = Math.round(frame.height * resolution); return context.getImageData(x, y, width, height).data; } diff --git a/packages/extract/src/Extract.ts b/packages/extract/src/Extract.ts index 6c247d4a12..50797d092d 100644 --- a/packages/extract/src/Extract.ts +++ b/packages/extract/src/Extract.ts @@ -11,6 +11,7 @@ const BYTES_PER_PIXEL = 4; /** * this interface is used to extract only a single pixel of Render Texture or Display Object * if you use this Interface all fields is required + * @deprecated * @example * test: PixelExtractOptions = { x: 15, y: 20, resolution: 4, width: 10, height: 10 } */ @@ -91,13 +92,13 @@ export class Extract implements IRendererPlugin * Creates a Canvas element, renders this target to it and then returns it. * @param target - A displayObject or renderTexture * to convert. If left empty will use the main renderer + * @param frame - The frame the extraction is restricted to. * @returns - A Canvas element with the texture rendered on. */ - public canvas(target: DisplayObject | RenderTexture): HTMLCanvasElement + public canvas(target: DisplayObject | RenderTexture, frame?: Rectangle): HTMLCanvasElement { const renderer = this.renderer; let resolution; - let frame; let flipY = false; let renderTexture; let generated = false; @@ -118,25 +119,27 @@ export class Extract implements IRendererPlugin if (renderTexture) { resolution = renderTexture.baseTexture.resolution; - frame = renderTexture.frame; + frame = frame ?? renderTexture.frame; flipY = false; renderer.renderTexture.bind(renderTexture); } else { - resolution = this.renderer.resolution; - - flipY = true; + resolution = renderer.resolution; - frame = TEMP_RECT; - frame.width = this.renderer.width; - frame.height = this.renderer.height; + if (!frame) + { + frame = TEMP_RECT; + frame.width = renderer.width; + frame.height = renderer.height; + } + flipY = true; renderer.renderTexture.bind(null); } - const width = Math.floor((frame.width * resolution) + 1e-4); - const height = Math.floor((frame.height * resolution) + 1e-4); + const width = Math.round(frame.width * resolution); + const height = Math.round(frame.height * resolution); let canvasBuffer = new CanvasRenderTarget(width, height, 1); @@ -146,8 +149,8 @@ export class Extract implements IRendererPlugin const gl = renderer.gl; gl.readPixels( - frame.x * resolution, - frame.y * resolution, + Math.round(frame.x * resolution), + Math.round(frame.y * resolution), width, height, gl.RGBA, @@ -190,14 +193,13 @@ export class Extract implements IRendererPlugin * order, with integer values between 0 and 255 (included). * @param target - A displayObject or renderTexture * to convert. If left empty will use the main renderer - * @param options + * @param frame - The frame the extraction is restricted to. * @returns - One-dimensional array containing the pixel data of the entire texture */ - public pixels(target?: DisplayObject | RenderTexture, options?: PixelExtractOptions): Uint8Array + public pixels(target?: DisplayObject | RenderTexture, frame?: Rectangle | PixelExtractOptions): Uint8Array { const renderer = this.renderer; let resolution; - let frame; let renderTexture; let generated = false; @@ -207,7 +209,7 @@ export class Extract implements IRendererPlugin { renderTexture = target; } - else if (target instanceof DisplayObject) + else { renderTexture = this.renderer.generateTexture(target); generated = true; @@ -216,45 +218,26 @@ export class Extract implements IRendererPlugin if (renderTexture) { - if (options) - { - resolution = options.resolution; - frame = renderTexture.frame; - - // bind the buffer - renderer.renderTexture.bind(renderTexture); - } - else - { - resolution = renderTexture.baseTexture.resolution; - frame = renderTexture.frame; - - // bind the buffer - renderer.renderTexture.bind(renderTexture); - } - } - else if (options) - { - resolution = options.resolution; - - frame = TEMP_RECT; - frame.width = options.width; - frame.height = options.height; - renderer.renderTexture.bind(null); + resolution = renderTexture.baseTexture.resolution; + frame = frame ?? renderTexture.frame; + renderer.renderTexture.bind(renderTexture); } else { resolution = renderer.resolution; - frame = TEMP_RECT; - frame.width = renderer.width; - frame.height = renderer.height; + if (!frame) + { + frame = TEMP_RECT; + frame.width = renderer.width; + frame.height = renderer.height; + } renderer.renderTexture.bind(null); } - const width = frame.width * resolution; - const height = frame.height * resolution; + const width = Math.round(frame.width * resolution); + const height = Math.round(frame.height * resolution); const webglPixels = new Uint8Array(BYTES_PER_PIXEL * width * height); @@ -262,8 +245,8 @@ export class Extract implements IRendererPlugin const gl = renderer.gl; gl.readPixels( - frame.x * resolution, - frame.y * resolution, + Math.round(frame.x * resolution), + Math.round(frame.y * resolution), width, height, gl.RGBA, diff --git a/packages/extract/test/Extract.tests.ts b/packages/extract/test/Extract.tests.ts index 49a4035ff4..ed73bebb2f 100644 --- a/packages/extract/test/Extract.tests.ts +++ b/packages/extract/test/Extract.tests.ts @@ -2,7 +2,8 @@ import { Sprite } from '@pixi/sprite'; import { expect } from 'chai'; import { skipHello } from '@pixi/utils'; import { Texture, RenderTexture, BatchRenderer, Renderer } from '@pixi/core'; -import { Extract, PixelExtractOptions } from '@pixi/extract'; +import { Extract } from '@pixi/extract'; +import { Rectangle } from '@pixi/math'; skipHello(); @@ -57,13 +58,13 @@ describe('Extract', () => const extract = renderer.plugins.extract as Extract; const renderTexture = RenderTexture.create({ width: 10, height: 10 }); const sprite = new Sprite(Texture.WHITE); - const test: PixelExtractOptions = { x: 1, y: 2, resolution: 5, width: 10, height: 10 }; + const frame = new Rectangle(1, 2, 5, 6); renderer.render(sprite, { renderTexture }); expect(extract.canvas(renderTexture)).to.be.an.instanceof(HTMLCanvasElement); expect(extract.base64(renderTexture)).to.be.a('string'); - expect(extract.pixels(renderTexture, test)).to.be.instanceOf(Uint8Array); + expect(extract.pixels(renderTexture, frame)).to.be.instanceOf(Uint8Array); expect(extract.image(renderTexture)).to.be.instanceOf(HTMLImageElement); renderer.destroy();