diff --git a/dist/index.js b/dist/index.js index d795876..bb00ba3 100644 --- a/dist/index.js +++ b/dist/index.js @@ -13,32 +13,37 @@ const initFont = ({ height=DEFAULT_CHAR_HEIGHT, ...chars }={}, ctx) => { return } - const bin2arr = (bin, width) => bin.match(new RegExp(`.{${width}}`, 'g')); - const isNumber = code => code > 0; - - return (string, x=0, y=0, size=24, color=DEFAULT_COLOR) => { - const renderChar = (charX, char) => { - const pixelSize = size/height; - const fontCode = chars[char.charCodeAt()] || ''; - const binaryChar = isNumber(fontCode) ? fontCode : fontCode.codePointAt(); - - const binary = (binaryChar || 0).toString(2); - - const width = Math.ceil(binary.length / height); - const marginX = charX + pixelSize; - const formattedBinary = binary.padStart(width * height, 0); - const binaryCols = bin2arr(formattedBinary, height); - - console.debug('Rendering char', char, char.charCodeAt(), fontCode, binaryChar, binaryCols); - - binaryCols.map((column, colPos) => - [...column].map((pixel, pixPos) => { - ctx.fillStyle = !+pixel ? 'transparent' : color; // pixel == 0 ? - ctx.fillRect(x + marginX + colPos * pixelSize, y + pixPos * pixelSize, pixelSize, pixelSize); - }) - ); - - return charX + (width+1)*pixelSize + return ( string, x = 0, y = 0, size = 24, color = DEFAULT_COLOR ) => { + const pixelSize = size / height; + const renderChar = ( charX, char ) => { + const fontCode = chars[ char.charCodeAt() ] || ''; + let bin = Number.isInteger( fontCode ) ? fontCode : fontCode.codePointAt(); + const binary = ( bin || 0 ).toString( 2 ); + const width = Math.ceil( binary.length / height ); + const mask = ( 1 << height ) - 1; + + ctx.fillStyle = color; + for ( let col = width; col > 0; col-- ) { + let rowPos = height - 1; + for ( let row = bin & mask; row > 0; row >>= 1 ) { + if ( row & 1 ) { + let y1 = y + rowPos * pixelSize, h = pixelSize; + + while ( ( row >> 1 ) & 1 ) { + y1 -= pixelSize; + h += pixelSize; + row >>= 1; + rowPos--; + } + + ctx.fillRect( x + charX + col * pixelSize, y1, pixelSize, h ); + } + rowPos--; + } + bin >>= height; + } + + return charX + ( width + 1 ) * pixelSize; }; console.debug('Rendering string', string); diff --git a/dist/tinyfont-font-pixel.min.js b/dist/tinyfont-font-pixel.min.js index 61416b0..6083773 100644 --- a/dist/tinyfont-font-pixel.min.js +++ b/dist/tinyfont-font-pixel.min.js @@ -1 +1 @@ -"use strict";const t=5,e="#000",r=({height:t=5,...e}={},r)=>{if(e&&r)return(n,o=0,a=0,c=24,i="#000")=>{[...n].reduce((n,s)=>{const l=c/t,p=e[s.charCodeAt()]||"",h=(((t=>t>0)(p)?p:p.codePointAt())||0).toString(2),g=Math.ceil(h.length/t),d=n+l;return((t,e)=>t.match(new RegExp(`.{${e}}`,"g")))(h.padStart(g*t,0),t).map((t,e)=>[...t].map((t,n)=>{r.fillStyle=+t?i:"transparent",r.fillRect(o+d+e*l,a+n*l,l,l)})),n+(g+1)*l},0)}};exports.initFont=r;const n=[...Array(33),29,,,,,,12,,,,"ᇄ",3,"ႄ",1,1118480,"縿",31,"庽","嚿","炟","皷","纷","䈟","线","皿",17,,,"⥊",,"䊼",,"㹏","纮","縱","縮","纵","纐","񴚦","粟","䟱","丿",1020241,"簡",33059359,1024159,"縿","纜","񼙯","繍","皷","䏰","簿",25363672,32541759,18157905,"惸",18470705,,,,,"С"];exports.font=n; \ No newline at end of file +"use strict";const t=5,e="#000",r=({height:t=5,...e}={},r)=>{if(e&&r)return(o,n=0,i=0,l=24,c="#000")=>{const s=l/t;[...o].reduce((o,l)=>{const f=e[l.charCodeAt()]||"";let h=Number.isInteger(f)?f:f.codePointAt();const u=(h||0).toString(2),g=Math.ceil(u.length/t),a=(1<0;e--){let l=t-1;for(let t=h&a;t>0;t>>=1){if(1&t){let c=i+l*s,f=s;for(;t>>1&1;)c-=s,f+=s,t>>=1,l--;r.fillRect(n+o+e*s,c,s,f)}l--}h>>=t}return o+(g+1)*s},0)}};exports.initFont=r;const o=[...Array(33),29,,,,,,12,,,,"ᇄ",3,"ႄ",1,1118480,"縿",31,"庽","嚿","炟","皷","纷","䈟","线","皿",17,,,"⥊",,"䊼",,"㹏","纮","縱","縮","纵","纐","񴚦","粟","䟱","丿",1020241,"簡",33059359,1024159,"縿","纜","񼙯","繍","皷","䏰","簿",25363672,32541759,18157905,"惸",18470705,,,,,"С"];exports.font=o; \ No newline at end of file diff --git a/dist/tinyfont-font-tiny.min.js b/dist/tinyfont-font-tiny.min.js index 19a069e..bfec4dc 100644 --- a/dist/tinyfont-font-tiny.min.js +++ b/dist/tinyfont-font-tiny.min.js @@ -1 +1 @@ -"use strict";const t=5,e="#000",r=({height:t=5,...e}={},r)=>{if(e&&r)return(n,i=0,o=0,a=24,c="#000")=>{[...n].reduce((n,h)=>{const s=a/t,l=e[h.charCodeAt()]||"",p=(((t=>t>0)(l)?l:l.codePointAt())||0).toString(2),g=Math.ceil(p.length/t),u=n+s;return((t,e)=>t.match(new RegExp(`.{${e}}`,"g")))(p.padStart(g*t,0),t).map((t,e)=>[...t].map((t,n)=>{r.fillStyle=+t?c:"transparent",r.fillRect(i+u+e*s,o+n*s,s,s)})),n+(g+1)*s},0)}};exports.initFont=r;const n=[...Array(33),13,,,,,,12,,,,"ɲ",3,"Ȣ",1,"Ĥ","ྟ","","஝","য়","ฯ","ඛ","ྒྷ","ࢼ","࿟","ඟ",9,,,"Օ",,"࢜",,"͗","བྷ","u","ݟ","ݖ","ݤ","ݓ","ܧ",11,27,"༥",15,476995,"݇","ݗ","ݦ","畱","t","Ŵ","ô","ܗ","ؖ",398870,"ԥ","ا","ѱ",,,,,273];n.height=4,exports.font=n; \ No newline at end of file +"use strict";const t=5,e="#000",r=({height:t=5,...e}={},r)=>{if(e&&r)return(o,n=0,i=0,l=24,c="#000")=>{const s=l/t;[...o].reduce((o,l)=>{const f=e[l.charCodeAt()]||"";let h=Number.isInteger(f)?f:f.codePointAt();const u=(h||0).toString(2),g=Math.ceil(u.length/t),a=(1<0;e--){let l=t-1;for(let t=h&a;t>0;t>>=1){if(1&t){let c=i+l*s,f=s;for(;t>>1&1;)c-=s,f+=s,t>>=1,l--;r.fillRect(n+o+e*s,c,s,f)}l--}h>>=t}return o+(g+1)*s},0)}};exports.initFont=r;const o=[...Array(33),13,,,,,,12,,,,"ɲ",3,"Ȣ",1,"Ĥ","ྟ","","஝","য়","ฯ","ඛ","ྒྷ","ࢼ","࿟","ඟ",9,,,"Օ",,"࢜",,"͗","བྷ","u","ݟ","ݖ","ݤ","ݓ","ܧ",11,27,"༥",15,476995,"݇","ݗ","ݦ","畱","t","Ŵ","ô","ܗ","ؖ",398870,"ԥ","ا","ѱ",,,,,273];o.height=4,exports.font=o; \ No newline at end of file diff --git a/src/index.js b/src/index.js index 00ef1b2..e59bb60 100644 --- a/src/index.js +++ b/src/index.js @@ -11,32 +11,39 @@ export const initFont = ({ height=DEFAULT_CHAR_HEIGHT, ...chars }={}, ctx) => { return } - const bin2arr = (bin, width) => bin.match(new RegExp(`.{${width}}`, 'g')); - const isNumber = code => code > 0; - - return (string, x=0, y=0, size=24, color=DEFAULT_COLOR) => { - const renderChar = (charX, char) => { - const pixelSize = size/height; - const fontCode = chars[char.charCodeAt()] || ''; - const binaryChar = isNumber(fontCode) ? fontCode : fontCode.codePointAt(); - - const binary = (binaryChar || 0).toString(2); - - const width = Math.ceil(binary.length / height); - const marginX = charX + pixelSize; - const formattedBinary = binary.padStart(width * height, 0); - const binaryCols = bin2arr(formattedBinary, height); - - console.debug('Rendering char', char, char.charCodeAt(), fontCode, binaryChar, binaryCols); - - binaryCols.map((column, colPos) => - [...column].map((pixel, pixPos) => { - ctx.fillStyle = !+pixel ? 'transparent' : color; // pixel == 0 ? - ctx.fillRect(x + marginX + colPos * pixelSize, y + pixPos * pixelSize, pixelSize, pixelSize); - }) - ); - - return charX + (width+1)*pixelSize + return ( string, x = 0, y = 0, size = 24, color = DEFAULT_COLOR ) => { + const pixelSize = size / height; + const renderChar = ( charX, char ) => { + const fontCode = chars[ char.charCodeAt() ] || ''; + let bin = Number.isInteger( fontCode ) ? fontCode : fontCode.codePointAt(); + const binary = ( bin || 0 ).toString( 2 ); + const width = Math.ceil( binary.length / height ); + const mask = ( 1 << height ) - 1; + + ctx.fillStyle = color; + for ( let col = width; col > 0; col-- ) { + let rowPos = height - 1; + for ( let row = bin & mask; row > 0; row >>= 1 ) { + if ( row & 1 ) { + let y1 = y + rowPos * pixelSize, h = pixelSize; + + // This while loop greatly reduces the amount of draw calls. + // If you need a few more bytes, you could remove this. + while ( ( row >> 1 ) & 1 ) { + y1 -= pixelSize; + h += pixelSize; + row >>= 1; + rowPos--; + } + + ctx.fillRect( x + charX + col * pixelSize, y1, pixelSize, h ); + } + rowPos--; + } + bin >>= height; + } + + return charX + ( width + 1 ) * pixelSize; }; console.debug('Rendering string', string);