Skip to content

Commit

Permalink
Fix Extract's and CanvasExtract's pixels and canvas frame parameter (p…
Browse files Browse the repository at this point in the history
  • Loading branch information
dev7355608 committed Jun 13, 2022
1 parent fb6c197 commit 9aeaeb7
Show file tree
Hide file tree
Showing 3 changed files with 65 additions and 71 deletions.
48 changes: 29 additions & 19 deletions packages/canvas-extract/src/CanvasExtract.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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);

Expand All @@ -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)
Expand All @@ -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;
}
Expand Down
81 changes: 32 additions & 49 deletions packages/extract/src/Extract.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 }
*/
Expand Down Expand Up @@ -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;
Expand All @@ -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);

Expand All @@ -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,
Expand Down Expand Up @@ -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;

Expand All @@ -207,7 +209,7 @@ export class Extract implements IRendererPlugin
{
renderTexture = target;
}
else if (target instanceof DisplayObject)
else
{
renderTexture = this.renderer.generateTexture(target);
generated = true;
Expand All @@ -216,54 +218,35 @@ 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);

// read pixels to the array
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,
Expand Down
7 changes: 4 additions & 3 deletions packages/extract/test/Extract.tests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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();

Expand Down Expand Up @@ -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();
Expand Down

0 comments on commit 9aeaeb7

Please sign in to comment.