refactoring of image-generation; added experimental PNG encoder (not active now)

git-svn-id: https://svn.berlios.de/svnroot/repos/yacy/trunk@1008 6c8d7289-2bf4-0310-a012-ef5d649a1542
pull/1/head
orbiter 20 years ago
parent 7a9fc653e9
commit b058ecf0bc

@ -144,6 +144,7 @@
<mkdir dir="${build}/de/anomic/plasma/parser"/>
<mkdir dir="${build}/de/anomic/server"/>
<mkdir dir="${build}/de/anomic/tools"/>
<mkdir dir="${build}/de/anomic/ymage"/>
<mkdir dir="${build}/de/anomic/yacy"/>
<mkdir dir="${build}/de/anomic/yacy/seedUpload"/>

@ -44,19 +44,17 @@
// Contributions and changes to the program code must be marked as such.
import java.awt.image.BufferedImage;
import de.anomic.http.httpHeader;
import de.anomic.server.serverObjects;
import de.anomic.server.serverSwitch;
import de.anomic.ymage.ymagePainter;
import de.anomic.plasma.plasmaGrafics;
// draw a picture of the yacy network
public class NetworkPicture {
public static BufferedImage respond(httpHeader header, serverObjects post, serverSwitch env) {
public static ymagePainter respond(httpHeader header, serverObjects post, serverSwitch env) {
int width = 640;
int height = 480;
@ -77,7 +75,7 @@ public class NetworkPicture {
if (passiveLimit > 500) passiveLimit = 500;
if (potentialLimit > 500) potentialLimit = 500;
if (maxCount > 1000) maxCount = 1000;
return plasmaGrafics.getNetworkPicture(10000, width, height, passiveLimit, potentialLimit, maxCount).toImage(true);
return plasmaGrafics.getNetworkPicture(10000, width, height, passiveLimit, potentialLimit, maxCount);
}
}

@ -51,18 +51,20 @@ import de.anomic.server.serverObjects;
import de.anomic.server.serverSwitch;
import de.anomic.plasma.plasmaGrafics;
import de.anomic.tools.ImagePainter;
import de.anomic.ymage.ymagePainter;
import de.anomic.ymage.ymageMatrixPainter;
import de.anomic.ymage.ymageMatrix;
// draw a picture of the yacy network
public class SearchEventPicture {
public static BufferedImage respond(httpHeader header, serverObjects post, serverSwitch env) {
public static ymagePainter respond(httpHeader header, serverObjects post, serverSwitch env) {
ImagePainter ip = plasmaGrafics.getSearchEventPicture();
if (ip == null) return new BufferedImage(1, 1, BufferedImage.TYPE_INT_RGB); // empty image
ymagePainter yp = plasmaGrafics.getSearchEventPicture();
if (yp == null) return new ymageMatrixPainter(1, 1, "000000"); // empty image
return ip.toImage(true);
return yp;
}
}

@ -46,7 +46,9 @@
import de.anomic.http.httpHeader;
import de.anomic.server.serverObjects;
import de.anomic.server.serverSwitch;
import de.anomic.tools.ImagePainter;
import de.anomic.ymage.ymagePainter;
import de.anomic.ymage.ymageMatrixPainter;
import de.anomic.ymage.ymageMatrix;
import java.awt.Graphics2D;
import java.awt.Color;
@ -64,7 +66,7 @@ import java.lang.reflect.Method;
public class imagetest {
public static BufferedImage respond(httpHeader header, serverObjects post, serverSwitch env) {
public static ymagePainter respond(httpHeader header, serverObjects post, serverSwitch env) {
/*
BufferedImage bi = new BufferedImage(640, 400, BufferedImage.TYPE_INT_RGB);
Graphics2D g = bi.createGraphics();
@ -96,26 +98,26 @@ public class imagetest {
for (int i = 20; i < 100; i++) r.setPixel(i, 34, new int[]{0, 0, 255});
return bi;
*/
ImagePainter img = new ImagePainter(800, 600, 0);
ymagePainter img = new ymageMatrixPainter(800, 600, "000000");
img.setMode(ImagePainter.MODE_ADD);
img.setColor(ImagePainter.ADDITIVE_BLACK);
img.setMode(ymageMatrix.MODE_ADD);
img.setColor(ymageMatrix.ADDITIVE_BLACK);
for (int y = 0; y < 600; y = y + 50) img.print(0, 6 + y, 0, "" + y, true);
for (int x = 0; x < 800; x = x + 50) img.print(x, 6 , 0, "" + x, true);
img.setColor(ImagePainter.ADDITIVE_RED);
img.setColor(ymageMatrix.ADDITIVE_RED);
img.dot(550, 110, 90, true);
img.setColor(ImagePainter.ADDITIVE_GREEN);
img.setColor(ymageMatrix.ADDITIVE_GREEN);
img.dot(480, 200, 90, true);
img.setColor(ImagePainter.ADDITIVE_BLUE);
img.setColor(ymageMatrix.ADDITIVE_BLUE);
img.dot(620, 200, 90, true);
img.setColor(ImagePainter.ADDITIVE_RED);
img.setColor(ymageMatrix.ADDITIVE_RED);
img.arc(300, 270, 30, 70, 0, 360);
img.setColor("330000");
img.arc(220, 110, 50, 90, 30, 110);
img.arc(210, 120, 50, 90, 30, 110);
img.setColor(ImagePainter.ADDITIVE_BLACK);
img.setColor(ymageMatrix.ADDITIVE_BLACK);
img.print(50, 110, 0, "BROADCAST MESSAGE #772: NODE %882 BLACK abcefghijklmnopqrstuvwxyz", true);
img.setColor(ImagePainter.ADDITIVE_GREEN);
img.setColor(ymageMatrix.ADDITIVE_GREEN);
img.print(50, 120, 0, "BROADCAST MESSAGE #772: NODE %882 GREEN abcefghijklmnopqrstuvwxyz", true);
for (long i = 0; i < 256; i++) {
img.setColor(i);
@ -138,14 +140,14 @@ public class imagetest {
for (int i = 0; i <= 360; i++) {
img.arc(550, 400, 40, 41 + i/9, 0, i);
}
img.setColor(ImagePainter.ADDITIVE_BLACK);
img.setColor(ymageMatrix.ADDITIVE_BLACK);
int angle;
for (byte c = (byte) 'A'; c <= 'Z'; c++) {
angle = ((byte) c - (byte) 'A') * 360 / ((byte) 'Z' - (byte) 'A');
img.arcLine(550, 400, 81, 100, angle);
img.arcPrint(550, 400, 100, angle, "ANGLE" + angle + ":" + (char) c);
}
return img.toImage(true);
return img;
}

@ -14,7 +14,8 @@ import java.util.Date;
import de.anomic.server.serverCodings;
import de.anomic.kelondro.kelondroIndex;
import de.anomic.kelondro.kelondroTree;
import de.anomic.tools.ImageChart;
import de.anomic.ymage.ymageChart;
import de.anomic.ymage.ymagePNGEncoderAWT;
import de.anomic.server.serverMemory;
public class dbtest {
@ -215,7 +216,7 @@ final class dbTable implements kelondroIndex {
final class memprofiler extends Thread {
ImageChart memChart;
ymageChart memChart;
boolean run;
File outputFile;
long start;
@ -223,11 +224,11 @@ final class memprofiler extends Thread {
public memprofiler(int width, int height, int expectedTimeSeconds, File outputFile) {
this.outputFile = outputFile;
int expectedKilobytes = (int) 20 * 1024;//(Runtime.getRuntime().totalMemory() / 1024);
memChart = new ImageChart(width, height, "000010", 50, 20, 20, 20, "MEMORY CHART FROM EXECUTION AT " + new Date());
memChart = new ymageChart(width, height, "000010", 50, 20, 20, 20, "MEMORY CHART FROM EXECUTION AT " + new Date());
int timescale = 10; // steps with each 10 seconds
int memscale = 1024;
memChart.declareDimension(ImageChart.DIMENSION_BOTTOM, timescale, (width - 40) * timescale / expectedTimeSeconds, "FFFFFF", "555555", "SECONDS");
memChart.declareDimension(ImageChart.DIMENSION_LEFT, memscale, (height - 40) * memscale / expectedKilobytes , "FFFFFF", "555555", "KILOBYTES");
memChart.declareDimension(ymageChart.DIMENSION_BOTTOM, timescale, (width - 40) * timescale / expectedTimeSeconds, "FFFFFF", "555555", "SECONDS");
memChart.declareDimension(ymageChart.DIMENSION_LEFT, memscale, (height - 40) * memscale / expectedKilobytes , "FFFFFF", "555555", "KILOBYTES");
run = true;
start = System.currentTimeMillis();
}
@ -239,13 +240,13 @@ final class memprofiler extends Thread {
memChart.setColor("FF0000");
seconds1 = (int) ((System.currentTimeMillis() - start) / 1000);
kilobytes1 = (int) (serverMemory.used() / 1024);
memChart.chartLine(ImageChart.DIMENSION_BOTTOM, ImageChart.DIMENSION_LEFT, seconds0, kilobytes0, seconds1, kilobytes1);
memChart.chartLine(ymageChart.DIMENSION_BOTTOM, ymageChart.DIMENSION_LEFT, seconds0, kilobytes0, seconds1, kilobytes1);
seconds0 = seconds1;
kilobytes0 = kilobytes1;
try {Thread.sleep(100);} catch (InterruptedException e) {}
}
try {
memChart.toPNG(true, outputFile);
ymagePNGEncoderAWT.toPNG(memChart, true, outputFile);
} catch (IOException e) {}
}

@ -96,8 +96,7 @@ import java.util.Properties;
import java.util.logging.Level;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;
import java.awt.image.BufferedImage;
import javax.imageio.ImageIO;
import javax.imageio.ImageIO;
import de.anomic.plasma.plasmaSwitchboard;
import de.anomic.plasma.plasmaParser;
@ -110,7 +109,10 @@ import de.anomic.server.serverObjects;
import de.anomic.server.serverSwitch;
import de.anomic.server.logging.serverLog;
import de.anomic.data.userDB;
import de.anomic.ymage.ymagePainter;
import de.anomic.ymage.ymageMatrixPainter;
import de.anomic.ymage.ymagePNGEncoderAWT;
import de.anomic.ymage.ymagePNGEncoderJDE;
public final class httpdFileHandler extends httpdAbstractHandler implements httpdHandler {
@ -456,12 +458,12 @@ public final class httpdFileHandler extends httpdAbstractHandler implements http
if ((targetClass != null) && (path.endsWith("png"))) {
// call an image-servlet to produce an on-the-fly - generated image
BufferedImage bi = null;
ymagePainter yp = null;
try {
requestHeader.put("CLIENTIP", conProp.getProperty("CLIENTIP"));
requestHeader.put("PATH", path);
// in case that there are no args given, args = null or empty hashmap
bi = (BufferedImage) rewriteMethod(targetClass).invoke(null, new Object[] {requestHeader, args, switchboard});
yp = (ymagePainter) rewriteMethod(targetClass).invoke(null, new Object[] {requestHeader, args, switchboard});
} catch (InvocationTargetException e) {
this.theLogger.logSevere("INTERNAL ERROR: " + e.toString() + ":" +
e.getMessage() +
@ -471,7 +473,7 @@ public final class httpdFileHandler extends httpdAbstractHandler implements http
"; java.awt.graphicsenv='" + System.getProperty("java.awt.graphicsenv","") + "'",e);
targetClass = null;
}
if (bi == null) {
if (yp == null) {
// error with image generation; send file-not-found
httpd.sendRespondError(this.connectionProperties,out,3,404,"File not Found",null,null);
} else {
@ -481,7 +483,9 @@ public final class httpdFileHandler extends httpdAbstractHandler implements http
// generate an byte array from the generated image
serverByteBuffer baos = new serverByteBuffer();
ImageIO.write(bi, targetExt, baos);
//ymagePNGEncoderJDE jde = new ymagePNGEncoderJDE((ymageMatrixPainter) yp, ymagePNGEncoderJDE.FILTER_NONE, 0);
//byte[] result = jde.pngEncode();
ImageIO.write(ymagePNGEncoderAWT.toImage((ymageMatrixPainter) yp, true), targetExt, baos);
byte[] result = baos.toByteArray();
baos.close(); baos = null;

@ -45,12 +45,13 @@
package de.anomic.plasma;
import java.awt.image.BufferedImage;
import java.util.Iterator;
import java.util.Enumeration;
import java.util.Date;
import de.anomic.tools.ImagePainter;
import de.anomic.ymage.ymagePainter;
import de.anomic.ymage.ymageMatrix;
import de.anomic.ymage.ymageMatrixPainter;
import de.anomic.yacy.yacyCore;
import de.anomic.yacy.yacySeed;
@ -61,17 +62,17 @@ public class plasmaGrafics {
private static int shortestName = 10;
private static int longestName = 12;
private static ImagePainter networkPicture = null;
private static ymagePainter networkPicture = null;
private static long networkPictureDate = 0;
public static ImagePainter getSearchEventPicture() {
public static ymagePainter getSearchEventPicture() {
if (plasmaSearchEvent.lastEvent == null) return null;
yacySearch[] searches = plasmaSearchEvent.lastEvent.getSearchThreads();
if (searches == null) return null; // this was a local search and there are no threads
// get a copy of a recent network picture
ImagePainter eventPicture = (ImagePainter) getNetworkPicture(120000).clone();
ymagePainter eventPicture = (ymagePainter) getNetworkPicture(120000).clone();
// get dimensions
int cr = Math.min(eventPicture.getWidth(), eventPicture.getHeight()) / 5 - 20;
@ -83,7 +84,7 @@ public class plasmaGrafics {
// draw in the search peers
for (int j = 0; j < searches.length; j++) {
eventPicture.setColor((searches[j].isAlive()) ? ImagePainter.ADDITIVE_RED : ImagePainter.ADDITIVE_GREEN);
eventPicture.setColor((searches[j].isAlive()) ? ymageMatrix.ADDITIVE_RED : ymageMatrix.ADDITIVE_GREEN);
hash = searches[j].target().hash;
angle = (int) ((long) 360 * (yacySeed.dhtPosition(hash) / (yacySeed.maxDHTDistance / (long) 10000)) / (long) 10000);
eventPicture.arcLine(cx, cy, cr - 20, cr, angle);
@ -92,8 +93,8 @@ public class plasmaGrafics {
// draw in the search target
plasmaSearchQuery query = plasmaSearchEvent.lastEvent.getQuery();
Iterator i = query.queryHashes.iterator();
eventPicture.setMode(ImagePainter.MODE_ADD);
eventPicture.setColor(ImagePainter.ADDITIVE_BLACK);
eventPicture.setMode(ymageMatrix.MODE_ADD);
eventPicture.setColor(ymageMatrix.ADDITIVE_BLACK);
while (i.hasNext()) {
hash = (String) i.next();
angle = (int) ((long) 360 * (yacySeed.dhtPosition(hash) / (yacySeed.maxDHTDistance / (long) 10000)) / (long) 10000);
@ -103,11 +104,11 @@ public class plasmaGrafics {
return eventPicture;
}
public static ImagePainter getNetworkPicture(long maxAge) {
public static ymagePainter getNetworkPicture(long maxAge) {
return getNetworkPicture(maxAge, 640, 480, 300, 300, 1000);
}
public static ImagePainter getNetworkPicture(long maxAge, int width, int height, int passiveLimit, int potentialLimit, int maxCount) {
public static ymagePainter getNetworkPicture(long maxAge, int width, int height, int passiveLimit, int potentialLimit, int maxCount) {
if ((networkPicture == null) || ((System.currentTimeMillis() - networkPictureDate) > maxAge)) {
drawNetworkPicture(width, height, passiveLimit, potentialLimit, maxCount);
}
@ -122,8 +123,8 @@ public class plasmaGrafics {
if (yacyCore.seedDB == null) return; // no other peers known
networkPicture = new ImagePainter(width, height, "000010");
networkPicture.setMode(ImagePainter.MODE_ADD);
networkPicture = new ymageMatrixPainter(width, height, "000010");
networkPicture.setMode(ymageMatrix.MODE_ADD);
// draw network circle
networkPicture.setColor("008020");
@ -182,7 +183,7 @@ public class plasmaGrafics {
// draw description
networkPicture.setColor("FFFFFF");
networkPicture.setMode(ImagePainter.MODE_ADD);
networkPicture.setMode(ymageMatrix.MODE_ADD);
networkPicture.print(2, 8, 0, "THE YACY NETWORK", true);
networkPicture.print(2, 16, 0, "DRAWING OF " + totalCount + " SELECTED PEERS", true);
networkPicture.print(width - 2, 8, 0, "SNAPSHOT FROM " + new Date().toString().toUpperCase(), false);
@ -191,7 +192,7 @@ public class plasmaGrafics {
networkPictureDate = System.currentTimeMillis();
}
private static void drawNetworkPicturePeer(ImagePainter img, int x, int y, int innerradius, int outerradius, yacySeed seed, String colorDot, String colorLine, String colorText) {
private static void drawNetworkPicturePeer(ymagePainter img, int x, int y, int innerradius, int outerradius, yacySeed seed, String colorDot, String colorLine, String colorText) {
String name = seed.getName().toUpperCase();
if (name.length() < shortestName) shortestName = name.length();
if (name.length() > longestName) longestName = name.length();
@ -201,7 +202,7 @@ public class plasmaGrafics {
if (linelength > outerradius) linelength = outerradius;
int dotsize = 6 + 2 * (int) (seed.getLinkCount() / 500000L);
if (dotsize > 18) dotsize = 18;
img.setMode(ImagePainter.MODE_ADD);
img.setMode(ymageMatrix.MODE_ADD);
// draw dot
img.setColor(colorDot);
img.arcDot(x, y, innerradius, angle, dotsize);
@ -217,7 +218,7 @@ public class plasmaGrafics {
if (ppm10 > 3) ppm10 = 3;
// draw a wave around crawling peers
long strength;
img.setMode(ImagePainter.MODE_SUB);
img.setMode(ymageMatrix.MODE_SUB);
img.setColor("303030");
img.arcArc(x, y, innerradius, angle, dotsize + 1, dotsize + 1, 0, 360);
int waveradius = innerradius / 2;

@ -143,5 +143,21 @@ public class plasmaURL {
public Iterator urlHashes(String urlHash, boolean up) throws IOException {
return urlHashCache.rows(up, false, urlHash.getBytes());
}
/* TLDs:
AC, AD, AE, AERO, AF, AG, AI, AL, AM, AN, AO, AQ, AR, ARPA, AS, AT, AU, AW, AZ,
BA, BB, BD, BE, BF, BG, BH, BI, BIZ, BJ, BM, BN, BO, BR, BS, BT, BV, BW, BY, BZ,
CA, CC, CD, CF, CG, CH, CI, CK, CL, CM, CN, CO, COM, COOP, CR, CU, CV, CX, CY, CZ,
DE, DJ, DK, DM, DO, DZ, EC, EDU, EE, EG, ER, ES, ET, EU, FI, FJ, FK, FM, FO, FR,
GA, GB, GD, GE, GF, GG, GH, GI, GL, GM, GN, GOV, GP, GQ, GR, GS, GT, GU, GW, GY,
HK, HM, HN, HR, HT, HU, ID, IE, IL, IM, IN, INFO, INT, IO, IQ, IR, IS, IT,
JE, JM, JO, JOBS, JP, KE, KG, KH, KI, KM, KN, KR, KW, KY, KZ,
LA, LB, LC, LI, LK, LR, LS, LT, LU, LV, LY,
MA, MC, MD, MG, MH, MIL, MK, ML, MM, MN, MO, MOBI, MP, MQ, MR, MS, MT, MU, MUSEUM, MV, MW, MX, MY, MZ,
NA, NAME, NC, NE, NET, NF, NG, NI, NL, NO, NP, NR, NU, NZ, OM, ORG,
PA, PE, PF, PG, PH, PK, PL, PM, PN, PR, PRO, PS, PT, PW, PY, QA, RE, RO, RU, RW,
SA, SB, SC, SD, SE, SG, SH, SI, SJ, SK, SL, SM, SN, SO, SR, ST, SU, SV, SY, SZ,
TC, TD, TF, TG, TH, TJ, TK, TL, TM, TN, TO, TP, TR, TRAVEL, TT, TV, TW, TZ,
UA, UG, UK, UM, US, UY, UZ, VA, VC, VE, VG, VI, VN, VU, WF, WS, YE, YT, YU, ZA, ZM, ZW
*/
}

@ -263,7 +263,12 @@ public class yacySeed {
public long getUTCDiff() {
String utc = (String) this.dna.get(UTC);
if (utc == null) { utc = "+0200"; }
return serverDate.UTCDiff(utc);
try {
return serverDate.UTCDiff(utc);
} catch (RuntimeException e) {
return 0;
}
}
public long getLastSeenTime() {

@ -1,4 +1,4 @@
// ImageChart.java
// ymageChart.java
// ---------------------------
// (C) by Michael Peter Christen; mc@anomic.de
// first published on http://www.anomic.de
@ -39,12 +39,12 @@
// Contributions and changes to the program code must be marked as such.
package de.anomic.tools;
package de.anomic.ymage;
import java.io.File;
import java.io.IOException;
public class ImageChart extends ImagePainter {
public class ymageChart extends ymageMatrixPainter {
public static final int DIMENSION_RIGHT = 0;
public static final int DIMENSION_TOP = 1;
@ -61,7 +61,7 @@ public class ImageChart extends ImagePainter {
String[] colscale = new String[]{null,null,null,null};
String[] tablenames = new String[]{"","","",""};
public ImageChart(int width, int height, String backgroundColor,
public ymageChart(int width, int height, String backgroundColor,
int leftborder, int rightborder, int topborder, int bottomborder,
String name) {
super(width, height, backgroundColor);
@ -149,7 +149,7 @@ public class ImageChart extends ImagePainter {
public static void main(String[] args) {
System.setProperty("java.awt.headless", "true");
ImageChart ip = new ImageChart(640, 480, "000010", 40, 40, 20, 20, "TESTCHART");
ymageChart ip = new ymageChart(640, 480, "000010", 40, 40, 20, 20, "TESTCHART");
ip.declareDimension(DIMENSION_BOTTOM, 10, 30, "FFFFFF", "555555", "time");
ip.declareDimension(DIMENSION_TOP, 10, 40, "FFFFFF", null, "count");
ip.declareDimension(DIMENSION_LEFT, 100, 30, "FFFFFF", "555555", "money");
@ -161,9 +161,11 @@ public class ImageChart extends ImagePainter {
//ip.print(100, 100, 0, "1234", false);
//ip.print(100, 100, 90, "TEXT", true);
//ip.print(100, 100, 90, "1234", false);
/*
try {
ip.toPNG(true, new File("/Users/admin/dev/yacy/trunk/testimage.png"));
} catch (IOException e) {}
*/
}
}

@ -0,0 +1,573 @@
// ymageFontGenerator.java
// ---------------------------
// (C) by Michael Peter Christen; mc@anomic.de
// first published on http://www.anomic.de
// Frankfurt, Germany, 2005
// created: 31.10.2005
//
// This program 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 program 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.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
// Using this software in any meaning (reading, learning, copying, compiling,
// running) means that you agree that the Author(s) is (are) not responsible
// for cost, loss of data or any harm that may be caused directly or indirectly
// by usage of this softare or this documentation. The usage of this software
// is on your own risk. The installation and usage (starting/running) of this
// software may allow other people or application to access your computer and
// any attached devices and is highly dependent on the configuration of the
// software which must be done by the user of the software; the author(s) is
// (are) also not responsible for proper configuration and usage of the
// software, even if provoked by documentation provided together with
// the software.
//
// Any changes to this file according to the GPL as documented in the file
// gpl.txt aside this file in the shipment you received can be done to the
// lines that follows this copyright notice here, but changes must not be
// done inside the copyright notive above. A re-distribution must contain
// the intact and unchanged copyright notice.
// Contributions and changes to the program code must be marked as such.
package de.anomic.ymage;
public class ymageFontGenerator {
/*
?0x20: !"#$%&'
0x28:()*+,-./
0x30:01234567
0x38:89:;<=>?
0x40:@ABCDEFG
0x48:HIJKLMNO
0x50:PQRSTUVW
0x58:XYZ[\]^_
0x60:`abcdefg
0x68:hijklmno
0x70:pqrstuvw
0x78:xyz{|}~
*/
public static final String[][] font =
{
{".....", //0x20
".....",
".....",
".....",
"....."},
{"..X..",
"..X..",
"..X..",
".....",
"..X.."},
{".X.X.",
".X.X.",
".....",
".....",
"....."},
{".X.X.",
"XXXXX",
".X.X.",
"XXXXX",
".X.X."},
{".XXXX",
"X.X..",
".XXX.",
"..X.X",
"XXXX."},
{".X..X",
"X.XX.",
".XXX.",
".XX.X",
"X..X."},
{".XXX.",
"X....",
".X.X.",
"X.X..",
".X.X."},
{"..X..",
"..X..",
".....",
".....",
"....."},
{"...X.", //0x28
"..X..",
"..X..",
"..X..",
"...X."},
{".X...",
"..X..",
"..X..",
"..X..",
".x..."},
{".....",
".X.X.",
"xxXxx",
".x.X.",
"....."},
{".....",
"..X..",
".XXX.",
"..X..",
"....."},
{".....",
".....",
"..X..",
"..X..",
".X..."},
{".....",
".....",
".XXX.",
".....",
"....."},
{".....",
".....",
".....",
".....",
"..X.."},
{"....X",
"...X.",
"..X..",
".X...",
"X...."},
{".XXX.", //0x30
"X..XX",
"X.X.X",
"XX..X",
".XXX."},
{"..X..",
".XX..",
"..X..",
"..X..",
".XXX."},
{".XXX.",
"X...X",
"..XX.",
".X...",
"XXXXX"},
{".XXX.",
"X...X",
"...X.",
"X...X",
".XXX."},
{"..XX.",
".X.X.",
"XXXXX",
"...X.",
"...X."},
{"XXXXX",
"X....",
"XXXX.",
"....X",
"XXXX."},
{".XXX.",
"X....",
"XXXX.",
"X...X",
".XXX."},
{"XXXXX",
"...X.",
"..X..",
"..X..",
"..X.."},
{".XXX.", //0x38
"X...X",
".XXX.",
"X...X",
".XXX."},
{".XXX.",
"X...X",
".XXXX",
"....X",
".XXX."},
{".....",
"..X..",
".....",
"..X..",
"....."},
{".....",
"..X..",
".....",
"..X..",
".X..."},
{"...X.",
"..X..",
".X...",
"..X..",
"...X."},
{".....",
"XXXXX",
".....",
"XXXXX",
"....."},
{".X...",
"..X..",
"...X.",
"..X..",
".X..."},
{".XXX.",
"...X.",
"..X..",
".....",
"..X.."},
{".XXX.", //0x40
"XXX.X",
"XXXX.",
"X....",
".XXX."},
{"..X..",
".X.X.",
"X...X",
"XXXXX",
"X...X"},
{"XXX..",
"X..X.",
"XXXX.",
"X...X",
"XXXX."},
{".XXX.",
"X....",
"X....",
"X....",
".XXX."},
{"XXXX.",
"X...X",
"X...X",
"X...X",
"XXXX."},
{"XXXXX",
"X....",
"XXX..",
"X....",
"XXXXX"},
{"XXXXX",
"X....",
"XXX..",
"X....",
"X...."},
{".XXX.",
"X....",
"X.XXX",
"X...X",
".XXX."},
{"X...X", //0x48
"X...X",
"XXXXX",
"X...X",
"X...X"},
{"XXXXX",
"..X..",
"..X..",
"..X..",
"XXXXX"},
{"XXXXX",
"....X",
"....X",
"X...X",
".XXX."},
{"X...X",
"X..X.",
"XXX..",
"X..X..",
"X...X"},
{"X....",
"X....",
"X....",
"X....",
"XXXXX"},
{"X...X",
"XX.XX",
"X.X.X",
"X...X",
"X...X"},
{"X...X",
"XX..X",
"X.X.X",
"X..XX",
"X...X"},
{".XXX.",
"X...X",
"X...X",
"X...X",
".XXX."},
{"XXXX.", //0x50
"X...X",
"XXXX.",
"X....",
"X...."},
{".XXX.",
"X...X",
"X.X.X",
"X..X.",
".XX.X"},
{"XXXX.",
"X...X",
"XXXX.",
"X..X.",
"X...X"},
{".XXX.",
"X....",
".XXX.",
"....X",
".XXX."},
{"XXXXX",
"..X..",
"..X..",
"..X..",
"..X.."},
{"X...X",
"X...X",
"X...X",
"X...X",
".XXX."},
{"X...X",
"X...X",
"X...X",
".X.X.",
"..X.."},
{"X...X",
"X...X",
"X...X",
"X.X.X",
".X.X."},
{"X...X", //0x58
".X.X.",
"..X..",
".X.X.",
"X...X"},
{"X...X",
".X.X.",
"..X..",
"..X..",
"..X.."},
{"XXXXX",
"...X.",
"..X..",
".X...",
"XXXXX"},
{".XXX.",
".X...",
".X...",
".X...",
".XXX."},
{"X....",
".X...",
"..X..",
"...X.",
"....X"},
{".XXX.",
"...X.",
"...X.",
"...X.",
".XXX."},
{"..X..",
".X.X.",
"X...X",
".....",
"....."},
{".....",
".....",
".....",
".....",
"XXXXX"},
{".X...", //0x60
"..X..",
".....",
".....",
"....."},
{".....",
".....",
".XXXX",
"X...X",
".XXXX"},
{"X....",
"X....",
"XXXX.",
"X...X",
"XXXX."},
{".....",
".....",
".XXXX",
"X....",
".XXXX"},
{"....X",
"....X",
".XXXX",
"X...X",
".XXXX"},
{".....",
".XX..",
"X..X.",
"X.X..",
".XXXX"},
{"..XX.",
"..X..",
".XXX.",
"..X..",
"..X.."},
{".....",
"..XX.",
".X..X",
"..X.X",
"XXXX."},
{"X....", //0x68
"X....",
"X.XX.",
"XX..X",
"X...X"},
{"..X..",
".....",
"..X..",
"..X..",
"..X.."},
{"..X..",
".....",
"..X..",
"..X..",
".X..."},
{"X....",
"X....",
"X..XX",
"XXX..",
"X..XX"},
{"..X..",
"..X..",
"..X..",
"..X..",
"..X.."},
{".....",
".....",
".X.X.",
"X.X.X",
"X.X.X"},
{".....",
".....",
".XXX.",
"X...X",
"X...X"},
{".....",
".....",
".XXX.",
"X...X",
".XXX."},
{".....", //0x70
"XXXX.",
"X...X",
"XXXX.",
"X...."},
{".....",
".XXXX",
"X...X",
".XXXX",
"....X"},
{".....",
"...X.",
"..X..",
"..X..",
"..X.."},
{".....",
".....",
"..XX.",
".X..X",
"X..X."},
{"..X..",
".XXX.",
"..X..",
"..X..",
"..X.."},
{".....",
".....",
"X...X",
"X...X",
".XXX."},
{".....",
".....",
"X...X",
".X.X.",
"..X.."},
{".....",
".....",
"X.X.X",
"X.X.X",
".X.X."},
{".....", //0x78
".....",
".X.X.",
"..X..",
".X.X."},
{".....",
".....",
".X.X.",
"..X..",
"..X.."},
{".....",
".....",
".XXXX",
"..X..",
"XXXX."},
{"..XX.",
"..X..",
".X...",
"..X..",
"..XX."},
{"..X..",
"..X..",
"..X..",
"..X..",
"..X.."},
{".XX..",
"..X..",
"...X.",
"..X..",
".XX.."},
{".....",
".X...",
"X.X.X",
"...X.",
"....."},
{"XXXXX",
"X...X",
"X...X",
"X...X",
"XXXXX"},
};
public static void main(String[] args) {
String[] letter;
int b;
int v;
int c = 0;
String s;
for (int i = 0; i < font.length; i++) {
letter = font[i];
b = 0;
for (int j = 0; j < 5; j++) {
b = b << 5;
v = 16;
for (int col = 0; col < 5; col++) {
if (letter[j].charAt(col) == 'X') b += v;
v = v >> 1;
}
}
s = Long.toHexString(b).toUpperCase();
while (s.length() < 7) s = "0" + s;
System.out.print("0x" + s + ",");
c++;
if (c >= 8) {
System.out.println();
c = 0;
}
}
}
}

@ -0,0 +1,228 @@
// ymageMatrix.java
// ---------------------------
// (C) by Michael Peter Christen; mc@anomic.de
// first published on http://www.anomic.de
// Frankfurt, Germany, 2005
// last major change: 16.09.2005
//
// This program 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 program 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.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
// Using this software in any meaning (reading, learning, copying, compiling,
// running) means that you agree that the Author(s) is (are) not responsible
// for cost, loss of data or any harm that may be caused directly or indirectly
// by usage of this softare or this documentation. The usage of this software
// is on your own risk. The installation and usage (starting/running) of this
// software may allow other people or application to access your computer and
// any attached devices and is highly dependent on the configuration of the
// software which must be done by the user of the software; the author(s) is
// (are) also not responsible for proper configuration and usage of the
// software, even if provoked by documentation provided together with
// the software.
//
// Any changes to this file according to the GPL as documented in the file
// gpl.txt aside this file in the shipment you received can be done to the
// lines that follows this copyright notice here, but changes must not be
// done inside the copyright notive above. A re-distribution must contain
// the intact and unchanged copyright notice.
// Contributions and changes to the program code must be marked as such.
/*
This Class implements some convenience-methods to support drawing of statistical Data
It is not intended to replace existing awt-funktions even if it looks so
This class provides some drawing methods that creates transparency effects that
are not available in awt.
*/
package de.anomic.ymage;
public class ymageMatrix implements Cloneable {
// colors regarding RGB Color Model
public static final long ADDITIVE_RED = 0xFF0000;
public static final long ADDITIVE_GREEN = 0x00FF00;
public static final long ADDITIVE_BLUE = 0x0000FF;
public static final long ADDITIVE_BLACK = 0xFFFFFF;
// colors regarding CMY Color Model
public static final long SUBTRACTIVE_CYAN = 0xFF0000;
public static final long SUBTRACTIVE_MAGENTA = 0x00FF00;
public static final long SUBTRACTIVE_YELLOW = 0x0000FF;
public static final long SUBTRACTIVE_WHITE = 0xFFFFFF;
public static final byte MODE_REPLACE = 0;
public static final byte MODE_ADD = 1;
public static final byte MODE_SUB = 2;
protected int width, height;
private byte[] grid; // one-dimensional arrays are much faster than two-dimensional
private int defaultColR, defaultColG, defaultColB;
private byte defaultMode;
private boolean grabComplementary = false;
public ymageMatrix(int width, int height, String backgroundColor) {
this(width, height, colNum(backgroundColor));
}
public ymageMatrix(int width, int height, long backgroundColor) {
this.width = width;
this.height = height;
this.defaultColR = 0xFF;
this.defaultColG = 0xFF;
this.defaultColB = 0xFF;
this.defaultMode = MODE_REPLACE;
grid = new byte[3*width*height];
// fill grid with background color
byte bgR = (byte) (backgroundColor >> 16);
byte bgG = (byte) ((backgroundColor >> 8) & 0xff);
byte bgB = (byte) (backgroundColor & 0xff);
for (int n = 3 * width * height - 3; n >= 0; n = n - 3) {
grid[n ] = bgR;
grid[n + 1] = bgG;
grid[n + 2] = bgB;
}
}
private static long colNum(String col) {
return Long.parseLong(col, 16);
//return Integer.parseInt(col.substring(0,2), 16) << 16 | Integer.parseInt(col.substring(2,4), 16) << 8 | Integer.parseInt(col.substring(4,6), 16);
}
private static String colStr(long c) {
String s = Long.toHexString(c);
while (s.length() < 6) s = "0" + s;
return s;
}
public Object clone() {
ymageMatrix ip = new ymageMatrix(this.width, this.height, 0);
System.arraycopy(this.grid, 0, ip.grid, 0, this.grid.length);
ip.defaultColR = this.defaultColR;
ip.defaultColG = this.defaultColG;
ip.defaultColB = this.defaultColB;
ip.defaultMode = this.defaultMode;
return ip;
}
public int getWidth() {
return width;
}
public int getHeight() {
return height;
}
public void setColor(long c) {
defaultColR = (int) (c >> 16);
defaultColG = (int) ((c >> 8) & 0xff);
defaultColB = (int) (c & 0xff);
}
public void setColor(String s) {
setColor(colNum(s));
}
public void setMode(byte m) {
this.defaultMode = m;
}
public void plot(int x, int y) {
if ((x < 0) || (x >= width)) return;
if ((y < 0) || (y >= height)) return;
int n = 3 * (x + y * width);
if (this.defaultMode == MODE_REPLACE) {
grid[n ] = (byte) defaultColR;
grid[n + 1] = (byte) defaultColG;
grid[n + 2] = (byte) defaultColB;
} else if (this.defaultMode == MODE_ADD) {
int r = ((int) (0xff & grid[n ])) + defaultColR; if (r > 0xff) r = 0xff;
int g = ((int) (0xff & grid[n + 1])) + defaultColG; if (g > 0xff) g = 0xff;
int b = ((int) (0xff & grid[n + 2])) + defaultColB; if (b > 0xff) b = 0xff;
grid[n ] = (byte) r;
grid[n + 1] = (byte) g;
grid[n + 2] = (byte) b;
} else if (this.defaultMode == MODE_SUB) {
int r = ((int) (0xff & grid[n ])) - defaultColR; if (r < 0) r = 0;
int g = ((int) (0xff & grid[n + 1])) - defaultColG; if (g < 0) g = 0;
int b = ((int) (0xff & grid[n + 2])) - defaultColB; if (b < 0) b = 0;
grid[n ] = (byte) r;
grid[n + 1] = (byte) g;
grid[n + 2] = (byte) b;
}
}
public void line(int Ax, int Ay, int Bx, int By) {
// Bresenham's line drawing algorithm
int dX = Math.abs(Bx-Ax);
int dY = Math.abs(By-Ay);
int Xincr, Yincr;
if (Ax > Bx) Xincr=-1; else Xincr=1;
if (Ay > By) Yincr=-1; else Yincr=1;
if (dX >= dY) {
int dPr = dY<<1;
int dPru = dPr - (dX<<1);
int P = dPr - dX;
for (; dX>=0; dX--) {
plot(Ax, Ay);
if (P > 0) {
Ax+=Xincr;
Ay+=Yincr;
P+=dPru;
} else {
Ax+=Xincr;
P+=dPr;
}
}
} else {
int dPr = dX<<1;
int dPru = dPr - (dY<<1);
int P = dPr - dY;
for (; dY>=0; dY--) {
plot(Ax, Ay);
if (P > 0) {
Ax+=Xincr;
Ay+=Yincr;
P+=dPru;
} else {
Ay+=Yincr;
P+=dPr;
}
}
}
}
public void getColorMode(boolean grabComplementary) {
this.grabComplementary = grabComplementary;
}
public int[] getColor(int x, int y) {
int n = 3 * (x + y * width);
if (grabComplementary) {
int r = 0xff & grid[n ];
int g = 0xff & grid[n + 1];
int b = 0xff & grid[n + 2];
return new int[]{(0x1fe - g - b) / 2, (0x1fe - r - b) / 2, (0x1fe - r - g) / 2};
} else {
int r = 0xff & grid[n ];
int g = 0xff & grid[n + 1];
int b = 0xff & grid[n + 2];
return new int[]{r, g, b};
}
}
}

@ -1,494 +1,258 @@
// ImagePainter.java
// ---------------------------
// (C) by Michael Peter Christen; mc@anomic.de
// first published on http://www.anomic.de
// Frankfurt, Germany, 2005
// last major change: 16.09.2005
//
// This program 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 program 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.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
// Using this software in any meaning (reading, learning, copying, compiling,
// running) means that you agree that the Author(s) is (are) not responsible
// for cost, loss of data or any harm that may be caused directly or indirectly
// by usage of this softare or this documentation. The usage of this software
// is on your own risk. The installation and usage (starting/running) of this
// software may allow other people or application to access your computer and
// any attached devices and is highly dependent on the configuration of the
// software which must be done by the user of the software; the author(s) is
// (are) also not responsible for proper configuration and usage of the
// software, even if provoked by documentation provided together with
// the software.
//
// Any changes to this file according to the GPL as documented in the file
// gpl.txt aside this file in the shipment you received can be done to the
// lines that follows this copyright notice here, but changes must not be
// done inside the copyright notive above. A re-distribution must contain
// the intact and unchanged copyright notice.
// Contributions and changes to the program code must be marked as such.
/*
This Class implements some convenience-methods to support drawing of statistical Data
It is not intended to replace existing awt-funktions even if it looks so
This class provides some drawing methods that creates transparency effects that
are not available in awt.
*/
package de.anomic.tools;
import java.io.File;
import java.awt.Graphics2D;
import java.awt.GraphicsEnvironment;
import java.awt.GraphicsDevice;
import java.awt.GraphicsConfiguration;
import java.awt.Transparency;
import java.awt.Color;
import java.awt.image.BufferedImage;
import java.awt.image.WritableRaster;
import java.util.HashSet;
import java.util.ArrayList;
import javax.imageio.ImageIO;
import java.io.IOException;
public class ImagePainter implements Cloneable {
// colors regarding RGB Color Model
public static final long ADDITIVE_RED = 0xFF0000;
public static final long ADDITIVE_GREEN = 0x00FF00;
public static final long ADDITIVE_BLUE = 0x0000FF;
public static final long ADDITIVE_BLACK = 0xFFFFFF;
// colors regarding CMY Color Model
public static final long SUBTRACTIVE_CYAN = 0xFF0000;
public static final long SUBTRACTIVE_MAGENTA = 0x00FF00;
public static final long SUBTRACTIVE_YELLOW = 0x0000FF;
public static final long SUBTRACTIVE_WHITE = 0xFFFFFF;
public static final byte MODE_REPLACE = 0;
public static final byte MODE_ADD = 1;
public static final byte MODE_SUB = 2;
private static long[] font = new long[]{
0x0000000,0x0421004,0x0A50000,0x0AFABEA,0x0FA38BE,0x09B39B2,0x0E82A8A,0x0420000,
0x0221082,0x0821080,0x0051040,0x0023880,0x0001088,0x0003800,0x0000004,0x0111110,
0x0E9D72E,0x046108E,0x0E8991F,0x0E88A2E,0x0657C42,0x1F8783E,0x0E87A2E,0x1F11084,
0x0E8BA2E,0x0E8BC2E,0x0020080,0x0020088,0x0222082,0x00F83E0,0x0820888,0x0E11004,
0x0EEFA0E,0x04547F1,0x1C97A3E,0x0E8420E,0x1E8C63E,0x1F8721F,0x1F87210,0x0E85E2E,
0x118FE31,0x1F2109F,0x1F0862E,0x1197251,0x108421F,0x11DD631,0x11CD671,0x0E8C62E,
0x1E8FA10,0x0E8D64D,0x1E8FA51,0x0E8382E,0x1F21084,0x118C62E,0x118C544,0x118C6AA,
0x1151151,0x1151084,0x1F1111F,0x0E4210E,0x1041041,0x0E1084E,0x0454400,0x000001F,
0x0820000,0x0003E2F,0x1087A3E,0x0003E0F,0x010BE2F,0x0064A8F,0x0623884,0x00324BE,
0x1085B31,0x0401084,0x0401088,0x1084F93,0x0421084,0x0002AB5,0x0003A31,0x0003A2E,
0x00F47D0,0x007C5E1,0x0011084,0x0001932,0x0471084,0x000462E,0x0004544,0x00056AA,
0x000288A,0x0002884,0x0003C9E,0x0622086,0x0421084,0x0C2088C,0x0045440,0x1F8C63F
};
private static int[][] circles = new int[0][];
protected int width, height;
private byte[] grid; // one-dimensional arrays are much faster than two-dimensional
private int defaultColR, defaultColG, defaultColB;
private byte defaultMode;
public ImagePainter(int width, int height, String backgroundColor) {
this(width, height, colNum(backgroundColor));
}
public ImagePainter(int width, int height, long backgroundColor) {
this.width = width;
this.height = height;
this.defaultColR = 0xFF;
this.defaultColG = 0xFF;
this.defaultColB = 0xFF;
this.defaultMode = MODE_REPLACE;
grid = new byte[3*width*height];
// fill grid with background color
byte bgR = (byte) (backgroundColor >> 16);
byte bgG = (byte) ((backgroundColor >> 8) & 0xff);
byte bgB = (byte) (backgroundColor & 0xff);
for (int n = 3 * width * height - 3; n >= 0; n = n - 3) {
grid[n ] = bgR;
grid[n + 1] = bgG;
grid[n + 2] = bgB;
}
}
private static long colNum(String col) {
return Long.parseLong(col, 16);
//return Integer.parseInt(col.substring(0,2), 16) << 16 | Integer.parseInt(col.substring(2,4), 16) << 8 | Integer.parseInt(col.substring(4,6), 16);
}
private static String colStr(long c) {
String s = Long.toHexString(c);
while (s.length() < 6) s = "0" + s;
return s;
}
public Object clone() {
ImagePainter ip = new ImagePainter(this.width, this.height, 0);
System.arraycopy(this.grid, 0, ip.grid, 0, this.grid.length);
ip.defaultColR = this.defaultColR;
ip.defaultColG = this.defaultColG;
ip.defaultColB = this.defaultColB;
ip.defaultMode = this.defaultMode;
return ip;
}
public int getWidth() {
return width;
}
public int getHeight() {
return height;
}
public void setColor(long c) {
defaultColR = (int) (c >> 16);
defaultColG = (int) ((c >> 8) & 0xff);
defaultColB = (int) (c & 0xff);
}
public void setColor(String s) {
setColor(colNum(s));
}
public void setMode(byte m) {
this.defaultMode = m;
}
protected void plot(int x, int y) {
if ((x < 0) || (x >= width)) return;
if ((y < 0) || (y >= height)) return;
int n = 3 * (x + y * width);
if (this.defaultMode == MODE_REPLACE) {
grid[n ] = (byte) defaultColR;
grid[n + 1] = (byte) defaultColG;
grid[n + 2] = (byte) defaultColB;
} else if (this.defaultMode == MODE_ADD) {
int r = ((int) (0xff & grid[n ])) + defaultColR; if (r > 0xff) r = 0xff;
int g = ((int) (0xff & grid[n + 1])) + defaultColG; if (g > 0xff) g = 0xff;
int b = ((int) (0xff & grid[n + 2])) + defaultColB; if (b > 0xff) b = 0xff;
grid[n ] = (byte) r;
grid[n + 1] = (byte) g;
grid[n + 2] = (byte) b;
} else if (this.defaultMode == MODE_SUB) {
int r = ((int) (0xff & grid[n ])) - defaultColR; if (r < 0) r = 0;
int g = ((int) (0xff & grid[n + 1])) - defaultColG; if (g < 0) g = 0;
int b = ((int) (0xff & grid[n + 2])) - defaultColB; if (b < 0) b = 0;
grid[n ] = (byte) r;
grid[n + 1] = (byte) g;
grid[n + 2] = (byte) b;
}
}
protected void line(int Ax, int Ay, int Bx, int By) {
// Bresenham's line drawing algorithm
int dX = Math.abs(Bx-Ax);
int dY = Math.abs(By-Ay);
int Xincr, Yincr;
if (Ax > Bx) Xincr=-1; else Xincr=1;
if (Ay > By) Yincr=-1; else Yincr=1;
if (dX >= dY) {
int dPr = dY<<1;
int dPru = dPr - (dX<<1);
int P = dPr - dX;
for (; dX>=0; dX--) {
plot(Ax, Ay);
if (P > 0) {
Ax+=Xincr;
Ay+=Yincr;
P+=dPru;
} else {
Ax+=Xincr;
P+=dPr;
}
}
} else {
int dPr = dX<<1;
int dPru = dPr - (dY<<1);
int P = dPr - dY;
for (; dY>=0; dY--) {
plot(Ax, Ay);
if (P > 0) {
Ax+=Xincr;
Ay+=Yincr;
P+=dPru;
} else {
Ay+=Yincr;
P+=dPr;
}
}
}
}
private static int[] getCircleCoords(int radius) {
if ((radius - 1) < circles.length) return circles[radius - 1];
// read some lines from known circles
HashSet crds = new HashSet();
crds.add("0|0");
String co;
for (int i = Math.max(0, circles.length - 5); i < circles.length; i++) {
for (int j = 0; j < circles[i].length; j = j + 2) {
co = circles[i][j] + "|" + circles[i][j + 1];
if (!(crds.contains(co))) crds.add(co);
}
}
// copy old circles into new array
int[][] newCircles = new int[radius + 30][];
System.arraycopy(circles, 0, newCircles, 0, circles.length);
// compute more lines in new circles
int x, y;
ArrayList crc;
for (int r = circles.length; r < newCircles.length; r++) {
crc = new ArrayList();
for (int a = 0; a <= 2 * (r + 1); a++) {
x = (int) ((r + 1) * Math.cos(Math.PI * a / (4 * (r + 1))));
y = (int) ((r + 1) * Math.sin(Math.PI * a / (4 * (r + 1))));
co = x + "|" + y;
if (!(crds.contains(co))) {
crc.add(new int[]{x, y});
crds.add(co);
}
x = (int) ((r + 0.5) * Math.cos(Math.PI * a / (4 * (r + 1))));
y = (int) ((r + 0.5) * Math.sin(Math.PI * a / (4 * (r + 1))));
co = x + "|" + y;
if (!(crds.contains(co))) {
crc.add(new int[]{x, y});
crds.add(co);
}
}
// put coordinates into array
//System.out.print("Radius " + r + " => " + crc.size() + " points: ");
newCircles[r] = new int[2 * (crc.size() - 1)];
int[] coords;
for (int i = 0; i < crc.size() - 1; i++) {
coords = (int[]) crc.get(i);
newCircles[r][2 * i ] = coords[0];
newCircles[r][2 * i + 1] = coords[1];
//System.out.print(circles[r][i][0] + "," +circles[r][i][1] + "; ");
}
//System.out.println();
}
crc = null;
crds = null;
// move newCircles to circles array
circles = newCircles;
newCircles = null;
// finally return wanted slice
return circles[radius - 1];
}
private void circle(int xc, int yc, int radius) {
if (radius == 0) {
plot(xc, yc);
} else {
int[] c = getCircleCoords(radius);
int x, y;
for (int i = (c.length / 2) - 1; i >= 0; i--) {
x = c[2 * i ];
y = c[2 * i + 1];
plot(xc + x , yc - y - 1); // quadrant 1
plot(xc - x + 1, yc - y - 1); // quadrant 2
plot(xc + x , yc + y ); // quadrant 4
plot(xc - x + 1, yc + y ); // quadrant 3
}
}
}
private void circle(int xc, int yc, int radius, int fromArc, int toArc) {
// draws only a part of a circle
// arc is given in degree
if (radius == 0) {
plot(xc, yc);
} else {
int[] c = getCircleCoords(radius);
int q = c.length / 2;
int[][] c4 = new int[q * 4][];
for (int i = 0; i < q; i++) {
c4[i ] = new int[]{ c[2 * (i )], -c[2 * (i ) + 1] - 1}; // quadrant 1
c4[i + q] = new int[]{1 - c[2 * (q - 1 - i)], -c[2 * (q - 1 - i) + 1] - 1}; // quadrant 2
c4[i + 2 * q] = new int[]{1 - c[2 * (i )], c[2 * (i ) + 1] }; // quadrant 3
c4[i + 3 * q] = new int[]{ c[2 * (q - 1 - i)], c[2 * (q - 1 - i) + 1] }; // quadrant 4
}
for (int i = q * 4 * fromArc / 360; i < q * 4 * toArc / 360; i++) {
plot(xc + c4[i][0], yc + c4[i][1]);
}
}
}
public void dot(int x, int y, int radius, boolean filled) {
if (filled) {
for (int r = radius; r >= 0; r--) circle(x, y, r);
} else {
circle(x, y, radius);
}
}
public void arc(int x, int y, int innerRadius, int outerRadius, int fromArc, int toArc) {
for (int r = innerRadius; r <= outerRadius; r++) circle(x, y, r, fromArc, toArc);
}
private void print(int x, int y, int angle, char letter) {
int index = (int) letter - 0x20;
if (index >= font.length) return;
long character = font[index];
long row;
for (int i = 0; i < 5; i++) {
row = character & 0x1f;
character = character >> 5;
if (angle == 0) {
for (int j = 0; j < 5; j++) {
if ((row & 1) == 1) plot(x + 5 - j, y);
row = row >> 1;
}
y--;
}
if (angle == 90) {
for (int j = 0; j < 5; j++) {
if ((row & 1) == 1) plot(x, y - 5 + j);
row = row >> 1;
}
x--;
}
}
}
public void print(int x, int y, int angle, String message, boolean alignLeft) {
int xx = 0, yy = 0;
if (angle == 0) {
xx = (alignLeft) ? x : x - 6 * message.length();
yy = y;
} else if (angle == 90) {
xx = x;
yy = (alignLeft) ? y : y + 6 * message.length();
}
for (int i = 0; i < message.length(); i++) {
print(xx, yy, angle, message.charAt(i));
if (angle == 0) xx += 6;
else if (angle == 90) yy -= 6;
}
}
private static final int arcDist = 8;
public void arcPrint(int cx, int cy, int radius, int angle, String message) {
int x = cx + (int) ((radius + 1) * Math.cos(Math.PI * angle / 180));
int y = cy - (int) ((radius + 1) * Math.sin(Math.PI * angle / 180));
int yp = y + 3;
if ((angle > arcDist) && (angle < 180 - arcDist)) yp = y;
if ((angle > 180 + arcDist) && (angle < 360 - arcDist)) yp = y + 6;
if ((angle > ( 90 - arcDist)) && (angle < ( 90 + arcDist))) yp -= 6;
if ((angle > (270 - arcDist)) && (angle < (270 + arcDist))) yp += 6;
int xp = x - 3 * message.length();
if ((angle > (90 + arcDist)) && (angle < (270 - arcDist))) xp = x - 6 * message.length();
if ((angle < (90 - arcDist)) || (angle > (270 + arcDist))) xp = x;
print(xp, yp, 0, message, true);
}
public void arcLine(int cx, int cy, int innerRadius, int outerRadius, int angle) {
int xi = cx + (int) (innerRadius * Math.cos(Math.PI * angle / 180));
int yi = cy - (int) (innerRadius * Math.sin(Math.PI * angle / 180));
int xo = cx + (int) (outerRadius * Math.cos(Math.PI * angle / 180));
int yo = cy - (int) (outerRadius * Math.sin(Math.PI * angle / 180));
line(xi, yi, xo, yo);
}
public void arcDot(int cx, int cy, int arcRadius, int angle, int dotRadius) {
int x = cx + (int) (arcRadius * Math.cos(Math.PI * angle / 180));
int y = cy - (int) (arcRadius * Math.sin(Math.PI * angle / 180));
dot(x, y, dotRadius, true);
}
public void arcArc(int cx, int cy, int arcRadius, int angle, int innerRadius, int outerRadius, int fromArc, int toArc) {
int x = cx + (int) (arcRadius * Math.cos(Math.PI * angle / 180));
int y = cy - (int) (arcRadius * Math.sin(Math.PI * angle / 180));
arc(x, y, innerRadius, outerRadius, fromArc, toArc);
}
public BufferedImage toImage(boolean complementary) {
/*
GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
GraphicsDevice gs = ge.getDefaultScreenDevice();
GraphicsConfiguration gc = gs.getDefaultConfiguration();
BufferedImage bi = gc.createCompatibleImage(width, height, Transparency.TRANSLUCENT);
*/
try {
BufferedImage bi = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
Graphics2D gr = bi.createGraphics();
gr.setBackground(Color.white);
gr.clearRect(0, 0, width, height);
WritableRaster wr = bi.getRaster();
int n;
int r, g, b;
if (complementary) {
// then set pixels
for (int i = width - 1; i >= 0; i--) {
for (int j = height - 1; j >= 0; j--) {
n = 3 * (i + j * width);
r = 0xff & grid[n ];
g = 0xff & grid[n + 1];
b = 0xff & grid[n + 2];
wr.setPixel(i, j, new int[]{(0x1fe - g - b) / 2, (0x1fe - r - b) / 2, (0x1fe - r - g) / 2});
}
}
} else {
for (int i = width - 1; i >= 0; i--) {
for (int j = height - 1; j >= 0; j--) {
n = 3 * (i + j * width);
r = 0xff & grid[n ];
g = 0xff & grid[n + 1];
b = 0xff & grid[n + 2];
wr.setPixel(i, j, new int[]{r, g, b});
}
}
}
return bi;
} catch (Exception e) {
// strange case where environment disallowes generation of graphics
/*
java.lang.InternalError: Can't connect to X11 window server using ':0.0' as the value of the DISPLAY variable.
at sun.awt.X11GraphicsEnvironment.initDisplay(Native Method)
at sun.awt.X11GraphicsEnvironment.access$000(X11GraphicsEnvironment.java:53)
at sun.awt.X11GraphicsEnvironment$1.run(X11GraphicsEnvironment.java:142)
at java.security.AccessController.doPrivileged(Native Method)
at sun.awt.X11GraphicsEnvironment.<clinit>(X11GraphicsEnvironment.java:131)
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Class.java:164)
at java.awt.GraphicsEnvironment.getLocalGraphicsEnvironment(GraphicsEnvironment.java:68)
at java.awt.image.BufferedImage.createGraphics(BufferedImage.java:1141)
at de.anomic.tools.ImagePainter.toImage(ImagePainter.java:354)
*/
System.out.println("Error with Graphics environment:");
e.printStackTrace();
return new BufferedImage(0, 0, BufferedImage.TYPE_INT_RGB);
}
}
public void toPNG(boolean complementary, File f) throws IOException {
BufferedImage bi = toImage(complementary);
ImageIO.write(bi, "png", f);
}
}
// ymageMatrixPainter.java
// ---------------------------
// (C) by Michael Peter Christen; mc@anomic.de
// first published on http://www.anomic.de
// Frankfurt, Germany, 2005
// created: 31.10.2005
//
// This program 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 program 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.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
// Using this software in any meaning (reading, learning, copying, compiling,
// running) means that you agree that the Author(s) is (are) not responsible
// for cost, loss of data or any harm that may be caused directly or indirectly
// by usage of this softare or this documentation. The usage of this software
// is on your own risk. The installation and usage (starting/running) of this
// software may allow other people or application to access your computer and
// any attached devices and is highly dependent on the configuration of the
// software which must be done by the user of the software; the author(s) is
// (are) also not responsible for proper configuration and usage of the
// software, even if provoked by documentation provided together with
// the software.
//
// Any changes to this file according to the GPL as documented in the file
// gpl.txt aside this file in the shipment you received can be done to the
// lines that follows this copyright notice here, but changes must not be
// done inside the copyright notive above. A re-distribution must contain
// the intact and unchanged copyright notice.
// Contributions and changes to the program code must be marked as such.
package de.anomic.ymage;
import java.util.HashSet;
import java.util.ArrayList;
public class ymageMatrixPainter extends ymageMatrix implements ymagePainter {
private static long[] font = new long[]{
0x0000000,0x0421004,0x0A50000,0x0AFABEA,0x0FA38BE,0x09B39B2,0x0E82A8A,0x0420000,
0x0221082,0x0821080,0x0051040,0x0023880,0x0001088,0x0003800,0x0000004,0x0111110,
0x0E9D72E,0x046108E,0x0E8991F,0x0E88A2E,0x0657C42,0x1F8783E,0x0E87A2E,0x1F11084,
0x0E8BA2E,0x0E8BC2E,0x0020080,0x0020088,0x0222082,0x00F83E0,0x0820888,0x0E11004,
0x0EEFA0E,0x04547F1,0x1C97A3E,0x0E8420E,0x1E8C63E,0x1F8721F,0x1F87210,0x0E85E2E,
0x118FE31,0x1F2109F,0x1F0862E,0x1197251,0x108421F,0x11DD631,0x11CD671,0x0E8C62E,
0x1E8FA10,0x0E8D64D,0x1E8FA51,0x0E8382E,0x1F21084,0x118C62E,0x118C544,0x118C6AA,
0x1151151,0x1151084,0x1F1111F,0x0E4210E,0x1041041,0x0E1084E,0x0454400,0x000001F,
0x0820000,0x0003E2F,0x1087A3E,0x0003E0F,0x010BE2F,0x0064A8F,0x0623884,0x00324BE,
0x1085B31,0x0401084,0x0401088,0x1084F93,0x0421084,0x0002AB5,0x0003A31,0x0003A2E,
0x00F47D0,0x007C5E1,0x0011084,0x0001932,0x0471084,0x000462E,0x0004544,0x00056AA,
0x000288A,0x0002884,0x0003C9E,0x0622086,0x0421084,0x0C2088C,0x0045440,0x1F8C63F
};
private static int[][] circles = new int[0][];
public ymageMatrixPainter(int width, int height, String backgroundColor) {
super(width, height, backgroundColor);
}
private static int[] getCircleCoords(int radius) {
if ((radius - 1) < circles.length) return circles[radius - 1];
// read some lines from known circles
HashSet crds = new HashSet();
crds.add("0|0");
String co;
for (int i = Math.max(0, circles.length - 5); i < circles.length; i++) {
for (int j = 0; j < circles[i].length; j = j + 2) {
co = circles[i][j] + "|" + circles[i][j + 1];
if (!(crds.contains(co))) crds.add(co);
}
}
// copy old circles into new array
int[][] newCircles = new int[radius + 30][];
System.arraycopy(circles, 0, newCircles, 0, circles.length);
// compute more lines in new circles
int x, y;
ArrayList crc;
for (int r = circles.length; r < newCircles.length; r++) {
crc = new ArrayList();
for (int a = 0; a <= 2 * (r + 1); a++) {
x = (int) ((r + 1) * Math.cos(Math.PI * a / (4 * (r + 1))));
y = (int) ((r + 1) * Math.sin(Math.PI * a / (4 * (r + 1))));
co = x + "|" + y;
if (!(crds.contains(co))) {
crc.add(new int[]{x, y});
crds.add(co);
}
x = (int) ((r + 0.5) * Math.cos(Math.PI * a / (4 * (r + 1))));
y = (int) ((r + 0.5) * Math.sin(Math.PI * a / (4 * (r + 1))));
co = x + "|" + y;
if (!(crds.contains(co))) {
crc.add(new int[]{x, y});
crds.add(co);
}
}
// put coordinates into array
//System.out.print("Radius " + r + " => " + crc.size() + " points: ");
newCircles[r] = new int[2 * (crc.size() - 1)];
int[] coords;
for (int i = 0; i < crc.size() - 1; i++) {
coords = (int[]) crc.get(i);
newCircles[r][2 * i ] = coords[0];
newCircles[r][2 * i + 1] = coords[1];
//System.out.print(circles[r][i][0] + "," +circles[r][i][1] + "; ");
}
//System.out.println();
}
crc = null;
crds = null;
// move newCircles to circles array
circles = newCircles;
newCircles = null;
// finally return wanted slice
return circles[radius - 1];
}
public void circle(int xc, int yc, int radius) {
if (radius == 0) {
plot(xc, yc);
} else {
int[] c = getCircleCoords(radius);
int x, y;
for (int i = (c.length / 2) - 1; i >= 0; i--) {
x = c[2 * i ];
y = c[2 * i + 1];
plot(xc + x , yc - y - 1); // quadrant 1
plot(xc - x + 1, yc - y - 1); // quadrant 2
plot(xc + x , yc + y ); // quadrant 4
plot(xc - x + 1, yc + y ); // quadrant 3
}
}
}
public void circle(int xc, int yc, int radius, int fromArc, int toArc) {
// draws only a part of a circle
// arc is given in degree
if (radius == 0) {
plot(xc, yc);
} else {
int[] c = getCircleCoords(radius);
int q = c.length / 2;
int[][] c4 = new int[q * 4][];
for (int i = 0; i < q; i++) {
c4[i ] = new int[]{ c[2 * (i )], -c[2 * (i ) + 1] - 1}; // quadrant 1
c4[i + q] = new int[]{1 - c[2 * (q - 1 - i)], -c[2 * (q - 1 - i) + 1] - 1}; // quadrant 2
c4[i + 2 * q] = new int[]{1 - c[2 * (i )], c[2 * (i ) + 1] }; // quadrant 3
c4[i + 3 * q] = new int[]{ c[2 * (q - 1 - i)], c[2 * (q - 1 - i) + 1] }; // quadrant 4
}
for (int i = q * 4 * fromArc / 360; i < q * 4 * toArc / 360; i++) {
plot(xc + c4[i][0], yc + c4[i][1]);
}
}
}
public void dot(int x, int y, int radius, boolean filled) {
if (filled) {
for (int r = radius; r >= 0; r--) circle(x, y, r);
} else {
circle(x, y, radius);
}
}
public void arc(int x, int y, int innerRadius, int outerRadius, int fromArc, int toArc) {
for (int r = innerRadius; r <= outerRadius; r++) circle(x, y, r, fromArc, toArc);
}
private void print(int x, int y, int angle, char letter) {
int index = (int) letter - 0x20;
if (index >= font.length) return;
long character = font[index];
long row;
for (int i = 0; i < 5; i++) {
row = character & 0x1f;
character = character >> 5;
if (angle == 0) {
for (int j = 0; j < 5; j++) {
if ((row & 1) == 1) plot(x + 5 - j, y);
row = row >> 1;
}
y--;
}
if (angle == 90) {
for (int j = 0; j < 5; j++) {
if ((row & 1) == 1) plot(x, y - 5 + j);
row = row >> 1;
}
x--;
}
}
}
public void print(int x, int y, int angle, String message, boolean alignLeft) {
int xx = 0, yy = 0;
if (angle == 0) {
xx = (alignLeft) ? x : x - 6 * message.length();
yy = y;
} else if (angle == 90) {
xx = x;
yy = (alignLeft) ? y : y + 6 * message.length();
}
for (int i = 0; i < message.length(); i++) {
print(xx, yy, angle, message.charAt(i));
if (angle == 0) xx += 6;
else if (angle == 90) yy -= 6;
}
}
private static final int arcDist = 8;
public void arcPrint(int cx, int cy, int radius, int angle, String message) {
int x = cx + (int) ((radius + 1) * Math.cos(Math.PI * angle / 180));
int y = cy - (int) ((radius + 1) * Math.sin(Math.PI * angle / 180));
int yp = y + 3;
if ((angle > arcDist) && (angle < 180 - arcDist)) yp = y;
if ((angle > 180 + arcDist) && (angle < 360 - arcDist)) yp = y + 6;
if ((angle > ( 90 - arcDist)) && (angle < ( 90 + arcDist))) yp -= 6;
if ((angle > (270 - arcDist)) && (angle < (270 + arcDist))) yp += 6;
int xp = x - 3 * message.length();
if ((angle > (90 + arcDist)) && (angle < (270 - arcDist))) xp = x - 6 * message.length();
if ((angle < (90 - arcDist)) || (angle > (270 + arcDist))) xp = x;
print(xp, yp, 0, message, true);
}
public void arcLine(int cx, int cy, int innerRadius, int outerRadius, int angle) {
int xi = cx + (int) (innerRadius * Math.cos(Math.PI * angle / 180));
int yi = cy - (int) (innerRadius * Math.sin(Math.PI * angle / 180));
int xo = cx + (int) (outerRadius * Math.cos(Math.PI * angle / 180));
int yo = cy - (int) (outerRadius * Math.sin(Math.PI * angle / 180));
line(xi, yi, xo, yo);
}
public void arcDot(int cx, int cy, int arcRadius, int angle, int dotRadius) {
int x = cx + (int) (arcRadius * Math.cos(Math.PI * angle / 180));
int y = cy - (int) (arcRadius * Math.sin(Math.PI * angle / 180));
dot(x, y, dotRadius, true);
}
public void arcArc(int cx, int cy, int arcRadius, int angle, int innerRadius, int outerRadius, int fromArc, int toArc) {
int x = cx + (int) (arcRadius * Math.cos(Math.PI * angle / 180));
int y = cy - (int) (arcRadius * Math.sin(Math.PI * angle / 180));
arc(x, y, innerRadius, outerRadius, fromArc, toArc);
}
}

@ -0,0 +1,93 @@
// ymagePNGEncoderAWT.java
// ---------------------------
// (C) by Michael Peter Christen; mc@anomic.de
// first published on http://www.anomic.de
// Frankfurt, Germany, 2005
// created: 31.10.2005
//
// This program 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 program 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.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
// Using this software in any meaning (reading, learning, copying, compiling,
// running) means that you agree that the Author(s) is (are) not responsible
// for cost, loss of data or any harm that may be caused directly or indirectly
// by usage of this softare or this documentation. The usage of this software
// is on your own risk. The installation and usage (starting/running) of this
// software may allow other people or application to access your computer and
// any attached devices and is highly dependent on the configuration of the
// software which must be done by the user of the software; the author(s) is
// (are) also not responsible for proper configuration and usage of the
// software, even if provoked by documentation provided together with
// the software.
//
// Any changes to this file according to the GPL as documented in the file
// gpl.txt aside this file in the shipment you received can be done to the
// lines that follows this copyright notice here, but changes must not be
// done inside the copyright notive above. A re-distribution must contain
// the intact and unchanged copyright notice.
// Contributions and changes to the program code must be marked as such.
package de.anomic.ymage;
import java.awt.Graphics2D;
import java.awt.GraphicsEnvironment;
import java.awt.GraphicsDevice;
import java.awt.GraphicsConfiguration;
import java.awt.Transparency;
import java.awt.Color;
import java.awt.image.BufferedImage;
import java.awt.image.WritableRaster;
import javax.imageio.ImageIO;
import java.io.File;
import java.io.IOException;
public class ymagePNGEncoderAWT {
public static BufferedImage toImage(ymageMatrix matrix, boolean complementary) {
// GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
// GraphicsDevice gs = ge.getDefaultScreenDevice();
// GraphicsConfiguration gc = gs.getDefaultConfiguration();
// BufferedImage bi = gc.createCompatibleImage(width, height, Transparency.TRANSLUCENT);
try {
BufferedImage bi = new BufferedImage(matrix.getWidth(), matrix.getHeight(), BufferedImage.TYPE_INT_RGB);
Graphics2D gr = bi.createGraphics();
gr.setBackground(Color.white);
gr.clearRect(0, 0, matrix.getWidth(), matrix.getHeight());
WritableRaster wr = bi.getRaster();
int n;
int r, g, b;
matrix.getColorMode(complementary);
for (int i = matrix.getWidth() - 1; i >= 0; i--) {
for (int j = matrix.getHeight() - 1; j >= 0; j--) {
wr.setPixel(i, j, matrix.getColor(i, j));
}
}
return bi;
} catch (Exception e) {
// strange case where environment disallowes generation of graphics
System.out.println("Error with Graphics environment:");
e.printStackTrace();
return new BufferedImage(0, 0, BufferedImage.TYPE_INT_RGB);
}
}
public static void toPNG(ymageMatrix matrix, boolean complementary, File f) throws IOException {
BufferedImage bi = toImage(matrix, complementary);
ImageIO.write(bi, "png", f);
}
}

@ -0,0 +1,552 @@
/**
* PngEncoder takes a Java Image object and creates a byte string which can be saved as a PNG file.
* The Image is presumed to use the DirectColorModel.
*
* Thanks to Jay Denny at KeyPoint Software
* http://www.keypoint.com/
* who let me develop this code on company time.
*
* You may contact me with (probably very-much-needed) improvements,
* comments, and bug fixes at:
*
* david@catcode.com
*
* 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.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* A copy of the GNU LGPL may be found at
* http://www.gnu.org/copyleft/lesser.html,
*
* @author J. David Eisenberg
* @version 1.4, 31 March 2000
*/
/*
* this file was taken from
* http://chem.sis.nlm.nih.gov/chemidplus/applet/chemaxon/marvin/help/PngEncoder.java.txt
* and modified by Michael Peter Christen, Frankfurt, 2005
* to work with ImagePainter Objects instead of awt.image Objetcs
* this avoids using any awt routines
*/
package de.anomic.ymage;
import java.util.*;
import java.util.zip.*;
import java.io.*;
public class ymagePNGEncoderJDE extends Object
{
/** Constants for filters */
public static final int FILTER_NONE = 0;
public static final int FILTER_SUB = 1;
public static final int FILTER_UP = 2;
public static final int FILTER_LAST = 2;
protected byte[] pngBytes;
protected byte[] priorRow;
protected byte[] leftBytes;
protected ymageMatrix matrix;
protected int width, height;
protected int bytePos, maxPos;
protected int hdrPos, dataPos, endPos;
protected CRC32 crc = new CRC32();
protected long crcValue;
protected boolean encodeAlpha;
protected int filter;
protected int bytesPerPixel;
protected int compressionLevel;
/**
* Class constructor specifying Image source to encode, whether to encode alpha, filter to use, and compression level.
*
* @param image A Java Image object
* @param encodeAlpha Encode the alpha channel? false=no; true=yes
* @param whichFilter 0=none, 1=sub, 2=up
* @param compLevel 0..9
* @see java.awt.Image
*/
public ymagePNGEncoderJDE(ymageMatrix matrix, int whichFilter, int compLevel)
{
this.matrix = matrix;
this.encodeAlpha = false;
setFilter( whichFilter );
if (compLevel >=0 && compLevel <=9)
{
this.compressionLevel = compLevel;
}
}
/**
* Creates an array of bytes that is the PNG equivalent of the current image, specifying whether to encode alpha or not.
*
* @param encodeAlpha boolean false=no alpha, true=encode alpha
* @return an array of bytes, or null if there was a problem
*/
public byte[] pngEncode( boolean encodeAlpha )
{
byte[] pngIdBytes = { -119, 80, 78, 71, 13, 10, 26, 10 };
int i;
if (matrix == null)
{
return null;
}
width = matrix.getWidth();
height = matrix.getHeight();
this.matrix = matrix;
/*
* start with an array that is big enough to hold all the pixels
* (plus filter bytes), and an extra 200 bytes for header info
*/
pngBytes = new byte[((width+1) * height * 3) + 200];
/*
* keep track of largest byte written to the array
*/
maxPos = 0;
bytePos = writeBytes( pngIdBytes, 0 );
hdrPos = bytePos;
writeHeader();
dataPos = bytePos;
if (writeImageData())
{
writeEnd();
pngBytes = resizeByteArray( pngBytes, maxPos );
}
else
{
pngBytes = null;
}
return pngBytes;
}
/**
* Creates an array of bytes that is the PNG equivalent of the current image.
* Alpha encoding is determined by its setting in the constructor.
*
* @return an array of bytes, or null if there was a problem
*/
public byte[] pngEncode()
{
return pngEncode( encodeAlpha );
}
/**
* Set the alpha encoding on or off.
*
* @param encodeAlpha false=no, true=yes
*/
public void setEncodeAlpha( boolean encodeAlpha )
{
this.encodeAlpha = encodeAlpha;
}
/**
* Retrieve alpha encoding status.
*
* @return boolean false=no, true=yes
*/
public boolean getEncodeAlpha()
{
return encodeAlpha;
}
/**
* Set the filter to use
*
* @param whichFilter from constant list
*/
public void setFilter( int whichFilter )
{
this.filter = FILTER_NONE;
if ( whichFilter <= FILTER_LAST )
{
this.filter = whichFilter;
}
}
/**
* Retrieve filtering scheme
*
* @return int (see constant list)
*/
public int getFilter()
{
return filter;
}
/**
* Set the compression level to use
*
* @param level 0 through 9
*/
public void setCompressionLevel( int level )
{
if ( level >= 0 && level <= 9)
{
this.compressionLevel = level;
}
}
/**
* Retrieve compression level
*
* @return int in range 0-9
*/
public int getCompressionLevel()
{
return compressionLevel;
}
/**
* Increase or decrease the length of a byte array.
*
* @param array The original array.
* @param newLength The length you wish the new array to have.
* @return Array of newly desired length. If shorter than the
* original, the trailing elements are truncated.
*/
protected byte[] resizeByteArray( byte[] array, int newLength )
{
byte[] newArray = new byte[newLength];
int oldLength = array.length;
System.arraycopy( array, 0, newArray, 0,
Math.min( oldLength, newLength ) );
return newArray;
}
/**
* Write an array of bytes into the pngBytes array.
* Note: This routine has the side effect of updating
* maxPos, the largest element written in the array.
* The array is resized by 1000 bytes or the length
* of the data to be written, whichever is larger.
*
* @param data The data to be written into pngBytes.
* @param offset The starting point to write to.
* @return The next place to be written to in the pngBytes array.
*/
protected int writeBytes( byte[] data, int offset )
{
maxPos = Math.max( maxPos, offset + data.length );
if (data.length + offset > pngBytes.length)
{
pngBytes = resizeByteArray( pngBytes, pngBytes.length +
Math.max( 1000, data.length ) );
}
System.arraycopy( data, 0, pngBytes, offset, data.length );
return offset + data.length;
}
/**
* Write an array of bytes into the pngBytes array, specifying number of bytes to write.
* Note: This routine has the side effect of updating
* maxPos, the largest element written in the array.
* The array is resized by 1000 bytes or the length
* of the data to be written, whichever is larger.
*
* @param data The data to be written into pngBytes.
* @param nBytes The number of bytes to be written.
* @param offset The starting point to write to.
* @return The next place to be written to in the pngBytes array.
*/
protected int writeBytes( byte[] data, int nBytes, int offset )
{
maxPos = Math.max( maxPos, offset + nBytes );
if (nBytes + offset > pngBytes.length)
{
pngBytes = resizeByteArray( pngBytes, pngBytes.length +
Math.max( 1000, nBytes ) );
}
System.arraycopy( data, 0, pngBytes, offset, nBytes );
return offset + nBytes;
}
/**
* Write a two-byte integer into the pngBytes array at a given position.
*
* @param n The integer to be written into pngBytes.
* @param offset The starting point to write to.
* @return The next place to be written to in the pngBytes array.
*/
protected int writeInt2( int n, int offset )
{
byte[] temp = { (byte)((n >> 8) & 0xff),
(byte) (n & 0xff) };
return writeBytes( temp, offset );
}
/**
* Write a four-byte integer into the pngBytes array at a given position.
*
* @param n The integer to be written into pngBytes.
* @param offset The starting point to write to.
* @return The next place to be written to in the pngBytes array.
*/
protected int writeInt4( int n, int offset )
{
byte[] temp = { (byte)((n >> 24) & 0xff),
(byte) ((n >> 16) & 0xff ),
(byte) ((n >> 8) & 0xff ),
(byte) ( n & 0xff ) };
return writeBytes( temp, offset );
}
/**
* Write a single byte into the pngBytes array at a given position.
*
* @param n The integer to be written into pngBytes.
* @param offset The starting point to write to.
* @return The next place to be written to in the pngBytes array.
*/
protected int writeByte( int b, int offset )
{
byte[] temp = { (byte) b };
return writeBytes( temp, offset );
}
/**
* Write a string into the pngBytes array at a given position.
* This uses the getBytes method, so the encoding used will
* be its default.
*
* @param n The integer to be written into pngBytes.
* @param offset The starting point to write to.
* @return The next place to be written to in the pngBytes array.
* @see java.lang.String#getBytes()
*/
protected int writeString( String s, int offset )
{
return writeBytes( s.getBytes(), offset );
}
/**
* Write a PNG "IHDR" chunk into the pngBytes array.
*/
protected void writeHeader()
{
int startPos;
startPos = bytePos = writeInt4( 13, bytePos );
bytePos = writeString( "IHDR", bytePos );
width = matrix.getWidth();
height = matrix.getHeight();
bytePos = writeInt4( width, bytePos );
bytePos = writeInt4( height, bytePos );
bytePos = writeByte( 8, bytePos ); // bit depth
bytePos = writeByte( (encodeAlpha) ? 6 : 2, bytePos ); // direct model
bytePos = writeByte( 0, bytePos ); // compression method
bytePos = writeByte( 0, bytePos ); // filter method
bytePos = writeByte( 0, bytePos ); // no interlace
crc.reset();
crc.update( pngBytes, startPos, bytePos-startPos );
crcValue = crc.getValue();
bytePos = writeInt4( (int) crcValue, bytePos );
}
/**
* Perform "sub" filtering on the given row.
* Uses temporary array leftBytes to store the original values
* of the previous pixels. The array is 16 bytes long, which
* will easily hold two-byte samples plus two-byte alpha.
*
* @param pixels The array holding the scan lines being built
* @param startPos Starting position within pixels of bytes to be filtered.
* @param width Width of a scanline in pixels.
*/
protected void filterSub( byte[] pixels, int startPos, int width )
{
int i;
int offset = bytesPerPixel;
int actualStart = startPos + offset;
int nBytes = width * bytesPerPixel;
int leftInsert = offset;
int leftExtract = 0;
byte current_byte;
for (i=actualStart; i < startPos + nBytes; i++)
{
leftBytes[leftInsert] = pixels[i];
pixels[i] = (byte) ((pixels[i] - leftBytes[leftExtract]) % 256);
leftInsert = (leftInsert+1) % 0x0f;
leftExtract = (leftExtract + 1) % 0x0f;
}
}
/**
* Perform "up" filtering on the given row.
* Side effect: refills the prior row with current row
*
* @param pixels The array holding the scan lines being built
* @param startPos Starting position within pixels of bytes to be filtered.
* @param width Width of a scanline in pixels.
*/
protected void filterUp( byte[] pixels, int startPos, int width )
{
int i, nBytes;
byte current_byte;
nBytes = width * bytesPerPixel;
for (i=0; i < nBytes; i++)
{
current_byte = pixels[startPos + i];
pixels[startPos + i] = (byte) ((pixels[startPos + i] - priorRow[i]) % 256);
priorRow[i] = current_byte;
}
}
/**
* Write the image data into the pngBytes array.
* This will write one or more PNG "IDAT" chunks. In order
* to conserve memory, this method grabs as many rows as will
* fit into 32K bytes, or the whole image; whichever is less.
*
*
* @return true if no errors; false if error grabbing pixels
*/
protected boolean writeImageData()
{
int rowsLeft = height; // number of rows remaining to write
int startRow = 0; // starting row to process this time through
int nRows; // how many rows to grab at a time
byte[] scanLines; // the scan lines to be compressed
int scanPos; // where we are in the scan lines
int startPos; // where this line's actual pixels start (used for filtering)
byte[] compressedLines; // the resultant compressed lines
int nCompressed; // how big is the compressed area?
int depth; // color depth ( handle only 8 or 32 )
bytesPerPixel = (encodeAlpha) ? 4 : 3;
Deflater scrunch = new Deflater( compressionLevel );
ByteArrayOutputStream outBytes =
new ByteArrayOutputStream(1024);
DeflaterOutputStream compBytes =
new DeflaterOutputStream( outBytes, scrunch );
try
{
while (rowsLeft > 0)
{
nRows = Math.min( 32767 / (width*(bytesPerPixel+1)), rowsLeft );
// nRows = rowsLeft;
/*
* Create a data chunk. scanLines adds "nRows" for
* the filter bytes.
*/
scanLines = new byte[width * nRows * bytesPerPixel + nRows];
if (filter == FILTER_SUB)
{
leftBytes = new byte[16];
}
if (filter == FILTER_UP)
{
priorRow = new byte[width*bytesPerPixel];
}
scanPos = 0;
startPos = 1;
int[] pixel;
matrix.getColorMode(true);
for (int i=0; i<width*nRows; i++)
{
if (i % width == 0)
{
scanLines[scanPos++] = (byte) filter;
startPos = scanPos;
}
pixel = matrix.getColor(i % width, i / width);
scanLines[scanPos++] = (byte) pixel[0]; // red
scanLines[scanPos++] = (byte) pixel[1]; // green
scanLines[scanPos++] = (byte) pixel[2]; // blue
if (encodeAlpha)
{
//scanLines[scanPos++] = (byte) ((pixels[i] >> 24) & 0xff );
}
if ((i % width == width-1) && (filter != FILTER_NONE))
{
if (filter == FILTER_SUB)
{
filterSub( scanLines, startPos, width );
}
if (filter == FILTER_UP)
{
filterUp( scanLines, startPos, width );
}
}
}
/*
* Write these lines to the output area
*/
compBytes.write( scanLines, 0, scanPos );
startRow += nRows;
rowsLeft -= nRows;
}
compBytes.close();
/*
* Write the compressed bytes
*/
compressedLines = outBytes.toByteArray();
nCompressed = compressedLines.length;
crc.reset();
bytePos = writeInt4( nCompressed, bytePos );
bytePos = writeString("IDAT", bytePos );
crc.update("IDAT".getBytes());
bytePos = writeBytes( compressedLines, nCompressed, bytePos );
crc.update( compressedLines, 0, nCompressed );
crcValue = crc.getValue();
bytePos = writeInt4( (int) crcValue, bytePos );
scrunch.finish();
return true;
}
catch (IOException e)
{
System.err.println( e.toString());
return false;
} finally {
}
}
/**
* Write a PNG "IEND" chunk into the pngBytes array.
*/
protected void writeEnd()
{
bytePos = writeInt4( 0, bytePos );
bytePos = writeString( "IEND", bytePos );
crc.reset();
crc.update("IEND".getBytes());
crcValue = crc.getValue();
bytePos = writeInt4( (int) crcValue, bytePos );
}
}

@ -0,0 +1,80 @@
// ymagePainter.java
// ---------------------------
// (C) by Michael Peter Christen; mc@anomic.de
// first published on http://www.anomic.de
// Frankfurt, Germany, 2005
// created: 31.10.2005
//
// This program 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 program 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.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
// Using this software in any meaning (reading, learning, copying, compiling,
// running) means that you agree that the Author(s) is (are) not responsible
// for cost, loss of data or any harm that may be caused directly or indirectly
// by usage of this softare or this documentation. The usage of this software
// is on your own risk. The installation and usage (starting/running) of this
// software may allow other people or application to access your computer and
// any attached devices and is highly dependent on the configuration of the
// software which must be done by the user of the software; the author(s) is
// (are) also not responsible for proper configuration and usage of the
// software, even if provoked by documentation provided together with
// the software.
//
// Any changes to this file according to the GPL as documented in the file
// gpl.txt aside this file in the shipment you received can be done to the
// lines that follows this copyright notice here, but changes must not be
// done inside the copyright notive above. A re-distribution must contain
// the intact and unchanged copyright notice.
// Contributions and changes to the program code must be marked as such.
package de.anomic.ymage;
public interface ymagePainter {
public Object clone();
public int getWidth();
public int getHeight();
public void setColor(String s);
public void setColor(long c);
public void setMode(byte m);
public void plot(int x, int y);
public void line(int Ax, int Ay, int Bx, int By);
public void circle(int xc, int yc, int radius);
public void circle(int xc, int yc, int radius, int fromArc, int toArc);
public void dot(int x, int y, int radius, boolean filled);
public void arc(int x, int y, int innerRadius, int outerRadius, int fromArc, int toArc);
public void print(int x, int y, int angle, String message, boolean alignLeft);
public void arcPrint(int cx, int cy, int radius, int angle, String message);
public void arcLine(int cx, int cy, int innerRadius, int outerRadius, int angle);
public void arcDot(int cx, int cy, int arcRadius, int angle, int dotRadius);
public void arcArc(int cx, int cy, int arcRadius, int angle, int innerRadius, int outerRadius, int fromArc, int toArc);
}
Loading…
Cancel
Save