diff --git a/src/core/text/Text.js b/src/core/text/Text.js index 1c3c7b3..9813324 100644 --- a/src/core/text/Text.js +++ b/src/core/text/Text.js @@ -6,6 +6,7 @@ import { TEXT_GRADIENT } from '../const'; import settings from '../settings'; import TextStyle from './TextStyle'; +import trimCanvas from '../utils/trimCanvas'; const defaultDestroyOptions = { texture: true, @@ -326,6 +327,15 @@ */ updateTexture() { + if (this._style.trim) + { + const trimmed = trimCanvas(this.canvas); + + this.canvas.width = trimmed.width; + this.canvas.height = trimmed.height; + this.context.putImageData(trimmed.data, 0, 0); + } + const texture = this._texture; const style = this._style; diff --git a/src/core/text/Text.js b/src/core/text/Text.js index 1c3c7b3..9813324 100644 --- a/src/core/text/Text.js +++ b/src/core/text/Text.js @@ -6,6 +6,7 @@ import { TEXT_GRADIENT } from '../const'; import settings from '../settings'; import TextStyle from './TextStyle'; +import trimCanvas from '../utils/trimCanvas'; const defaultDestroyOptions = { texture: true, @@ -326,6 +327,15 @@ */ updateTexture() { + if (this._style.trim) + { + const trimmed = trimCanvas(this.canvas); + + this.canvas.width = trimmed.width; + this.canvas.height = trimmed.height; + this.context.putImageData(trimmed.data, 0, 0); + } + const texture = this._texture; const style = this._style; diff --git a/src/core/text/TextStyle.js b/src/core/text/TextStyle.js index 58e77e0..eec2820 100644 --- a/src/core/text/TextStyle.js +++ b/src/core/text/TextStyle.js @@ -28,6 +28,7 @@ stroke: 'black', strokeThickness: 0, textBaseline: 'alphabetic', + trim: false, wordWrap: false, wordWrapWidth: 100, }; @@ -79,6 +80,7 @@ * e.g 'blue', '#FCFF00' * @param {number} [style.strokeThickness=0] - A number that represents the thickness of the stroke. * Default is 0 (no stroke) + * @param {boolean} [style.trim=false] - Trim transparent borders * @param {string} [style.textBaseline='alphabetic'] - The baseline of the text that is rendered. * @param {boolean} [style.wordWrap=false] - Indicates if word wrap should be used * @param {number} [style.wordWrapWidth=100] - The width at which text will wrap, it needs wordWrap to be set to true @@ -418,6 +420,19 @@ } } + get trim() + { + return this._trim; + } + set trim(trim) + { + if (this._trim !== trim) + { + this._trim = trim; + this.styleID++; + } + } + get wordWrap() { return this._wordWrap; diff --git a/src/core/text/Text.js b/src/core/text/Text.js index 1c3c7b3..9813324 100644 --- a/src/core/text/Text.js +++ b/src/core/text/Text.js @@ -6,6 +6,7 @@ import { TEXT_GRADIENT } from '../const'; import settings from '../settings'; import TextStyle from './TextStyle'; +import trimCanvas from '../utils/trimCanvas'; const defaultDestroyOptions = { texture: true, @@ -326,6 +327,15 @@ */ updateTexture() { + if (this._style.trim) + { + const trimmed = trimCanvas(this.canvas); + + this.canvas.width = trimmed.width; + this.canvas.height = trimmed.height; + this.context.putImageData(trimmed.data, 0, 0); + } + const texture = this._texture; const style = this._style; diff --git a/src/core/text/TextStyle.js b/src/core/text/TextStyle.js index 58e77e0..eec2820 100644 --- a/src/core/text/TextStyle.js +++ b/src/core/text/TextStyle.js @@ -28,6 +28,7 @@ stroke: 'black', strokeThickness: 0, textBaseline: 'alphabetic', + trim: false, wordWrap: false, wordWrapWidth: 100, }; @@ -79,6 +80,7 @@ * e.g 'blue', '#FCFF00' * @param {number} [style.strokeThickness=0] - A number that represents the thickness of the stroke. * Default is 0 (no stroke) + * @param {boolean} [style.trim=false] - Trim transparent borders * @param {string} [style.textBaseline='alphabetic'] - The baseline of the text that is rendered. * @param {boolean} [style.wordWrap=false] - Indicates if word wrap should be used * @param {number} [style.wordWrapWidth=100] - The width at which text will wrap, it needs wordWrap to be set to true @@ -418,6 +420,19 @@ } } + get trim() + { + return this._trim; + } + set trim(trim) + { + if (this._trim !== trim) + { + this._trim = trim; + this.styleID++; + } + } + get wordWrap() { return this._wordWrap; diff --git a/src/core/utils/trimCanvas.js b/src/core/utils/trimCanvas.js new file mode 100644 index 0000000..37a0378 --- /dev/null +++ b/src/core/utils/trimCanvas.js @@ -0,0 +1,76 @@ +/** + * Trim transparent borders from a canvas + * + * @memberof PIXI + * @function trimCanvas + * @private + * @param {HTMLCanvasElement} canvas - the canvas to trim + * @returns {object} Trim data + */ +export default function trimCanvas(canvas) +{ + // https://gist.github.com/remy/784508 + const context = canvas.getContext('2d'); + const pixels = context.getImageData(0, 0, canvas.width, canvas.height); + const l = pixels.data.length; + const bound = { + top: null, + left: null, + right: null, + bottom: null, + }; + let i; + let x; + let y; + + for (i = 0; i < l; i += 4) + { + if (pixels.data[i + 3] !== 0) + { + x = (i / 4) % canvas.width; + y = ~~((i / 4) / canvas.width); + + if (bound.top === null) + { + bound.top = y; + } + + if (bound.left === null) + { + bound.left = x; + } + else if (x < bound.left) + { + bound.left = x; + } + + if (bound.right === null) + { + bound.right = x + 1; + } + else if (bound.right < x) + { + bound.right = x + 1; + } + + if (bound.bottom === null) + { + bound.bottom = y; + } + else if (bound.bottom < y) + { + bound.bottom = y; + } + } + } + + const height = bound.bottom - bound.top + 1; + const width = bound.right - bound.left; + const data = context.getImageData(bound.left, bound.top, width, height); + + return { + height, + width, + data, + }; +}