mirror of
https://github.com/espruino/Espruino.git
synced 2025-12-08 19:06:15 +00:00
Added Graphics.setFontCustom for custom fonts
This commit is contained in:
parent
099ad7d4f8
commit
b5182fc841
@ -1,5 +1,6 @@
|
||||
1v58 : Fix Serial.parity
|
||||
Fix glitches in jshGetSystemTime
|
||||
Added Graphics.setFontCustom for custom fonts
|
||||
|
||||
1v57 : Tweak IRQ priorities to try and make SPI RX more reliable
|
||||
Make http default to port 80 if no port is specified in options
|
||||
|
||||
@ -123,7 +123,7 @@ void graphicsSetVar(JsGraphics *gfx) {
|
||||
|
||||
void graphicsSetPixel(JsGraphics *gfx, short x, short y, unsigned int col) {
|
||||
if (x<0 || y<0 || x>=gfx->data.width || y>=gfx->data.height) return;
|
||||
gfx->setPixel(gfx,x,y,col & (unsigned int)((1<<gfx->data.bpp)-1));
|
||||
gfx->setPixel(gfx,x,y,col & (unsigned int)((1L<<gfx->data.bpp)-1));
|
||||
}
|
||||
|
||||
unsigned int graphicsGetPixel(JsGraphics *gfx, short x, short y) {
|
||||
|
||||
@ -32,8 +32,14 @@ typedef enum {
|
||||
} JsGraphicsFlags;
|
||||
|
||||
#define JSGRAPHICS_FONTSIZE_4X6 (-1) // a bitmap font
|
||||
#define JSGRAPHICS_FONTSIZE_CUSTOM (-2) // a custom bitmap font made from fields in the graphics object (See below)
|
||||
// Positive font sizes are Vector fonts
|
||||
|
||||
#define JSGRAPHICS_CUSTOMFONT_BMP JS_HIDDEN_CHAR_STR"fntBmp"
|
||||
#define JSGRAPHICS_CUSTOMFONT_WIDTH JS_HIDDEN_CHAR_STR"fntW"
|
||||
#define JSGRAPHICS_CUSTOMFONT_HEIGHT JS_HIDDEN_CHAR_STR"fntH"
|
||||
#define JSGRAPHICS_CUSTOMFONT_FIRSTCHAR JS_HIDDEN_CHAR_STR"fnt1st"
|
||||
|
||||
typedef struct {
|
||||
JsGraphicsType type;
|
||||
JsGraphicsFlags flags;
|
||||
|
||||
@ -336,9 +336,49 @@ void jswrap_graphics_setFontSizeX(JsVar *parent, int size, bool checkValid) {
|
||||
if (size<1) size=1;
|
||||
if (size>1023) size=1023;
|
||||
}
|
||||
if (gfx.data.fontSize == JSGRAPHICS_FONTSIZE_CUSTOM) {
|
||||
jsvObjectSetChild(parent, JSGRAPHICS_CUSTOMFONT_BMP, 0);
|
||||
jsvObjectSetChild(parent, JSGRAPHICS_CUSTOMFONT_WIDTH, 0);
|
||||
jsvObjectSetChild(parent, JSGRAPHICS_CUSTOMFONT_HEIGHT, 0);
|
||||
jsvObjectSetChild(parent, JSGRAPHICS_CUSTOMFONT_FIRSTCHAR, 0);
|
||||
}
|
||||
gfx.data.fontSize = (short)size;
|
||||
graphicsSetVar(&gfx);
|
||||
}
|
||||
/*JSON{ "type":"method", "class": "Graphics", "name" : "setFontCustom",
|
||||
"description" : "Set Graphics to draw with a Custom Font",
|
||||
"generate" : "jswrap_graphics_setFontCustom",
|
||||
"params" : [ [ "bitmap", "JsVar", "A column-first, MSB-first, 1bpp bitmap containing the font bitmap" ],
|
||||
[ "firstChar", "int32", "The first character in the font - usually 32 (space)" ],
|
||||
[ "width", "JsVar", "The width of each character in the font. Either an integer, or a string where each character represents the width" ],
|
||||
[ "height", "int32", "The height as an integer" ] ]
|
||||
}*/
|
||||
void jswrap_graphics_setFontCustom(JsVar *parent, JsVar *bitmap, int firstChar, JsVar *width, int height) {
|
||||
JsGraphics gfx; if (!graphicsGetFromVar(&gfx, parent)) return;
|
||||
|
||||
if (!jsvIsString(bitmap)) {
|
||||
jsError("Font bitmap must be a String");
|
||||
return;
|
||||
}
|
||||
if (firstChar<0 || firstChar>255) {
|
||||
jsError("First character out of range");
|
||||
return;
|
||||
}
|
||||
if (!jsvIsString(width) && !jsvIsInt(width)) {
|
||||
jsError("Font width must be a String or an integer");
|
||||
return;
|
||||
}
|
||||
if (height<=0 || height>255) {
|
||||
jsError("Invalid height");
|
||||
return;
|
||||
}
|
||||
jsvObjectSetChild(parent, JSGRAPHICS_CUSTOMFONT_BMP, bitmap);
|
||||
jsvObjectSetChild(parent, JSGRAPHICS_CUSTOMFONT_WIDTH, width);
|
||||
jsvObjectSetChild(parent, JSGRAPHICS_CUSTOMFONT_HEIGHT, jsvNewFromInteger(height));
|
||||
jsvObjectSetChild(parent, JSGRAPHICS_CUSTOMFONT_FIRSTCHAR, jsvNewFromInteger(firstChar));
|
||||
gfx.data.fontSize = JSGRAPHICS_FONTSIZE_CUSTOM;
|
||||
graphicsSetVar(&gfx);
|
||||
}
|
||||
|
||||
|
||||
/*JSON{ "type":"method", "class": "Graphics", "name" : "drawString",
|
||||
@ -350,6 +390,16 @@ void jswrap_graphics_setFontSizeX(JsVar *parent, int size, bool checkValid) {
|
||||
}*/
|
||||
void jswrap_graphics_drawString(JsVar *parent, JsVar *var, int x, int y) {
|
||||
JsGraphics gfx; if (!graphicsGetFromVar(&gfx, parent)) return;
|
||||
|
||||
JsVar *customBitmap = 0, *customWidth = 0;
|
||||
int customHeight, customFirstChar;
|
||||
if (gfx.data.fontSize == JSGRAPHICS_FONTSIZE_CUSTOM) {
|
||||
customBitmap = jsvObjectGetChild(parent, JSGRAPHICS_CUSTOMFONT_BMP, 0);
|
||||
customWidth = jsvObjectGetChild(parent, JSGRAPHICS_CUSTOMFONT_WIDTH, 0);
|
||||
customHeight = (int)jsvGetIntegerAndUnLock(jsvObjectGetChild(parent, JSGRAPHICS_CUSTOMFONT_HEIGHT, 0));
|
||||
customFirstChar = (int)jsvGetIntegerAndUnLock(jsvObjectGetChild(parent, JSGRAPHICS_CUSTOMFONT_FIRSTCHAR, 0));
|
||||
}
|
||||
|
||||
JsVar *str = jsvAsString(var, false);
|
||||
JsvStringIterator it;
|
||||
jsvStringIteratorNew(&it, str, 0);
|
||||
@ -361,12 +411,54 @@ void jswrap_graphics_drawString(JsVar *parent, JsVar *var, int x, int y) {
|
||||
} else if (gfx.data.fontSize == JSGRAPHICS_FONTSIZE_4X6) {
|
||||
graphicsDrawChar4x6(&gfx, (short)x, (short)y, ch);
|
||||
x+=4;
|
||||
} else if (gfx.data.fontSize == JSGRAPHICS_FONTSIZE_CUSTOM) {
|
||||
// get char width and offset in string
|
||||
int width = 0, bmpOffset = 0;
|
||||
if (jsvIsString(customWidth)) {
|
||||
if (ch>=customFirstChar) {
|
||||
JsvStringIterator wit;
|
||||
jsvStringIteratorNew(&wit, customWidth, 0);
|
||||
while (jsvStringIteratorHasChar(&wit) && (int)jsvStringIteratorGetIndex(&wit)<(ch-customFirstChar)) {
|
||||
bmpOffset += (unsigned char)jsvStringIteratorGetChar(&wit);
|
||||
jsvStringIteratorNext(&wit);
|
||||
}
|
||||
width = (unsigned char)jsvStringIteratorGetChar(&wit);
|
||||
jsvStringIteratorFree(&wit);
|
||||
}
|
||||
} else {
|
||||
width = (int)jsvGetInteger(customWidth);
|
||||
bmpOffset = width*(ch-customFirstChar);
|
||||
}
|
||||
if (ch>=customFirstChar) {
|
||||
bmpOffset *= customHeight;
|
||||
// now render character
|
||||
JsvStringIterator cit;
|
||||
jsvStringIteratorNew(&cit, customBitmap, (size_t)bmpOffset>>3);
|
||||
bmpOffset &= 7;
|
||||
int cx,cy;
|
||||
for (cx=0;cx<width;cx++) {
|
||||
for (cy=0;cy<customHeight;cy++) {
|
||||
if ((jsvStringIteratorGetChar(&cit)<<bmpOffset)&128)
|
||||
graphicsSetPixel(&gfx, (short)(cx+x), (short)(cy+y), gfx.data.fgColor);
|
||||
bmpOffset++;
|
||||
if (bmpOffset==8) {
|
||||
bmpOffset=0;
|
||||
jsvStringIteratorNext(&cit);
|
||||
}
|
||||
}
|
||||
}
|
||||
jsvStringIteratorFree(&cit);
|
||||
}
|
||||
x += width;
|
||||
}
|
||||
if (jspIsInterrupted()) break;
|
||||
jsvStringIteratorNext(&it);
|
||||
}
|
||||
jsvStringIteratorFree(&it);
|
||||
jsvUnLock(str);
|
||||
|
||||
jsvUnLock(customBitmap);
|
||||
jsvUnLock(customWidth);
|
||||
}
|
||||
|
||||
/*JSON{ "type":"method", "class": "Graphics", "name" : "stringWidth",
|
||||
@ -377,6 +469,14 @@ void jswrap_graphics_drawString(JsVar *parent, JsVar *var, int x, int y) {
|
||||
}*/
|
||||
JsVarInt jswrap_graphics_stringWidth(JsVar *parent, JsVar *var) {
|
||||
JsGraphics gfx; if (!graphicsGetFromVar(&gfx, parent)) return 0;
|
||||
|
||||
JsVar *customWidth = 0;
|
||||
int customFirstChar;
|
||||
if (gfx.data.fontSize == JSGRAPHICS_FONTSIZE_CUSTOM) {
|
||||
customWidth = jsvObjectGetChild(parent, JSGRAPHICS_CUSTOMFONT_WIDTH, 0);
|
||||
customFirstChar = (int)jsvGetIntegerAndUnLock(jsvObjectGetChild(parent, JSGRAPHICS_CUSTOMFONT_FIRSTCHAR, 0));
|
||||
}
|
||||
|
||||
JsVar *str = jsvAsString(var, false);
|
||||
JsvStringIterator it;
|
||||
jsvStringIteratorNew(&it, str, 0);
|
||||
@ -387,11 +487,19 @@ JsVarInt jswrap_graphics_stringWidth(JsVar *parent, JsVar *var) {
|
||||
width += (int)graphicsVectorCharWidth(&gfx, gfx.data.fontSize, ch);
|
||||
} else if (gfx.data.fontSize == JSGRAPHICS_FONTSIZE_4X6) {
|
||||
width += 4;
|
||||
} else if (gfx.data.fontSize == JSGRAPHICS_FONTSIZE_CUSTOM) {
|
||||
if (jsvIsString(customWidth)) {
|
||||
if (ch>=customFirstChar)
|
||||
width += (unsigned char)jsvGetCharInString(customWidth, (size_t)(ch-customFirstChar));
|
||||
} else
|
||||
width += (int)jsvGetInteger(customWidth);
|
||||
}
|
||||
jsvStringIteratorNext(&it);
|
||||
}
|
||||
jsvStringIteratorFree(&it);
|
||||
jsvUnLock(str);
|
||||
|
||||
jsvUnLock(customWidth);
|
||||
return width;
|
||||
}
|
||||
|
||||
|
||||
@ -36,6 +36,7 @@ int jswrap_graphics_getPixel(JsVar *parent, int x, int y);
|
||||
void jswrap_graphics_setPixel(JsVar *parent, int x, int y, JsVar *color);
|
||||
void jswrap_graphics_setColorX(JsVar *parent, JsVar *r, JsVar *g, JsVar *b, bool isForeground);
|
||||
void jswrap_graphics_setFontSizeX(JsVar *parent, int size, bool checkValid);
|
||||
void jswrap_graphics_setFontCustom(JsVar *parent, JsVar *bitmap, int firstChar, JsVar *width, int height);
|
||||
void jswrap_graphics_drawString(JsVar *parent, JsVar *str, int x, int y);
|
||||
JsVarInt jswrap_graphics_stringWidth(JsVar *parent, JsVar *var);
|
||||
void jswrap_graphics_drawLine(JsVar *parent, int x1, int y1, int x2, int y2);
|
||||
|
||||
62
scripts/create_bitmap_font.js
Normal file
62
scripts/create_bitmap_font.js
Normal file
@ -0,0 +1,62 @@
|
||||
/*
|
||||
This file is part of Espruino, a JavaScript interpreter for Microcontrollers
|
||||
|
||||
Copyright (C) 2013 Gordon Williams <gw@pur3.co.uk>
|
||||
|
||||
This Source Code Form is subject to the terms of the Mozilla Public
|
||||
License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
----------------------------------------------------------------------------------------
|
||||
Bitmap font header file creator
|
||||
----------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
// convert charset.png -depth 8 gray:charset.raw
|
||||
pixels = require("fs").readFileSync("charset.raw");
|
||||
var W=128;
|
||||
var H=18;
|
||||
var CW = 4;
|
||||
var CWX = 3; // 1 of spaces
|
||||
var CH = 6;
|
||||
var packedChars = 5;
|
||||
|
||||
function genChar(xo,yo) {
|
||||
var r = [];
|
||||
for (var y=0;y<CH;y++) {
|
||||
var idx = xo+((y+yo)*W);
|
||||
var s = "";
|
||||
for (var x=0;x<CWX;x++) {
|
||||
s+= (pixels[idx++]>128) ? "_" : "X";
|
||||
}
|
||||
r.push(s);
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
var x=CW,y=0;
|
||||
|
||||
while (y < H) {
|
||||
var chars = [];
|
||||
for (var i=0;i<packedChars;i++) {
|
||||
chars.push(genChar(x,y));
|
||||
x += CW;
|
||||
if (x>=W) {
|
||||
x = 0;
|
||||
y += CH;
|
||||
}
|
||||
}
|
||||
for (var cy=0;cy<CH;cy++) {
|
||||
var s = " PACK_5_TO_16( ";
|
||||
for (i=0;i<packedChars;i++) {
|
||||
if (i>0) s+=" , ";
|
||||
s += chars[i][cy];
|
||||
}
|
||||
s += " ),";
|
||||
console.log(s);
|
||||
}
|
||||
console.log("");
|
||||
}
|
||||
|
||||
|
||||
99
scripts/create_custom_font.js
Normal file
99
scripts/create_custom_font.js
Normal file
@ -0,0 +1,99 @@
|
||||
/*
|
||||
This file is part of Espruino, a JavaScript interpreter for Microcontrollers
|
||||
|
||||
Copyright (C) 2013 Gordon Williams <gw@pur3.co.uk>
|
||||
|
||||
This Source Code Form is subject to the terms of the Mozilla Public
|
||||
License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
----------------------------------------------------------------------------------------
|
||||
Bitmap font creator for Graphics custom fonts
|
||||
|
||||
This is pretty rough-and-ready, and in order to easily get bitmap data out of an image
|
||||
it requires the image to already be in RAW format.
|
||||
|
||||
For this, use ImageMagick as follows: `convert charset_8x12.png -depth 8 gray:charset_8x12.raw`
|
||||
----------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
// npm install btoa
|
||||
pixels = require("fs").readFileSync("charset_8x12.raw");
|
||||
// image width and height
|
||||
var W = 128;
|
||||
var H = 72;
|
||||
// character width and height
|
||||
var CW = 8;
|
||||
var CH = 12;
|
||||
/*
|
||||
pixels = require("fs").readFileSync("charset_6x8.raw");
|
||||
var W = 192;
|
||||
var H = 24;
|
||||
var CW = 6;
|
||||
var CH = 8;*/
|
||||
|
||||
|
||||
var bits = [];
|
||||
var charWidths = [];
|
||||
|
||||
function genChar(xo,yo) {
|
||||
// work out widths
|
||||
var xStart = CW;
|
||||
var xEnd = 0;
|
||||
for (var x=0;x<CW;x++) {
|
||||
var set = false;
|
||||
for (var y=0;y<CH;y++) {
|
||||
var idx = x+xo+((y+yo)*W);
|
||||
set |= pixels[idx]<=128;
|
||||
}
|
||||
if (set) {
|
||||
if (x<xStart) xStart = x;
|
||||
xEnd = x;
|
||||
}
|
||||
}
|
||||
if (xStart>xEnd) {
|
||||
xStart=0;
|
||||
xEnd = CW/2; // treat space as half-width
|
||||
} else if (xEnd<CW-1)
|
||||
xEnd++; // if not full width, add a space after
|
||||
charWidths.push(xEnd+1-xStart);
|
||||
|
||||
for (var x=xStart;x<=xEnd;x++) {
|
||||
for (var y=0;y<CH;y++) {
|
||||
var idx = x+xo+((y+yo)*W);
|
||||
bits.push((pixels[idx]>128) ? 0 : 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// get an array of bits
|
||||
var x=0,y=0;
|
||||
while (y < H) {
|
||||
genChar(x,y);
|
||||
x += CW;
|
||||
if (x>=W) {
|
||||
x = 0;
|
||||
y += CH;
|
||||
}
|
||||
}
|
||||
|
||||
// compact array
|
||||
var bytes = "";
|
||||
for (var i=0;i<bits.length;i+=8) {
|
||||
var byte = 0;
|
||||
for (var b=0;b<8;b++)
|
||||
if (bits[i+b]===1) byte += 1<<(7-b);
|
||||
bytes += String.fromCharCode(byte);
|
||||
}
|
||||
// convert width array - widthBytes
|
||||
var widthBytes = "";
|
||||
for (i in charWidths)
|
||||
widthBytes += String.fromCharCode(charWidths[i]);
|
||||
// widthBytes = charWidths.map(String.fromCharCode).join(""); doesn't work here - too many 0 chars
|
||||
|
||||
console.log("var font = atob(\""+require('btoa')(bytes)+"\");");
|
||||
console.log("var widths = atob(\""+require('btoa')(widthBytes)+"\");");
|
||||
console.log("g.setFontCustom(font, 32, widths, "+CH+");");
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user