From b058ecf0bcb747bd2f20f4e0455a04ff19110f38 Mon Sep 17 00:00:00 2001 From: orbiter Date: Mon, 31 Oct 2005 02:43:55 +0000 Subject: [PATCH] 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 --- build.xml | 1 + htroot/NetworkPicture.java | 8 +- htroot/SearchEventPicture.java | 12 +- htroot/imagetest.java | 28 +- source/dbtest.java | 15 +- source/de/anomic/http/httpdFileHandler.java | 18 +- source/de/anomic/plasma/plasmaGrafics.java | 33 +- source/de/anomic/plasma/plasmaURL.java | 18 +- source/de/anomic/yacy/yacySeed.java | 7 +- .../ImageChart.java => ymage/ymageChart.java} | 12 +- .../de/anomic/ymage/ymageFontGenerator.java | 573 +++++++++++++ source/de/anomic/ymage/ymageMatrix.java | 228 ++++++ .../ymageMatrixPainter.java} | 752 ++++++------------ .../de/anomic/ymage/ymagePNGEncoderAWT.java | 93 +++ .../de/anomic/ymage/ymagePNGEncoderJDE.java | 552 +++++++++++++ source/de/anomic/ymage/ymagePainter.java | 80 ++ 16 files changed, 1876 insertions(+), 554 deletions(-) rename source/de/anomic/{tools/ImageChart.java => ymage/ymageChart.java} (96%) create mode 100644 source/de/anomic/ymage/ymageFontGenerator.java create mode 100644 source/de/anomic/ymage/ymageMatrix.java rename source/de/anomic/{tools/ImagePainter.java => ymage/ymageMatrixPainter.java} (52%) create mode 100644 source/de/anomic/ymage/ymagePNGEncoderAWT.java create mode 100644 source/de/anomic/ymage/ymagePNGEncoderJDE.java create mode 100644 source/de/anomic/ymage/ymagePainter.java diff --git a/build.xml b/build.xml index 3adaade9a..3d994d016 100644 --- a/build.xml +++ b/build.xml @@ -144,6 +144,7 @@ + diff --git a/htroot/NetworkPicture.java b/htroot/NetworkPicture.java index 402af270b..7a8fc00ca 100644 --- a/htroot/NetworkPicture.java +++ b/htroot/NetworkPicture.java @@ -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); } } diff --git a/htroot/SearchEventPicture.java b/htroot/SearchEventPicture.java index eafefa947..9cdf0ee66 100644 --- a/htroot/SearchEventPicture.java +++ b/htroot/SearchEventPicture.java @@ -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; } } diff --git a/htroot/imagetest.java b/htroot/imagetest.java index 299c1dbf9..558ca617b 100644 --- a/htroot/imagetest.java +++ b/htroot/imagetest.java @@ -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; } diff --git a/source/dbtest.java b/source/dbtest.java index b18edcc6d..81ea9efeb 100644 --- a/source/dbtest.java +++ b/source/dbtest.java @@ -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) {} } diff --git a/source/de/anomic/http/httpdFileHandler.java b/source/de/anomic/http/httpdFileHandler.java index 4eba231f2..d9c3e3679 100644 --- a/source/de/anomic/http/httpdFileHandler.java +++ b/source/de/anomic/http/httpdFileHandler.java @@ -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; diff --git a/source/de/anomic/plasma/plasmaGrafics.java b/source/de/anomic/plasma/plasmaGrafics.java index c0b66c442..d2217d63d 100644 --- a/source/de/anomic/plasma/plasmaGrafics.java +++ b/source/de/anomic/plasma/plasmaGrafics.java @@ -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; diff --git a/source/de/anomic/plasma/plasmaURL.java b/source/de/anomic/plasma/plasmaURL.java index 44b06512b..3c43b9dbd 100644 --- a/source/de/anomic/plasma/plasmaURL.java +++ b/source/de/anomic/plasma/plasmaURL.java @@ -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 + */ } diff --git a/source/de/anomic/yacy/yacySeed.java b/source/de/anomic/yacy/yacySeed.java index b48f47b7b..7ce7ae3ed 100644 --- a/source/de/anomic/yacy/yacySeed.java +++ b/source/de/anomic/yacy/yacySeed.java @@ -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() { diff --git a/source/de/anomic/tools/ImageChart.java b/source/de/anomic/ymage/ymageChart.java similarity index 96% rename from source/de/anomic/tools/ImageChart.java rename to source/de/anomic/ymage/ymageChart.java index 8b278976a..018222978 100644 --- a/source/de/anomic/tools/ImageChart.java +++ b/source/de/anomic/ymage/ymageChart.java @@ -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) {} + */ } } diff --git a/source/de/anomic/ymage/ymageFontGenerator.java b/source/de/anomic/ymage/ymageFontGenerator.java new file mode 100644 index 000000000..189147c8b --- /dev/null +++ b/source/de/anomic/ymage/ymageFontGenerator.java @@ -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; + } + } + } + +} diff --git a/source/de/anomic/ymage/ymageMatrix.java b/source/de/anomic/ymage/ymageMatrix.java new file mode 100644 index 000000000..55c5f68a5 --- /dev/null +++ b/source/de/anomic/ymage/ymageMatrix.java @@ -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}; + } + } + + +} diff --git a/source/de/anomic/tools/ImagePainter.java b/source/de/anomic/ymage/ymageMatrixPainter.java similarity index 52% rename from source/de/anomic/tools/ImagePainter.java rename to source/de/anomic/ymage/ymageMatrixPainter.java index 17e27480e..6fd8b4fd7 100644 --- a/source/de/anomic/tools/ImagePainter.java +++ b/source/de/anomic/ymage/ymageMatrixPainter.java @@ -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.(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); + } + +} diff --git a/source/de/anomic/ymage/ymagePNGEncoderAWT.java b/source/de/anomic/ymage/ymagePNGEncoderAWT.java new file mode 100644 index 000000000..85b2692f6 --- /dev/null +++ b/source/de/anomic/ymage/ymagePNGEncoderAWT.java @@ -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); + } + +} diff --git a/source/de/anomic/ymage/ymagePNGEncoderJDE.java b/source/de/anomic/ymage/ymagePNGEncoderJDE.java new file mode 100644 index 000000000..6d7c7b444 --- /dev/null +++ b/source/de/anomic/ymage/ymagePNGEncoderJDE.java @@ -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> 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 ); + } +} diff --git a/source/de/anomic/ymage/ymagePainter.java b/source/de/anomic/ymage/ymagePainter.java new file mode 100644 index 000000000..301000bd4 --- /dev/null +++ b/source/de/anomic/ymage/ymagePainter.java @@ -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); + +}