// LCDFont: Class for using tiny fonts with subpixel antialising // // Copyright 2005 Roar Lauritzsen <roarl@pvv.org> // // This class is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 2 of the License, or // (at your option) any later version. // // This class is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // The following link provides a copy of the GNU General Public License: // http://www.gnu.org/licenses/gpl.txt // If you are unable to obtain the copy from this address, write to // the Free Software Foundation, Inc., 59 Temple Place, Suite 330, // Boston, MA 02111-1307 USA package terminal; import java.io.IOException; import javax.microedition.lcdui.Graphics; import javax.microedition.lcdui.Image; public class LCDFont { //#ifdef midp2 public final int fontWidth; // Width of one character public final int fontHeight; // Height of one character private final int imageWidth, imageHeight; private int[] bwBuf; // Black-white version of font private int[] colorBuf; // Colored version of font private int[] currentBuf; private long currentColor; private long[] cacheColor; // Color of each cached character private int FR, FG, FB, BR, BG, BB; // Create subpixel-antialiased font based on image resource name. // If BGR is set to true, subpixel order is reversed (normal is RGB) public LCDFont(String fontImageName, boolean BGR) { Image fontImage; try { fontImage = Image.createImage(fontImageName); } catch (IOException e) { throw new RuntimeException("Cannot load LCDFont: " + e); } imageWidth = fontImage.getWidth(); imageHeight = fontImage.getHeight(); fontWidth = imageWidth / 32; fontHeight = imageHeight / 3; bwBuf = new int[imageWidth * (imageHeight + 1)]; colorBuf = new int[imageWidth * (imageHeight + 1)]; /* Karl: add 1 to the imageHeight because some device seek beyond the bottom of the array when * drawing. */ fontImage.getRGB(bwBuf, 0, imageWidth, 0, 0, imageWidth, imageHeight); if (BGR) { // For screens with BGR subpixel ordering, or for ROT_180 for (int i = 0; i < bwBuf.length; i++) { int c = bwBuf[i]; bwBuf[i] = ((c >> 16) & 0xff) + (c & 0xff00) + ((c & 0xff) << 16); } } cacheColor = new long[96]; currentBuf = bwBuf; currentColor = 0; } // Set the foreground and background color of font // For readability, input font colors will be modified public void setColor(int fg, int bg) { if (fg == 0xffffff && bg == 0) { currentBuf = bwBuf; } else if (((long) fg << 32) + bg != currentColor) { currentColor = ((long) fg << 32) + bg; currentBuf = colorBuf; // Because of the subpixel antialising, we cannot use the color // directly. Instead, we have to select a more "pastel" color, // and differentiate properly between background and foreground FR = (fg >> 16) & 0xff; FG = (fg >> 8) & 0xff; FB = fg & 0xff; BR = (bg >> 16) & 0xff; BG = (bg >> 8) & 0xff; BB = bg & 0xff; if (28 * FR + 55 * FG + 17 * FB >= 28 * BR + 55 * BG + 17 * BB) { // bright on dark FR = (6 * FR + 10 * 0xff) / 16; // Brighten foreground FG = (6 * FG + 10 * 0xff) / 16; FB = (6 * FB + 10 * 0xff) / 16; BR = (10 * BR) / 16; // Darken background BG = (10 * BG) / 16; BB = (10 * BB) / 16; } else { // dark on bright FR = (10 * FR) / 16; // Darken foreground FG = (10 * FG) / 16; FB = (10 * FB) / 16; BR = (6 * BR + 10 * 0xff) / 16; // Brighten background BG = (6 * BG + 10 * 0xff) / 16; BB = (6 * BB + 10 * 0xff) / 16; } // Scale to range 0-256 for later ">>8" instead of "/255" FR += FR >> 7; FG += FG >> 7; FB += FB >> 7; BR += BR >> 7; BG += BG >> 7; BB += BB >> 7; } } // Colored characters are cached in colorBuf and rendered as needed private void renderColorChar(int offset) { for (int y = 0; y < fontHeight; y++) for (int x = 0; x < fontWidth; x++) { int col = bwBuf[offset + y * imageWidth + x]; int R = (col >> 16) & 0xff; int G = (col >> 8) & 0xff; int B = col & 0xff; R = (FR * R + BR * (255 - R)) >> 8; G = (FG * G + BG * (255 - G)) >> 8; B = (FB * B + BB * (255 - B)) >> 8; colorBuf[offset + y * imageWidth + x] = (R << 16) + (G << 8) + B; } } // Draw one char public void drawChar(Graphics g, char c, int x, int y) { if (c <= ' ' || c > '~') return; c -= ' '; int offset = (c >> 5) * fontHeight * imageWidth + (c & 31) * fontWidth; if (currentBuf == colorBuf && cacheColor[c] != currentColor) { renderColorChar(offset); cacheColor[c] = currentColor; } g.drawRGB(currentBuf, offset, imageWidth, x, y, fontWidth, fontHeight, false); } //#endif }