mirror of
https://github.com/processing/processing4.git
synced 2026-06-16 04:26:26 +02:00
lots of cleanup, merging code
This commit is contained in:
+237
-545
@@ -7,9 +7,8 @@
|
||||
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
|
||||
@@ -129,132 +128,30 @@ public class PFont implements PConstants {
|
||||
static protected Font[] 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
|
||||
|
||||
|
||||
public PFont(InputStream input) throws IOException {
|
||||
DataInputStream is = new DataInputStream(input);
|
||||
|
||||
// number of character images stored in this font
|
||||
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.
|
||||
int version = is.readInt();
|
||||
|
||||
// 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
|
||||
is.readInt(); // ignore the other mbox attribute
|
||||
|
||||
// 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)));
|
||||
// size for the texture is stored in the font
|
||||
// twidth = theight = mbox2; //mbox2;
|
||||
|
||||
ascent = is.readInt(); // formerly baseHt (zero/ignored)
|
||||
descent = is.readInt(); // formerly ignored struct padding
|
||||
|
||||
// allocate enough space for the character info
|
||||
glyphs = new Glyph[glyphCount];
|
||||
// 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;
|
||||
|
||||
// read the information about the individual characters
|
||||
for (int i = 0; i < glyphCount; i++) {
|
||||
glyphs[i] = new Glyph();
|
||||
Glyph glyph = glyphs[i];
|
||||
|
||||
glyph.value = is.readInt();
|
||||
glyph.height = is.readInt();
|
||||
glyph.width = is.readInt();
|
||||
glyph.setWidth = is.readInt();
|
||||
glyph.topExtent = is.readInt();
|
||||
glyph.leftExtent = is.readInt();
|
||||
|
||||
// pointer from a struct in the c version, ignored
|
||||
is.readInt();
|
||||
|
||||
// cache locations of the ascii charset
|
||||
if (glyph.value < 128) ascii[glyph.value] = 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 (glyph.value == 'd') {
|
||||
if (ascent == 0) ascent = glyph.topExtent;
|
||||
}
|
||||
if (glyph.value == 'p') {
|
||||
if (descent == 0) descent = -glyph.topExtent + glyph.height;
|
||||
}
|
||||
}
|
||||
|
||||
// not a roman font, so throw an error and ask to re-build.
|
||||
// that way can avoid a bunch of error checking hacks in here.
|
||||
if ((ascent == 0) && (descent == 0)) {
|
||||
throw new RuntimeException("Please use \"Create Font\" to " +
|
||||
"re-create this font.");
|
||||
}
|
||||
|
||||
// images = new PImage[charCount];
|
||||
// for (int i = 0; i < charCount; i++) {
|
||||
// Glyph glyph = glyphs[i];
|
||||
for (Glyph glyph : glyphs) {
|
||||
//images[i] = new PImage(twidth, theight, ALPHA);
|
||||
glyph.image = new PImage(glyph.width, glyph.height, ALPHA);
|
||||
//int bitmapSize = height[i] * width[i];
|
||||
int bitmapSize = glyph.width * glyph.height;
|
||||
|
||||
byte[] temp = new byte[bitmapSize];
|
||||
is.readFully(temp);
|
||||
|
||||
// convert the bitmap to an alpha channel
|
||||
int w = glyph.width;
|
||||
int h = glyph.height;
|
||||
int[] pixels = glyph.image.pixels;
|
||||
for (int y = 0; y < h; y++) {
|
||||
for (int x = 0; x < w; x++) {
|
||||
int valu = temp[y*w + x] & 0xff;
|
||||
//image.pixels[y * twidth + x] = valu;
|
||||
pixels[y * glyph.width + x] = valu;
|
||||
//System.out.print((images[i].pixels[y*64+x] > 128) ? "*" : ".");
|
||||
}
|
||||
//System.out.println();
|
||||
}
|
||||
//System.out.println();
|
||||
}
|
||||
|
||||
if (version >= 10) { // includes the font name at the end of the file
|
||||
name = is.readUTF();
|
||||
psname = is.readUTF();
|
||||
}
|
||||
if (version == 11) {
|
||||
smooth = is.readBoolean();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Create a new image-based font on the fly.
|
||||
* 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
|
||||
@@ -265,242 +162,20 @@ public class PFont implements PConstants {
|
||||
this.font = font;
|
||||
this.smooth = smooth;
|
||||
|
||||
name = font.getName();
|
||||
psname = font.getPSName();
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
// the count gets reset later based on how many of
|
||||
// the chars are actually found inside the font.
|
||||
this.glyphCount = (charset == null) ? 65536 : charset.length;
|
||||
this.size = font.getSize();
|
||||
|
||||
// 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];
|
||||
glyphs = new Glyph[glyphCount];
|
||||
|
||||
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);
|
||||
|
||||
Graphics2D g = (Graphics2D) playground.getGraphics();
|
||||
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
|
||||
smooth ?
|
||||
RenderingHints.VALUE_ANTIALIAS_ON :
|
||||
RenderingHints.VALUE_ANTIALIAS_OFF);
|
||||
// adding this for post-1.0.9
|
||||
g.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
|
||||
smooth ?
|
||||
RenderingHints.VALUE_TEXT_ANTIALIAS_ON :
|
||||
RenderingHints.VALUE_TEXT_ANTIALIAS_OFF);
|
||||
|
||||
g.setFont(font);
|
||||
FontMetrics metrics = g.getFontMetrics();
|
||||
|
||||
int samples[] = new int[mbox3 * mbox3];
|
||||
|
||||
int maxWidthHeight = 0;
|
||||
int index = 0;
|
||||
for (int i = 0; i < glyphCount; i++) {
|
||||
Glyph glyph = new Glyph();
|
||||
char c = (charset == null) ? (char)i : charset[i];
|
||||
|
||||
if (!font.canDisplay(c)) { // skip chars not in the font
|
||||
continue;
|
||||
}
|
||||
|
||||
g.setColor(Color.white);
|
||||
g.fillRect(0, 0, mbox3, mbox3);
|
||||
g.setColor(Color.black);
|
||||
g.drawString(String.valueOf(c), size, size * 2);
|
||||
|
||||
// grabs copy of the current data.. so no updates (do each time)
|
||||
// Raster raster = playground.getData();
|
||||
// raster.getSamples(0, 0, mbox3, mbox3, 0, samples);
|
||||
// slightly faster version
|
||||
WritableRaster raster = playground.getRaster();
|
||||
raster.getDataElements(0, 0, mbox3, mbox3, samples);
|
||||
|
||||
int minX = 1000, maxX = 0;
|
||||
int minY = 1000, maxY = 0;
|
||||
boolean pixelFound = false;
|
||||
|
||||
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
|
||||
if (sample != 255) {
|
||||
if (x < minX) minX = x;
|
||||
if (y < minY) minY = y;
|
||||
if (x > maxX) maxX = x;
|
||||
if (y > maxY) maxY = y;
|
||||
pixelFound = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!pixelFound) {
|
||||
minX = minY = 0;
|
||||
maxX = maxY = 0;
|
||||
// this will create a 1 pixel white (clear) character..
|
||||
// maybe better to set one to -1 so nothing is added?
|
||||
}
|
||||
|
||||
// value[index] = c;
|
||||
glyph.value = c;
|
||||
glyph.height = (maxY - minY) + 1;
|
||||
glyph.width = (maxX - minX) + 1;
|
||||
glyph.setWidth = metrics.charWidth(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;
|
||||
|
||||
// offset from vertical location of baseline
|
||||
// of where the char was drawn (size*2)
|
||||
glyph.topExtent = size*2 - minY;
|
||||
|
||||
// offset from left of where coord was drawn
|
||||
glyph.leftExtent = minX - size;
|
||||
|
||||
// for version 11, using metrics instead
|
||||
// if (c == 'd') {
|
||||
// ascent = glyph.topExtent;
|
||||
// }
|
||||
// if (c == 'p') {
|
||||
// descent = -glyph.topExtent + glyph.height;
|
||||
// }
|
||||
ascent = metrics.getAscent();
|
||||
descent = metrics.getDescent();
|
||||
|
||||
if (glyph.width > maxWidthHeight) maxWidthHeight = glyph.width;
|
||||
if (glyph.height > maxWidthHeight) maxWidthHeight = glyph.height;
|
||||
|
||||
//bitmaps[index] = new PImage(width[index], height[index], ALPHA);
|
||||
glyph.image = new PImage(glyph.width, glyph.height, ALPHA);
|
||||
int[] pixels = glyph.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);
|
||||
int pindex = (y - minY) * glyph.width + (x - minX);
|
||||
//bitmaps[index].pixels[pindex] = val;
|
||||
pixels[pindex] = val;
|
||||
}
|
||||
}
|
||||
// index++;
|
||||
glyphs[index++] = glyph;
|
||||
}
|
||||
if (glyphCount != index) {
|
||||
glyphs = (Glyph[]) PApplet.subset(glyphs, 0, index);
|
||||
glyphCount = index;
|
||||
}
|
||||
|
||||
// foreign font, so just make ascent the max topExtent
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
// 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;
|
||||
// }
|
||||
}
|
||||
|
||||
|
||||
BufferedImage lazyImage;
|
||||
Graphics2D lazyGraphics;
|
||||
FontMetrics lazyMetrics;
|
||||
int[] lazySamples;
|
||||
|
||||
/**
|
||||
* 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) {
|
||||
// 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();
|
||||
// fwidth = fheight = size;
|
||||
|
||||
// no, i'm not interested in getting off the ouch
|
||||
// no, i'm not interested in getting off the couch
|
||||
lazy = true;
|
||||
// not sure what else to do here
|
||||
// mbox2 = 0;
|
||||
|
||||
// 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;
|
||||
|
||||
// PImage[] bitmaps = new PImage[charCount];
|
||||
//mbox2 = 0;
|
||||
|
||||
int initialCount = 10;
|
||||
glyphs = new Glyph[initialCount];
|
||||
|
||||
// allocate enough space for the character info
|
||||
// value = new int[initialCount];
|
||||
// height = new int[initialCount];
|
||||
// width = new int[initialCount];
|
||||
// setWidth = new int[initialCount];
|
||||
// topExtent = new int[initialCount];
|
||||
// leftExtent = new int[initialCount];
|
||||
|
||||
ascii = new int[128];
|
||||
for (int i = 0; i < 128; i++) ascii[i] = -1;
|
||||
Arrays.fill(ascii, -1);
|
||||
|
||||
int mbox3 = size * 3;
|
||||
|
||||
@@ -522,121 +197,159 @@ public class PFont implements PConstants {
|
||||
|
||||
ascent = lazyMetrics.getAscent();
|
||||
descent = lazyMetrics.getDescent();
|
||||
}
|
||||
|
||||
|
||||
protected Glyph createGlyph(char c) {
|
||||
Glyph glyph = new Glyph();
|
||||
|
||||
// if (font.canDisplay(c)) { // skip chars not in the font
|
||||
// continue;
|
||||
// }
|
||||
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);
|
||||
|
||||
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);
|
||||
glyphs = new Glyph[glyphCount];
|
||||
|
||||
// grabs copy of the current data.. so no updates (do each time)
|
||||
// Raster raster = playground.getData();
|
||||
// raster.getSamples(0, 0, mbox3, mbox3, 0, samples);
|
||||
// slightly faster version
|
||||
WritableRaster raster = lazyImage.getRaster();
|
||||
raster.getDataElements(0, 0, mbox3, mbox3, lazySamples);
|
||||
|
||||
int minX = 1000, maxX = 0;
|
||||
int minY = 1000, maxY = 0;
|
||||
boolean pixelFound = false;
|
||||
|
||||
for (int y = 0; y < mbox3; y++) {
|
||||
for (int x = 0; x < mbox3; x++) {
|
||||
//int sample = raster.getSample(x, y, 0); // maybe?
|
||||
int sample = lazySamples[y * mbox3 + x] & 0xff;
|
||||
// or int samples[] = raster.getPixel(x, y, null);
|
||||
|
||||
//if (sample == 0) { // or just not white? hmm
|
||||
if (sample != 255) {
|
||||
if (x < minX) minX = x;
|
||||
if (y < minY) minY = y;
|
||||
if (x > maxX) maxX = x;
|
||||
if (y > maxY) maxY = y;
|
||||
pixelFound = true;
|
||||
glyphCount = 0;
|
||||
for (char c : charset) {
|
||||
if (font.canDisplay(c)) {
|
||||
glyphs[glyphCount++] = new Glyph(c);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!pixelFound) {
|
||||
minX = minY = 0;
|
||||
maxX = maxY = 0;
|
||||
// this will create a 1 pixel white (clear) character..
|
||||
// maybe better to set one to -1 so nothing is added?
|
||||
}
|
||||
|
||||
glyph.value = c;
|
||||
glyph.height = (maxY - minY) + 1;
|
||||
glyph.width = (maxX - minX) + 1;
|
||||
glyph.setWidth = lazyMetrics.charWidth(c);
|
||||
//System.out.println((char)c + " " + setWidth[index]);
|
||||
|
||||
// int mx = PApplet.max(glyph.width, glyph.height);
|
||||
// if (mx > mbox2) {
|
||||
// mbox2 = (int) Math.pow(2, Math.ceil(Math.log(mx) / Math.log(2)));
|
||||
// }
|
||||
|
||||
// // cache locations of the ascii charset
|
||||
// if (c < 128) ascii[c] = index;
|
||||
|
||||
// offset from vertical location of baseline
|
||||
// of where the char was drawn (size*2)
|
||||
glyph.topExtent = size*2 - minY;
|
||||
|
||||
// offset from left of where coord was drawn
|
||||
glyph.leftExtent = minX - size;
|
||||
|
||||
/*
|
||||
if (c == 'd') {
|
||||
ascent = glyph.topExtent;
|
||||
// shorten the array if necessary
|
||||
if (glyphCount != charset.length) {
|
||||
glyphs = (Glyph[]) PApplet.subset(glyphs, 0, glyphCount);
|
||||
}
|
||||
if (c == 'p') {
|
||||
descent = -glyph.topExtent + glyph.height;
|
||||
}
|
||||
*/
|
||||
|
||||
// if (width[index] > maxWidthHeight) maxWidthHeight = width[index];
|
||||
// if (height[index] > maxWidthHeight) maxWidthHeight = height[index];
|
||||
|
||||
glyph.image = new PImage(glyph.width, glyph.height, ALPHA);
|
||||
int[] pixels = glyph.image.pixels;
|
||||
for (int y = minY; y <= maxY; y++) {
|
||||
for (int x = minX; x <= maxX; x++) {
|
||||
int val = 255 - (lazySamples[y * mbox3 + x] & 0xff);
|
||||
int pindex = (y - minY) * glyph.width + (x - minX);
|
||||
pixels[pindex] = val;
|
||||
}
|
||||
// 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;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
// replace the ascent/descent values with something.. err, decent.
|
||||
if (glyph.value == 'd') {
|
||||
if (ascent == 0) ascent = glyph.topExtent;
|
||||
}
|
||||
if (glyph.value == 'p') {
|
||||
if (descent == 0) descent = -glyph.topExtent + glyph.height;
|
||||
}
|
||||
return glyph;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
public PFont(InputStream input) throws IOException {
|
||||
DataInputStream is = new DataInputStream(input);
|
||||
|
||||
// number of character images stored in this font
|
||||
glyphCount = 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.
|
||||
int version = is.readInt();
|
||||
|
||||
// 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
|
||||
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
|
||||
glyphs = new Glyph[glyphCount];
|
||||
|
||||
ascii = new int[128];
|
||||
Arrays.fill(ascii, -1);
|
||||
|
||||
// read the information about the individual characters
|
||||
for (int i = 0; i < glyphCount; i++) {
|
||||
Glyph glyph = new Glyph(is);
|
||||
// cache locations of the ascii charset
|
||||
if (glyph.value < 128) {
|
||||
ascii[glyph.value] = i;
|
||||
}
|
||||
glyphs[i] = glyph;
|
||||
}
|
||||
|
||||
// not a roman font, so throw an error and ask to re-build.
|
||||
// that way can avoid a bunch of error checking hacks in here.
|
||||
if ((ascent == 0) && (descent == 0)) {
|
||||
throw new RuntimeException("Please use \"Create Font\" to " +
|
||||
"re-create this font.");
|
||||
}
|
||||
|
||||
for (Glyph glyph : glyphs) {
|
||||
glyph.readBitmap(is);
|
||||
}
|
||||
|
||||
if (version >= 10) { // includes the font name at the end of the file
|
||||
name = is.readUTF();
|
||||
psname = is.readUTF();
|
||||
}
|
||||
if (version == 11) {
|
||||
smooth = is.readBoolean();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Write this PFont to an OutputStream.
|
||||
* <p>
|
||||
* This is used by the Create Font tool, or whatever anyone else dreams
|
||||
* up for messing with fonts themselves.
|
||||
* <p>
|
||||
* 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 = createGlyph(c);
|
||||
// if (charCount != index) {
|
||||
// glyphs = (Glyph[]) PApplet.subset(glyphs, 0, index);
|
||||
// charCount = index;
|
||||
// }
|
||||
//Glyph glyph = createGlyph(c);
|
||||
Glyph glyph = new Glyph(c);
|
||||
|
||||
if (glyphCount == glyphs.length) {
|
||||
glyphs = (Glyph[]) PApplet.expand(glyphs);
|
||||
@@ -648,7 +361,6 @@ public class PFont implements PConstants {
|
||||
}
|
||||
|
||||
} else if (glyphs[glyphCount-1].value < glyph.value) {
|
||||
//System.out.println("at end " + (char) glyph.value);
|
||||
glyphs[glyphCount] = glyph;
|
||||
if (glyph.value < 128) {
|
||||
ascii[glyph.value] = glyphCount;
|
||||
@@ -656,41 +368,21 @@ public class PFont implements PConstants {
|
||||
|
||||
} else {
|
||||
for (int i = 0; i < glyphCount; i++) {
|
||||
// System.out.println(i + " of " + charCount + " is " + (char)glyphs[i].value);
|
||||
//int value = glyphs[i].value;
|
||||
//if (glyphs[i].value > glyph.value) {
|
||||
if (glyphs[i].value > c) {
|
||||
for (int j = glyphCount; j > i; --j) {
|
||||
// System.out.println(" moving " + (char)glyphs[j-1].value); // +
|
||||
// //" to " + (char)glyphs[j].value);
|
||||
glyphs[j] = glyphs[j-1];
|
||||
if (glyphs[j].value < 128) {
|
||||
ascii[glyphs[j].value] = j;
|
||||
}
|
||||
}
|
||||
//System.out.println("setting " + i + " to " + (char)glyph.value);
|
||||
glyphs[i] = glyph;
|
||||
// cache locations of the ascii charset
|
||||
if (c < 128) ascii[c] = i;
|
||||
// for (int k = 0; k < charCount+1; k++) { // charCount not incremented yet
|
||||
// if (glyphs[k].value < 128) {
|
||||
//// System.out.println("ascii[" + (char) glyphs[k].value + "] to " + k);
|
||||
// ascii[glyphs[k].value] = k; // re-set the ascii values
|
||||
// }
|
||||
// }
|
||||
// charCount++;
|
||||
// return;
|
||||
break;
|
||||
// i = charCount;
|
||||
}
|
||||
}
|
||||
}
|
||||
glyphCount++;
|
||||
// for (int i = 0; i < charCount; i++) {
|
||||
// System.out.println("[" + i + "] " + (char)glyphs[i].value);
|
||||
// }
|
||||
//System.out.println("e is " + (char)glyphs[ascii['e']].value + " w=" + (char)glyphs[ascii['w']].value);
|
||||
// System.out.println("e is " + ascii['e'] + " w=" + ascii['w']);
|
||||
}
|
||||
|
||||
|
||||
@@ -751,78 +443,6 @@ public class PFont implements PConstants {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Write this PFont to an OutputStream.
|
||||
* <p>
|
||||
* This is used by the Create Font tool, or whatever anyone else dreams
|
||||
* up for messing with fonts themselves.
|
||||
* <p>
|
||||
* 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 = "";
|
||||
}
|
||||
// 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)
|
||||
// TODO imperfect, should really be doing next power of 2 on all chars,
|
||||
// but this is ignored starting now, and the only problem would happen if
|
||||
// a font created on > 1.0.9 where used with 1.0.9 and earlier
|
||||
int mbox2 = (int) Math.pow(2, Math.ceil(Math.log(size) / Math.log(2)));
|
||||
os.writeInt(mbox2); // formerly mboxY
|
||||
os.writeInt(ascent); // formerly baseHt (was ignored)
|
||||
os.writeInt(descent); // formerly struct padding for c version
|
||||
|
||||
//for (int i = 0; i < charCount; i++) {
|
||||
for (Glyph glyph : glyphs) {
|
||||
os.writeInt(glyph.value);
|
||||
os.writeInt(glyph.height);
|
||||
os.writeInt(glyph.width);
|
||||
os.writeInt(glyph.setWidth);
|
||||
os.writeInt(glyph.topExtent);
|
||||
os.writeInt(glyph.leftExtent);
|
||||
// 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 (Glyph glyph : glyphs) {
|
||||
int[] pixels = glyph.image.pixels;
|
||||
for (int y = 0; y < glyph.height; y++) {
|
||||
for (int x = 0; x < glyph.width; x++) {
|
||||
//os.write(pixels[y * mbox2 + x] & 0xff);
|
||||
os.write(pixels[y * glyph.width + x] & 0xff);
|
||||
}
|
||||
// for (int x = glyph.width; x < mbox2; x++) {
|
||||
// os.write(0);
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
//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];
|
||||
@@ -853,7 +473,8 @@ public class PFont implements PConstants {
|
||||
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
|
||||
@@ -1054,10 +675,81 @@ public class PFont implements PConstants {
|
||||
|
||||
|
||||
protected Glyph() {
|
||||
// used when reading from a stream
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
|
||||
byte[] temp = new byte[bitmapSize];
|
||||
is.readFully(temp);
|
||||
|
||||
// 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((images[i].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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
protected Glyph(char c) {
|
||||
int mbox3 = size * 3;
|
||||
lazyGraphics.setColor(Color.white);
|
||||
|
||||
Reference in New Issue
Block a user