diff --git a/android/core/src/processing/core/PFont.java b/android/core/src/processing/core/PFont.java index 34a4972b2..0b883b507 100644 --- a/android/core/src/processing/core/PFont.java +++ b/android/core/src/processing/core/PFont.java @@ -3,13 +3,12 @@ /* Part of the Processing project - http://processing.org - Copyright (c) 2004-07 Ben Fry & Casey Reas + Copyright (c) 2004-10 Ben Fry & Casey Reas Copyright (c) 2001-04 Massachusetts Institute of Technology This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. + modify it under the terms of version 2.01 of the GNU Lesser General + Public License as published by the Free Software Foundation. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -24,26 +23,16 @@ package processing.core; -//import java.awt.*; -//import java.awt.image.BufferedImage; -//import java.awt.image.Raster; +import java.awt.*; +import java.awt.image.*; import java.io.*; -//import java.lang.reflect.*; import java.util.Arrays; -import java.util.HashMap; - -import android.graphics.Bitmap; -import android.graphics.Canvas; -import android.graphics.Color; -import android.graphics.Paint; -import android.graphics.Typeface; -import android.graphics.Bitmap.Config; /** * Grayscale bitmap font class used by Processing. *
- * Awful (and by that, I mean awesome) ascii (non)art for how this works: + * Awful (and by that, I mean awesome) ASCII (non-)art for how this works: *
* |
* | height is the full used height of the image
@@ -64,80 +53,201 @@ import android.graphics.Bitmap.Config;
*/
public class PFont implements PConstants {
- public int charCount;
- public PImage images[];
+ /** Number of character glyphs in this font. */
+ protected int glyphCount;
+
+ /**
+ * Actual glyph data. The length of this array won't necessarily be the
+ * same size as glyphCount, in cases where lazy font loading is in use.
+ */
+ protected Glyph[] glyphs;
+
+ /**
+ * Name of the font as seen by Java when it was created.
+ * If the font is available, the native version will be used.
+ */
+ protected String name;
+
+ /**
+ * Postscript name of the font that this bitmap was created from.
+ */
+ protected String psname;
+
+ /**
+ * The original size of the font when it was first created
+ */
+ protected int size;
+
+ /** true if smoothing was enabled for this font, used for native impl */
+ protected boolean smooth;
+
+ /**
+ * The ascent of the font. If the 'd' character is present in this PFont,
+ * this value is replaced with its pixel height, because the values returned
+ * by FontMetrics.getAscent() seem to be terrible.
+ */
+ protected int ascent;
+
+ /**
+ * The descent of the font. If the 'p' character is present in this PFont,
+ * this value is replaced with its lowest pixel height, because the values
+ * returned by FontMetrics.getDescent() are gross.
+ */
+ protected int descent;
+
+ /**
+ * A more efficient array lookup for straight ASCII characters. For Unicode
+ * characters, a QuickSort-style search is used.
+ */
+ protected int[] ascii;
+
+ /**
+ * True if this font is set to load dynamically. This is the default when
+ * createFont() method is called without a character set. Bitmap versions of
+ * characters are only created when prompted by an index() call.
+ */
+ protected boolean lazy;
/**
* Native Java version of the font. If possible, this allows the
* PGraphics subclass to just use Java's font rendering stuff
* in situations where that's faster.
*/
- protected Typeface font;
- //protected Font font;
+ protected Font font;
+
+ /**
+ * True if we've already tried to find the native AWT version of this font.
+ */
protected boolean fontSearched;
/**
- * Name of the font as seen by Java when it was created.
- * If the font is available, the native version will be used.
+ * Array of the native system fonts. Used to lookup native fonts by their
+ * PostScript name. This is a workaround for a several year old Apple Java
+ * bug that they can't be bothered to fix.
*/
- public String name;
+ static protected Font[] fonts;
- /**
- * Postscript name of the font that this bitmap was created from.
- */
- public String psname;
- /** "natural" size of the font (most often 48) */
- public int size;
-
- /** true if smoothing was enabled for this font, used for native impl */
- public boolean smooth;
-
- /** next power of 2 over the max image size (usually 64) */
- public int mbox2;
-
- /** floating point width (convenience) */
- protected float fwidth;
-
- /** floating point width (convenience) */
- protected float fheight;
-
- /** texture width, same as mbox2, but reserved for future use */
- public int twidth;
-
- /** texture height, same as mbox2, but reserved for future use */
- public int theight;
-
- public int value[]; // char code
- public int height[]; // height of the bitmap data
- public int width[]; // width of bitmap data
- public int setWidth[]; // width displaced by the char
- public int topExtent[]; // offset for the top
- public int leftExtent[]; // offset for the left
-
- public int ascent;
- public int descent;
-
- protected int ascii[]; // quick lookup for the ascii chars
-
- // shared by the text() functions to avoid incessant allocation of memory
- //protected char textBuffer[] = new char[8 * 1024];
- //protected char widthBuffer[] = new char[8 * 1024];
-
- static protected Typeface[] fonts;
+ // objects to handle creation of font characters only as they're needed
+ BufferedImage lazyImage;
+ Graphics2D lazyGraphics;
+ FontMetrics lazyMetrics;
+ int[] lazySamples;
public PFont() { } // for subclasses
+ /**
+ * Create a new Processing font from a native font, but don't create all the
+ * characters at once, instead wait until they're used to include them.
+ * @param font
+ * @param smooth
+ */
+ public PFont(Font font, boolean smooth) {
+ this(font, smooth, null);
+ }
+
+
+ /**
+ * Create a new image-based font on the fly. If charset is set to null,
+ * the characters will only be created as bitmaps when they're drawn.
+ *
+ * @param font the font object to create from
+ * @param charset array of all unicode chars that should be included
+ * @param smooth true to enable smoothing/anti-aliasing
+ */
+ public PFont(Font font, boolean smooth, char charset[]) {
+ // save this so that we can use the native version
+ this.font = font;
+ this.smooth = smooth;
+
+ name = font.getName();
+ psname = font.getPSName();
+ size = font.getSize();
+
+ // no, i'm not interested in getting off the couch
+ lazy = true;
+ // not sure what else to do here
+ //mbox2 = 0;
+
+ int initialCount = 10;
+ glyphs = new Glyph[initialCount];
+
+ ascii = new int[128];
+ Arrays.fill(ascii, -1);
+
+ int mbox3 = size * 3;
+
+ lazyImage = new BufferedImage(mbox3, mbox3, BufferedImage.TYPE_INT_RGB);
+ lazyGraphics = (Graphics2D) lazyImage.getGraphics();
+ lazyGraphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
+ smooth ?
+ RenderingHints.VALUE_ANTIALIAS_ON :
+ RenderingHints.VALUE_ANTIALIAS_OFF);
+ // adding this for post-1.0.9
+ lazyGraphics.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
+ smooth ?
+ RenderingHints.VALUE_TEXT_ANTIALIAS_ON :
+ RenderingHints.VALUE_TEXT_ANTIALIAS_OFF);
+
+ lazyGraphics.setFont(font);
+ lazyMetrics = lazyGraphics.getFontMetrics();
+ lazySamples = new int[mbox3 * mbox3];
+
+ ascent = lazyMetrics.getAscent();
+ descent = lazyMetrics.getDescent();
+
+ if (charset != null) {
+ // charset needs to be sorted to make index lookup run more quickly
+ // http://dev.processing.org/bugs/show_bug.cgi?id=494
+ Arrays.sort(charset);
+
+ glyphs = new Glyph[charset.length];
+
+ glyphCount = 0;
+ for (char c : charset) {
+ if (font.canDisplay(c)) {
+ glyphs[glyphCount++] = new Glyph(c);
+ }
+ }
+
+ // shorten the array if necessary
+ if (glyphCount != charset.length) {
+ glyphs = (Glyph[]) PApplet.subset(glyphs, 0, glyphCount);
+ }
+
+ // foreign font, so just make ascent the max topExtent
+ // for > 1.0.9, not doing this anymore.
+ // instead using getAscent() and getDescent() values for these cases.
+// if ((ascent == 0) && (descent == 0)) {
+// //for (int i = 0; i < charCount; i++) {
+// for (Glyph glyph : glyphs) {
+// char cc = (char) glyph.value;
+// //char cc = (char) glyphs[i].value;
+// if (Character.isWhitespace(cc) ||
+// (cc == '\u00A0') || (cc == '\u2007') || (cc == '\u202F')) {
+// continue;
+// }
+// if (glyph.topExtent > ascent) {
+// ascent = glyph.topExtent;
+// }
+// int d = -glyph.topExtent + glyph.height;
+// if (d > descent) {
+// descent = d;
+// }
+// }
+// }
+ }
+ }
+
+
public PFont(InputStream input) throws IOException {
DataInputStream is = new DataInputStream(input);
// number of character images stored in this font
- charCount = is.readInt();
+ glyphCount = is.readInt();
- // bit count is ignored since this is always 8
- //int numBits = is.readInt();
// used to be the bitCount, but now used for version number.
// version 8 is any font before 69, so 9 is anything from 83+
// 9 was buggy so gonna increment to 10.
@@ -146,62 +256,28 @@ public class PFont implements PConstants {
// this was formerly ignored, now it's the actual font size
//mbox = is.readInt();
size = is.readInt();
+
// this was formerly mboxY, the one that was used
// this will make new fonts downward compatible
- //mbox2 = is.readInt();
- mbox2 = is.readInt();
-
- fwidth = size; //mbox;
- fheight = size; //mbox;
-
- // size for image ("texture") is next power of 2
- // over the font size. for most vlw fonts, the size is 48
- // so the next power of 2 is 64.
- // double-check to make sure that mbox2 is a power of 2
- // there was a bug in the old font generator that broke this
- //mbox2 = (int) Math.pow(2, Math.ceil(Math.log(mbox2) / Math.log(2)));
- mbox2 = (int) Math.pow(2, Math.ceil(Math.log(mbox2) / Math.log(2)));
- // size for the texture is stored in the font
- twidth = theight = mbox2; //mbox2;
+ is.readInt(); // ignore the other mbox attribute
ascent = is.readInt(); // formerly baseHt (zero/ignored)
descent = is.readInt(); // formerly ignored struct padding
// allocate enough space for the character info
- value = new int[charCount];
- height = new int[charCount];
- width = new int[charCount];
- setWidth = new int[charCount];
- topExtent = new int[charCount];
- leftExtent = new int[charCount];
+ glyphs = new Glyph[glyphCount];
ascii = new int[128];
- for (int i = 0; i < 128; i++) ascii[i] = -1;
+ Arrays.fill(ascii, -1);
// read the information about the individual characters
- for (int i = 0; i < charCount; i++) {
- value[i] = is.readInt();
- height[i] = is.readInt();
- width[i] = is.readInt();
- setWidth[i] = is.readInt();
- topExtent[i] = is.readInt();
- leftExtent[i] = is.readInt();
-
- // pointer in the c version, ignored
- is.readInt();
-
+ for (int i = 0; i < glyphCount; i++) {
+ Glyph glyph = new Glyph(is);
// cache locations of the ascii charset
- if (value[i] < 128) ascii[value[i]] = i;
-
- // the values for getAscent() and getDescent() from FontMetrics
- // seem to be way too large.. perhaps they're the max?
- // as such, use a more traditional marker for ascent/descent
- if (value[i] == 'd') {
- if (ascent == 0) ascent = topExtent[i];
- }
- if (value[i] == 'p') {
- if (descent == 0) descent = -topExtent[i] + height[i];
+ if (glyph.value < 128) {
+ ascii[glyph.value] = i;
}
+ glyphs[i] = glyph;
}
// not a roman font, so throw an error and ask to re-build.
@@ -211,30 +287,8 @@ public class PFont implements PConstants {
"re-create this font.");
}
- images = new PImage[charCount];
- for (int i = 0; i < charCount; i++) {
-// images[i] = new PImage(twidth, theight, ALPHA);
- images[i] = new PImage(twidth, theight, ARGB);
- int bitmapSize = height[i] * width[i];
-
- byte temp[] = new byte[bitmapSize];
- is.readFully(temp);
-
- // convert the bitmap to an alpha channel
- int w = width[i];
- int h = height[i];
- for (int y = 0; y < h; y++) {
- for (int x = 0; x < w; x++) {
- int valu = temp[y*w + x] & 0xff;
- //images[i].pixels[y * twidth + x] = valu;
- images[i].pixels[y * twidth + x] = (valu << 24) | 0xFFFFFF;
-// images[i].pixels[y * twidth + x] = (valu << 24);
-
- //System.out.print((images[i].pixels[y*64+x] > 128) ? "*" : ".");
- }
- //System.out.println();
- }
- //System.out.println();
+ for (Glyph glyph : glyphs) {
+ glyph.readBitmap(is);
}
if (version >= 10) { // includes the font name at the end of the file
@@ -247,10 +301,104 @@ public class PFont implements PConstants {
}
+ /**
+ * Write this PFont to an OutputStream.
+ *
+ * This is used by the Create Font tool, or whatever anyone else dreams
+ * up for messing with fonts themselves.
+ *
+ * It is assumed that the calling class will handle closing
+ * the stream when finished.
+ */
+ public void save(OutputStream output) throws IOException {
+ DataOutputStream os = new DataOutputStream(output);
+
+ os.writeInt(glyphCount);
+
+ if ((name == null) || (psname == null)) {
+ name = "";
+ psname = "";
+ }
+
+ os.writeInt(11); // formerly numBits, now used for version number
+ os.writeInt(size); // formerly mboxX (was 64, now 48)
+ os.writeInt(0); // formerly mboxY, now ignored
+ os.writeInt(ascent); // formerly baseHt (was ignored)
+ os.writeInt(descent); // formerly struct padding for c version
+
+ for (int i = 0; i < glyphCount; i++) {
+ glyphs[i].writeHeader(os);
+ }
+
+ for (int i = 0; i < glyphCount; i++) {
+ glyphs[i].writeBitmap(os);
+ }
+
+ // version 11
+ os.writeUTF(name);
+ os.writeUTF(psname);
+ os.writeBoolean(smooth);
+
+ os.flush();
+ }
+
+
+ /**
+ * Create a new glyph, and add the character to the current font.
+ * @param c character to create an image for.
+ */
+ protected void addGlyph(char c) {
+ Glyph glyph = new Glyph(c);
+
+ if (glyphCount == glyphs.length) {
+ glyphs = (Glyph[]) PApplet.expand(glyphs);
+ }
+ if (glyphCount == 0) {
+ glyphs[glyphCount] = glyph;
+ if (glyph.value < 128) {
+ ascii[glyph.value] = 0;
+ }
+
+ } else if (glyphs[glyphCount-1].value < glyph.value) {
+ glyphs[glyphCount] = glyph;
+ if (glyph.value < 128) {
+ ascii[glyph.value] = glyphCount;
+ }
+
+ } else {
+ for (int i = 0; i < glyphCount; i++) {
+ if (glyphs[i].value > c) {
+ for (int j = glyphCount; j > i; --j) {
+ glyphs[j] = glyphs[j-1];
+ if (glyphs[j].value < 128) {
+ ascii[glyphs[j].value] = j;
+ }
+ }
+ glyphs[i] = glyph;
+ // cache locations of the ascii charset
+ if (c < 128) ascii[c] = i;
+ break;
+ }
+ }
+ }
+ glyphCount++;
+ }
+
+
+ public String getName() {
+ return name;
+ }
+
+
+ public String getPostScriptName() {
+ return psname;
+ }
+
+
/**
* Set the native complement of this font.
*/
- public void setFont(Typeface font) {
+ public void setFont(Font font) {
this.font = font;
}
@@ -258,7 +406,7 @@ public class PFont implements PConstants {
/**
* Return the native java.awt.Font associated with this PFont (if any).
*/
- public Typeface getFont() {
+ public Font getFont() {
// if (font == null && !fontSearched) {
// font = findFont();
// }
@@ -270,10 +418,8 @@ public class PFont implements PConstants {
* Attempt to find the native version of this font.
* (Public so that it can be used by OpenGL or other renderers.)
*/
- public Typeface findFont() {
+ public Font findFont() {
if (font == null) {
- throw new RuntimeException("findFont() not available with Android.");
- /*
if (!fontSearched) {
// this font may or may not be installed
font = new Font(name, Font.PLAIN, size);
@@ -291,83 +437,55 @@ public class PFont implements PConstants {
}
fontSearched = true;
}
- */
}
return font;
}
- /**
- * Write this PFont to an OutputStream.
- *
- * This is used by the Create Font tool, or whatever anyone else dreams
- * up for messing with fonts themselves.
- *
- * It is assumed that the calling class will handle closing
- * the stream when finished.
- */
- public void save(OutputStream output) throws IOException {
- DataOutputStream os = new DataOutputStream(output);
-
- os.writeInt(charCount);
-
- if ((name == null) || (psname == null)) {
- name = "";
- psname = "";
- }
- // formerly numBits, now used for version number
- //os.writeInt((name != null) ? 11 : 8);
- os.writeInt(11);
-
- os.writeInt(size); // formerly mboxX (was 64, now 48)
- os.writeInt(mbox2); // formerly mboxY (was 64, still 64)
- os.writeInt(ascent); // formerly baseHt (was ignored)
- os.writeInt(descent); // formerly struct padding for c version
-
- for (int i = 0; i < charCount; i++) {
- os.writeInt(value[i]);
- os.writeInt(height[i]);
- os.writeInt(width[i]);
- os.writeInt(setWidth[i]);
- os.writeInt(topExtent[i]);
- os.writeInt(leftExtent[i]);
- os.writeInt(0); // padding
- }
-
- for (int i = 0; i < charCount; i++) {
- for (int y = 0; y < height[i]; y++) {
- for (int x = 0; x < width[i]; x++) {
- os.write(images[i].pixels[y * mbox2 + x] & 0xff);
- }
- }
- }
-
- //if (name != null) { // version 11
- os.writeUTF(name);
- os.writeUTF(psname);
- os.writeBoolean(smooth);
- //}
-
- os.flush();
+ public Glyph getGlyph(char c) {
+ int index = index(c);
+ return (index == -1) ? null : glyphs[index];
}
/**
- * Get index for the char (convert from unicode to bagel charset).
+ * Get index for the character.
* @return index into arrays or -1 if not found
*/
- public int index(char c) {
+ protected int index(char c) {
+ if (lazy) {
+ int index = indexActual(c);
+ if (index != -1) {
+ return index;
+ }
+ if (font.canDisplay(c)) {
+ // create the glyph
+ addGlyph(c);
+ // now where did i put that?
+ return indexActual(c);
+
+ } else {
+ return -1;
+ }
+
+ } else {
+ return indexActual(c);
+ }
+ }
+
+
+ protected int indexActual(char c) {
// degenerate case, but the find function will have trouble
// if there are somehow zero chars in the lookup
//if (value.length == 0) return -1;
- if (charCount == 0) return -1;
+ if (glyphCount == 0) return -1;
// quicker lookup for the ascii fellers
if (c < 128) return ascii[c];
// some other unicode char, hunt it out
//return index_hunt(c, 0, value.length-1);
- return indexHunt(c, 0, charCount-1);
+ return indexHunt(c, 0, glyphCount-1);
}
@@ -375,14 +493,14 @@ public class PFont implements PConstants {
int pivot = (start + stop) / 2;
// if this is the char, then return it
- if (c == value[pivot]) return pivot;
+ if (c == glyphs[pivot].value) return pivot;
// char doesn't exist, otherwise would have been the pivot
//if (start == stop) return -1;
if (start >= stop) return -1;
// if it's in the lower half, continue searching that
- if (c < value[pivot]) return indexHunt(c, start, pivot-1);
+ if (c < glyphs[pivot].value) return indexHunt(c, start, pivot-1);
// if it's in the upper half, continue there
return indexHunt(c, pivot+1, stop);
@@ -403,7 +521,7 @@ public class PFont implements PConstants {
* The value is based on a font of size 1.
*/
public float ascent() {
- return ((float)ascent / fheight);
+ return ((float) ascent / (float) size);
}
@@ -412,7 +530,7 @@ public class PFont implements PConstants {
* The value is based on a font size of 1.
*/
public float descent() {
- return ((float)descent / fheight);
+ return ((float) descent / (float) size);
}
@@ -425,7 +543,7 @@ public class PFont implements PConstants {
int cc = index(c);
if (cc == -1) return 0;
- return ((float)setWidth[cc] / fwidth);
+ return ((float) glyphs[cc].setWidth / (float) size);
}
@@ -478,103 +596,171 @@ public class PFont implements PConstants {
*
* Not that I expect that to happen.
*/
- static public char[] DEFAULT_CHARSET;
+ static public char[] CHARSET;
static {
- DEFAULT_CHARSET = new char[126-33+1 + EXTRA_CHARS.length];
+ CHARSET = new char[126-33+1 + EXTRA_CHARS.length];
int index = 0;
for (int i = 33; i <= 126; i++) {
- DEFAULT_CHARSET[index++] = (char)i;
+ CHARSET[index++] = (char)i;
}
for (int i = 0; i < EXTRA_CHARS.length; i++) {
- DEFAULT_CHARSET[index++] = EXTRA_CHARS[i];
+ CHARSET[index++] = EXTRA_CHARS[i];
}
};
/**
- * Create a new image-based font on the fly.
- *
- * @param font the font object to create from
- * @param charset array of all unicode chars that should be included
- * @param smooth true to enable smoothing/anti-aliasing
+ * Get a list of the fonts installed on the system that can be used
+ * by Java. Not all fonts can be used in Java, in fact it's mostly
+ * only TrueType fonts. OpenType fonts with CFF data such as Adobe's
+ * OpenType fonts seem to have trouble (even though they're sort of
+ * TrueType fonts as well, or may have a .ttf extension). Regular
+ * PostScript fonts seem to work OK, however.
+ *
+ * Not recommended for use in applets, but this is implemented
+ * in PFont because the Java methods to access this information
+ * have changed between 1.1 and 1.4, and the 1.4 method is
+ * typical of the sort of undergraduate-level over-abstraction
+ * that the seems to have made its way into the Java API after 1.1.
*/
- public PFont(Typeface font, int size, boolean smooth, char charset[]) {
- // save this so that we can use the native version
- this.font = font;
- this.smooth = smooth;
+ static public String[] list() {
+ loadFonts();
+ String list[] = new String[fonts.length];
+ for (int i = 0; i < list.length; i++) {
+ list[i] = fonts[i].getName();
+ }
+ return list;
+ }
+
-// name = font.getName();
-// psname = font.getPSName();
+ static public void loadFonts() {
+ if (fonts == null) {
+ GraphicsEnvironment ge =
+ GraphicsEnvironment.getLocalGraphicsEnvironment();
+ fonts = ge.getAllFonts();
+ }
+ }
- // fix regression from sorting (bug #564)
- if (charset != null) {
- // charset needs to be sorted to make index lookup run more quickly
- // http://dev.processing.org/bugs/show_bug.cgi?id=494
- Arrays.sort(charset);
+
+ /**
+ * Starting with Java 1.5, Apple broke the ability to specify most fonts.
+ * This has been filed as bug #4769141 at bugreporter.apple.com. More info at
+ * Bug 407.
+ */
+ static public Font findFont(String name) {
+ loadFonts();
+ if (PApplet.platform == PConstants.MACOSX) {
+ for (int i = 0; i < fonts.length; i++) {
+ if (name.equals(fonts[i].getName())) {
+ return fonts[i];
+ }
+ }
+ }
+ return new Font(name, Font.PLAIN, 1);
+ }
+
+
+ //////////////////////////////////////////////////////////////
+
+
+ /**
+ * A single character, and its visage.
+ */
+ public class Glyph {
+ PImage image;
+ int value;
+ int height;
+ int width;
+ int setWidth;
+ int topExtent;
+ int leftExtent;
+
+
+ protected Glyph() {
+ // used when reading from a stream or for subclasses
+ }
+
+
+ protected Glyph(DataInputStream is) throws IOException {
+ readHeader(is);
+ }
+
+
+ protected void readHeader(DataInputStream is) throws IOException {
+ value = is.readInt();
+ height = is.readInt();
+ width = is.readInt();
+ setWidth = is.readInt();
+ topExtent = is.readInt();
+ leftExtent = is.readInt();
+
+ // pointer from a struct in the c version, ignored
+ is.readInt();
+
+ // the values for getAscent() and getDescent() from FontMetrics
+ // seem to be way too large.. perhaps they're the max?
+ // as such, use a more traditional marker for ascent/descent
+ if (value == 'd') {
+ if (ascent == 0) ascent = topExtent;
+ }
+ if (value == 'p') {
+ if (descent == 0) descent = -topExtent + height;
+ }
}
- // the count gets reset later based on how many of
- // the chars are actually found inside the font.
- this.charCount = (charset == null) ? 65536 : charset.length;
- this.size = size;
-
- fwidth = fheight = size;
-
- PImage bitmaps[] = new PImage[charCount];
-
- // allocate enough space for the character info
- value = new int[charCount];
- height = new int[charCount];
- width = new int[charCount];
- setWidth = new int[charCount];
- topExtent = new int[charCount];
- leftExtent = new int[charCount];
-
- ascii = new int[128];
- for (int i = 0; i < 128; i++) ascii[i] = -1;
-
- int mbox3 = size * 3;
-
-// BufferedImage playground =
-// new BufferedImage(mbox3, mbox3, BufferedImage.TYPE_INT_RGB);
- Bitmap playground = Bitmap.createBitmap(mbox3, mbox3, Config.ARGB_8888);
-// Graphics2D g = (Graphics2D) playground.getGraphics();
- Canvas canvas = new Canvas(playground);
-// g.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
-// smooth ?
-// RenderingHints.VALUE_ANTIALIAS_ON :
-// RenderingHints.VALUE_ANTIALIAS_OFF);
- Paint paint = new Paint();
- paint.setAntiAlias(smooth);
-
-// g.setFont(font);
-// FontMetrics metrics = g.getFontMetrics();
- paint.setTypeface(font);
- paint.setTextSize(size);
- int samples[] = new int[mbox3 * mbox3];
+ protected void writeHeader(DataOutputStream os) throws IOException {
+ os.writeInt(value);
+ os.writeInt(height);
+ os.writeInt(width);
+ os.writeInt(setWidth);
+ os.writeInt(topExtent);
+ os.writeInt(leftExtent);
+ os.writeInt(0); // padding
+ }
+
+
+ protected void readBitmap(DataInputStream is) throws IOException {
+ image = new PImage(width, height, ALPHA);
+ int bitmapSize = width * height;
- int maxWidthHeight = 0;
- int index = 0;
- for (int i = 0; i < charCount; i++) {
- char c = (charset == null) ? (char)i : charset[i];
+ byte[] temp = new byte[bitmapSize];
+ is.readFully(temp);
-// if (!font.canDisplay(c)) { // skip chars not in the font
-// continue;
-// }
+ // convert the bitmap to an alpha channel
+ int w = width;
+ int h = height;
+ int[] pixels = image.pixels;
+ for (int y = 0; y < h; y++) {
+ for (int x = 0; x < w; x++) {
+ pixels[y * width + x] = temp[y*w + x] & 0xff;
+// System.out.print((image.pixels[y*64+x] > 128) ? "*" : ".");
+ }
+// System.out.println();
+ }
+// System.out.println();
+ }
+
+
+ protected void writeBitmap(DataOutputStream os) throws IOException {
+ int[] pixels = image.pixels;
+ for (int y = 0; y < height; y++) {
+ for (int x = 0; x < width; x++) {
+ os.write(pixels[y * width + x] & 0xff);
+ }
+ }
+ }
-// g.setColor(Color.white);
-// g.fillRect(0, 0, mbox3, mbox3);
- canvas.drawColor(Color.WHITE);
-// g.setColor(Color.black);
- paint.setColor(Color.BLACK);
-// g.drawString(String.valueOf(c), size, size * 2);
- canvas.drawText(String.valueOf(c), size, size * 2, paint);
- // grabs copy of the current data.. so no updates (do each time)
-// Raster raster = playground.getData();
-// raster.getSamples(0, 0, mbox3, mbox3, 0, samples);
- playground.getPixels(samples, 0, mbox3, 0, 0, mbox3, mbox3);
+ protected Glyph(char c) {
+ int mbox3 = size * 3;
+ lazyGraphics.setColor(Color.white);
+ lazyGraphics.fillRect(0, 0, mbox3, mbox3);
+ lazyGraphics.setColor(Color.black);
+ lazyGraphics.drawString(String.valueOf(c), size, size * 2);
+
+ WritableRaster raster = lazyImage.getRaster();
+ raster.getDataElements(0, 0, mbox3, mbox3, lazySamples);
int minX = 1000, maxX = 0;
int minY = 1000, maxY = 0;
@@ -582,11 +768,7 @@ public class PFont implements PConstants {
for (int y = 0; y < mbox3; y++) {
for (int x = 0; x < mbox3; x++) {
- //int sample = raster.getSample(x, y, 0); // maybe?
- int sample = samples[y * mbox3 + x] & 0xff;
- // or int samples[] = raster.getPixel(x, y, null);
-
- //if (sample == 0) { // or just not white? hmm
+ int sample = lazySamples[y * mbox3 + x] & 0xff;
if (sample != 255) {
if (x < minX) minX = x;
if (y < minY) minY = y;
@@ -604,141 +786,35 @@ public class PFont implements PConstants {
// maybe better to set one to -1 so nothing is added?
}
- value[index] = c;
- height[index] = (maxY - minY) + 1;
- width[index] = (maxX - minX) + 1;
-// setWidth[index] = metrics.charWidth(c);
- setWidth[index] = (int) paint.measureText(String.valueOf(c));
- //System.out.println((char)c + " " + setWidth[index]);
-
- // cache locations of the ascii charset
- //if (value[i] < 128) ascii[value[i]] = i;
- if (c < 128) ascii[c] = index;
+ value = c;
+ height = (maxY - minY) + 1;
+ width = (maxX - minX) + 1;
+ setWidth = lazyMetrics.charWidth(c);
// offset from vertical location of baseline
// of where the char was drawn (size*2)
- topExtent[index] = size*2 - minY;
+ topExtent = size*2 - minY;
// offset from left of where coord was drawn
- leftExtent[index] = minX - size;
-
- if (c == 'd') {
- ascent = topExtent[index];
- }
- if (c == 'p') {
- descent = -topExtent[index] + height[index];
- }
-
- if (width[index] > maxWidthHeight) maxWidthHeight = width[index];
- if (height[index] > maxWidthHeight) maxWidthHeight = height[index];
-
- bitmaps[index] = new PImage(width[index], height[index], ALPHA);
+ leftExtent = minX - size;
+ image = new PImage(width, height, ALPHA);
+ int[] pixels = image.pixels;
for (int y = minY; y <= maxY; y++) {
for (int x = minX; x <= maxX; x++) {
- int val = 255 - (samples[y * mbox3 + x] & 0xff);
- int pindex = (y - minY) * width[index] + (x - minX);
- bitmaps[index].pixels[pindex] = val;
+ int val = 255 - (lazySamples[y * mbox3 + x] & 0xff);
+ int pindex = (y - minY) * width + (x - minX);
+ pixels[pindex] = val;
}
}
- index++;
- }
- charCount = index;
- // foreign font, so just make ascent the max topExtent
- if ((ascent == 0) && (descent == 0)) {
- for (int i = 0; i < charCount; i++) {
- char cc = (char) value[i];
- if (Character.isWhitespace(cc) ||
- (cc == '\u00A0') || (cc == '\u2007') || (cc == '\u202F')) {
- continue;
- }
- if (topExtent[i] > ascent) {
- ascent = topExtent[i];
- }
- int d = -topExtent[i] + height[i];
- if (d > descent) {
- descent = d;
- }
+ // replace the ascent/descent values with something.. err, decent.
+ if (value == 'd') {
+ if (ascent == 0) ascent = topExtent;
+ }
+ if (value == 'p') {
+ if (descent == 0) descent = -topExtent + height;
}
}
- // size for image/texture is next power of 2 over largest char
- mbox2 = (int)
- Math.pow(2, Math.ceil(Math.log(maxWidthHeight) / Math.log(2)));
- twidth = theight = mbox2;
-
- // shove the smaller PImage data into textures of next-power-of-2 size,
- // so that this font can be used immediately by p5.
- images = new PImage[charCount];
- for (int i = 0; i < charCount; i++) {
- images[i] = new PImage(mbox2, mbox2, ALPHA);
- for (int y = 0; y < height[i]; y++) {
- System.arraycopy(bitmaps[i].pixels, y*width[i],
- images[i].pixels, y*mbox2,
- width[i]);
- }
- bitmaps[i] = null;
- }
- }
-
-
- static HashMap fontMap;
- static String[] fontList;
-
-
- /**
- * Get a list of the built-in fonts.
- */
- static public String[] list() {
- loadFonts();
- return fontList;
- }
-
-
- static public void loadFonts() {
- if (fontMap == null) {
- fontMap = new HashMap();
-
- fontMap.put("Serif",
- Typeface.create(Typeface.SERIF, Typeface.NORMAL));
- fontMap.put("Serif-Bold",
- Typeface.create(Typeface.SERIF, Typeface.BOLD));
- fontMap.put("Serif-Italic",
- Typeface.create(Typeface.SERIF, Typeface.ITALIC));
- fontMap.put("Serif-BoldItalic",
- Typeface.create(Typeface.SERIF, Typeface.BOLD_ITALIC));
-
- fontMap.put("SansSerif",
- Typeface.create(Typeface.SANS_SERIF, Typeface.NORMAL));
- fontMap.put("SansSerif-Bold",
- Typeface.create(Typeface.SANS_SERIF, Typeface.BOLD));
- fontMap.put("SansSerif-Italic",
- Typeface.create(Typeface.SANS_SERIF, Typeface.ITALIC));
- fontMap.put("SansSerif-BoldItalic",
- Typeface.create(Typeface.SANS_SERIF, Typeface.BOLD_ITALIC));
-
- fontMap.put("Monospaced",
- Typeface.create(Typeface.MONOSPACE, Typeface.NORMAL));
- fontMap.put("Monospaced-Bold",
- Typeface.create(Typeface.MONOSPACE, Typeface.BOLD));
- fontMap.put("Monospaced-Italic",
- Typeface.create(Typeface.MONOSPACE, Typeface.ITALIC));
- fontMap.put("Monospaced-BoldItalic",
- Typeface.create(Typeface.MONOSPACE, Typeface.BOLD_ITALIC));
-
- fontList = new String[fontMap.size()];
- fontMap.keySet().toArray(fontList);
- }
- }
-
-
- /**
- * Starting with Java 1.5, Apple broke the ability to specify most fonts.
- * This has been filed as bug #4769141 at bugreporter.apple.com. More info at
- * Bug 407.
- */
- static public Typeface findFont(String name) {
- loadFonts();
- return fontMap.get(name);
}
}