001: // ymageMatrix.java
002: // (C) 2005 by Michael Peter Christen; mc@yacy.net, Frankfurt a. M., Germany
003: // first published 16.09.2005 on http://yacy.net
004: //
005: // This is a part of YaCy, a peer-to-peer based web search engine
006: //
007: // $LastChangedDate: 2006-04-02 22:40:07 +0200 (So, 02 Apr 2006) $
008: // $LastChangedRevision: 1986 $
009: // $LastChangedBy: orbiter $
010: //
011: // LICENSE
012: //
013: // This program is free software; you can redistribute it and/or modify
014: // it under the terms of the GNU General Public License as published by
015: // the Free Software Foundation; either version 2 of the License, or
016: // (at your option) any later version.
017: //
018: // This program is distributed in the hope that it will be useful,
019: // but WITHOUT ANY WARRANTY; without even the implied warranty of
020: // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
021: // GNU General Public License for more details.
022: //
023: // You should have received a copy of the GNU General Public License
024: // along with this program; if not, write to the Free Software
025: // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
026:
027: /*
028: This Class implements some convenience-methods to support drawing of statistical Data
029: It is not intended to replace existing awt-funktions even if it looks so
030: This class provides some drawing methods that creates transparency effects that
031: are not available in awt.
032: */
033:
034: package de.anomic.ymage;
035:
036: import java.awt.Color;
037: import java.awt.Graphics2D;
038: import java.awt.image.BufferedImage;
039: import java.awt.image.WritableRaster;
040: import java.io.File;
041: import java.io.FileOutputStream;
042: import java.io.IOException;
043: import java.util.ArrayList;
044:
045: import javax.imageio.ImageIO;
046:
047: import de.anomic.server.serverByteBuffer;
048: import de.anomic.server.serverMemory;
049:
050: public class ymageMatrix {
051:
052: // colors regarding RGB Color Model
053: public static final long RED = 0xFF0000;
054: public static final long GREEN = 0x00FF00;
055: public static final long BLUE = 0x0000FF;
056: public static final long GREY = 0x888888;
057:
058: public static final byte MODE_REPLACE = 0;
059: public static final byte MODE_ADD = 1;
060: public static final byte MODE_SUB = 2;
061:
062: public static final byte FILTER_ANTIALIASING = 0;
063: public static final byte FILTER_BLUR = 1;
064: public static final byte FILTER_INVERT = 2;
065:
066: protected int width, height;
067: private BufferedImage image;
068: private WritableRaster grid;
069: private int[] defaultCol;
070: private long backgroundCol;
071: private byte defaultMode;
072:
073: public ymageMatrix(int width, int height, byte drawMode,
074: String backgroundColor) {
075: this (width, height, drawMode, Long.parseLong(backgroundColor,
076: 16));
077: }
078:
079: public ymageMatrix(int width, int height, byte drawMode,
080: long backgroundColor) {
081: if (!(serverMemory.request(1024 * 1024 + 3 * width * height,
082: false)))
083: throw new RuntimeException("ymage: not enough memory ("
084: + serverMemory.available() + ") available");
085: this .width = width;
086: this .height = height;
087: this .backgroundCol = backgroundColor;
088: this .defaultCol = new int[] { 0xFF, 0xFF, 0xFF };
089: this .defaultMode = drawMode;
090:
091: this .image = new BufferedImage(width, height,
092: BufferedImage.TYPE_INT_RGB);
093: //this.image = imageFromPool(width, height, 1000);
094: this .clear();
095: this .grid = image.getRaster();
096: }
097:
098: public void clear() {
099: // fill grid with background color
100: int bgR, bgG, bgB;
101: /*if (drawMode == MODE_SUB) {
102: bgR = (int) (0xFF - (this.backgroundCol >> 16));
103: bgG = (int) (0xFF - ((this.backgroundCol >> 8) & 0xff));
104: bgB = (int) (0xFF - (this.backgroundCol & 0xff));
105: } else {*/
106: bgR = (int) (this .backgroundCol >> 16);
107: bgG = (int) ((this .backgroundCol >> 8) & 0xff);
108: bgB = (int) (this .backgroundCol & 0xff);
109: //}
110: Graphics2D gr = image.createGraphics();
111: gr.setBackground(new Color(bgR, bgG, bgB));
112: gr.clearRect(0, 0, width, height);
113: /*
114: int[] c = new int[]{bgR, bgG, bgB};
115: for (int i = 0; i < width; i++) {
116: for (int j = 0; j < height; j++) {
117: grid.setPixel(i, j, c);
118: }
119: }
120: */
121: }
122:
123: public BufferedImage getImage() {
124: return this .image;
125: }
126:
127: public int getWidth() {
128: return width;
129: }
130:
131: public int getHeight() {
132: return height;
133: }
134:
135: public void setColor(long c) {
136: if (this .defaultMode == MODE_SUB) {
137: int r = (int) (c >> 16);
138: int g = (int) ((c >> 8) & 0xff);
139: int b = (int) (c & 0xff);
140: defaultCol[0] = (g + b) / 2;
141: defaultCol[1] = (r + b) / 2;
142: defaultCol[2] = (r + g) / 2;
143: } else {
144: defaultCol[0] = (int) (c >> 16);
145: defaultCol[1] = (int) ((c >> 8) & 0xff);
146: defaultCol[2] = (int) (c & 0xff);
147: }
148:
149: }
150:
151: public void setColor(String s) {
152: setColor(Long.parseLong(s, 16));
153: }
154:
155: public void plot(int x, int y) {
156: plot(x, y, 100);
157: }
158:
159: private int[] cc = new int[3];
160:
161: public void plot(int x, int y, int intensity) {
162: if ((x < 0) || (x >= width))
163: return;
164: if ((y < 0) || (y >= height))
165: return;
166: synchronized (cc) {
167: if (this .defaultMode == MODE_REPLACE) {
168: if (intensity == 100) {
169: cc[0] = defaultCol[0];
170: cc[1] = defaultCol[1];
171: cc[2] = defaultCol[2];
172: } else {
173: int[] c = new int[3];
174: c = grid.getPixel(x, y, c);
175: cc[0] = (intensity * defaultCol[0] + (100 - intensity)
176: * c[0]) / 100;
177: cc[1] = (intensity * defaultCol[1] + (100 - intensity)
178: * c[1]) / 100;
179: cc[2] = (intensity * defaultCol[2] + (100 - intensity)
180: * c[2]) / 100;
181: }
182: } else if (this .defaultMode == MODE_ADD) {
183: int[] c = new int[3];
184: c = grid.getPixel(x, y, c);
185: if (intensity == 100) {
186: cc[0] = (0xff & c[0]) + defaultCol[0];
187: if (cc[0] > 255)
188: cc[0] = 255;
189: cc[1] = (0xff & c[1]) + defaultCol[1];
190: if (cc[1] > 255)
191: cc[1] = 255;
192: cc[2] = (0xff & c[2]) + defaultCol[2];
193: if (cc[2] > 255)
194: cc[2] = 255;
195: } else {
196: cc[0] = (0xff & c[0])
197: + (intensity * defaultCol[0] / 100);
198: if (cc[0] > 255)
199: cc[0] = 255;
200: cc[1] = (0xff & c[1])
201: + (intensity * defaultCol[1] / 100);
202: if (cc[1] > 255)
203: cc[1] = 255;
204: cc[2] = (0xff & c[2])
205: + (intensity * defaultCol[2] / 100);
206: if (cc[2] > 255)
207: cc[2] = 255;
208: }
209: } else if (this .defaultMode == MODE_SUB) {
210: int[] c = new int[3];
211: c = grid.getPixel(x, y, c);
212: if (intensity == 100) {
213: cc[0] = (0xff & c[0]) - defaultCol[0];
214: if (cc[0] < 0)
215: cc[0] = 0;
216: cc[1] = (0xff & c[1]) - defaultCol[1];
217: if (cc[1] < 0)
218: cc[1] = 0;
219: cc[2] = (0xff & c[2]) - defaultCol[2];
220: if (cc[2] < 0)
221: cc[2] = 0;
222: } else {
223: cc[0] = (0xff & c[0])
224: - (intensity * defaultCol[0] / 100);
225: if (cc[0] < 0)
226: cc[0] = 0;
227: cc[1] = (0xff & c[1])
228: - (intensity * defaultCol[1] / 100);
229: if (cc[1] < 0)
230: cc[1] = 0;
231: cc[2] = (0xff & c[2])
232: - (intensity * defaultCol[2] / 100);
233: if (cc[2] < 0)
234: cc[2] = 0;
235: }
236: }
237: grid.setPixel(x, y, cc);
238: }
239: }
240:
241: public void line(int Ax, int Ay, int Bx, int By) {
242: // Bresenham's line drawing algorithm
243: int dX = Math.abs(Bx - Ax);
244: int dY = Math.abs(By - Ay);
245: int Xincr, Yincr;
246: if (Ax > Bx)
247: Xincr = -1;
248: else
249: Xincr = 1;
250: if (Ay > By)
251: Yincr = -1;
252: else
253: Yincr = 1;
254: if (dX >= dY) {
255: int dPr = dY << 1;
256: int dPru = dPr - (dX << 1);
257: int P = dPr - dX;
258: for (; dX >= 0; dX--) {
259: plot(Ax, Ay);
260: if (P > 0) {
261: Ax += Xincr;
262: Ay += Yincr;
263: P += dPru;
264: } else {
265: Ax += Xincr;
266: P += dPr;
267: }
268: }
269: } else {
270: int dPr = dX << 1;
271: int dPru = dPr - (dY << 1);
272: int P = dPr - dY;
273: for (; dY >= 0; dY--) {
274: plot(Ax, Ay);
275: if (P > 0) {
276: Ax += Xincr;
277: Ay += Yincr;
278: P += dPru;
279: } else {
280: Ay += Yincr;
281: P += dPr;
282: }
283: }
284: }
285: }
286:
287: public void lineDot(int x0, int y0, int x1, int y1, int radius,
288: int distance, long lineColor, long dotColor) {
289: // draw a line with a dot at the end.
290: // the radius value is the radius of the dot
291: // the distance value is the distance of the dot border to the endpoint
292:
293: // compute first the angle of the line between the points
294: double angle = (x1 - x0 > 0) ? Math.atan(((double) (y0 - y1))
295: / ((double) (x1 - x0))) : Math.PI
296: - Math
297: .atan(((double) (y0 - y1))
298: / ((double) (x0 - x1)));
299: // now find two more points in between
300: // first calculate the radius' of the points
301: double ra = Math
302: .sqrt((double) ((x0 - x1) * (x0 - x1) + (y0 - y1)
303: * (y0 - y1))); // from a known point x1, y1
304: double rb = ra - radius - distance;
305: double rc = rb - radius;
306: //System.out.println("CONTROL angle = " + angle);
307: //System.out.println("CONTROL x1 = " + x1 + ", x1calc = " + ((x0 + ((int) ra * Math.cos(angle)))));
308: //System.out.println("CONTROL y1 = " + y1 + ", y1calc = " + ((y0 - ((int) ra * Math.sin(angle)))));
309: // the points are on a circle with radius rb and rc
310: int x2 = x0 + ((int) (rb * Math.cos(angle)));
311: int y2 = y0 - ((int) (rb * Math.sin(angle)));
312: int x3 = x0 + ((int) (rc * Math.cos(angle)));
313: int y3 = y0 - ((int) (rc * Math.sin(angle)));
314: setColor(lineColor);
315: line(x0, y0, x3, y3);
316: setColor(dotColor);
317: dot(x2, y2, radius, true);
318: }
319:
320: public int[] getColor(int x, int y) {
321: int[] c = new int[3];
322: return grid.getPixel(x, y, c);
323: }
324:
325: public void dot(int x, int y, int radius, boolean filled) {
326: if (filled) {
327: for (int r = radius; r >= 0; r--)
328: ymageToolCircle.circle(this , x, y, r);
329: } else {
330: ymageToolCircle.circle(this , x, y, radius);
331: }
332: }
333:
334: public void arc(int x, int y, int innerRadius, int outerRadius,
335: int fromArc, int toArc) {
336: for (int r = innerRadius; r <= outerRadius; r++)
337: ymageToolCircle.circle(this , x, y, r, fromArc, toArc);
338: }
339:
340: public void arcLine(int cx, int cy, int innerRadius,
341: int outerRadius, int angle) {
342: int xi = cx
343: + (int) (innerRadius * Math.cos(Math.PI * angle / 180));
344: int yi = cy
345: - (int) (innerRadius * Math.sin(Math.PI * angle / 180));
346: int xo = cx
347: + (int) (outerRadius * Math.cos(Math.PI * angle / 180));
348: int yo = cy
349: - (int) (outerRadius * Math.sin(Math.PI * angle / 180));
350: line(xi, yi, xo, yo);
351: }
352:
353: public void arcDot(int cx, int cy, int arcRadius, int angle,
354: int dotRadius) {
355: int x = cx
356: + (int) (arcRadius * Math.cos(Math.PI * angle / 180));
357: int y = cy
358: - (int) (arcRadius * Math.sin(Math.PI * angle / 180));
359: dot(x, y, dotRadius, true);
360: }
361:
362: public void arcArc(int cx, int cy, int arcRadius, int angle,
363: int innerRadius, int outerRadius, int fromArc, int toArc) {
364: int x = cx
365: + (int) (arcRadius * Math.cos(Math.PI * angle / 180));
366: int y = cy
367: - (int) (arcRadius * Math.sin(Math.PI * angle / 180));
368: arc(x, y, innerRadius, outerRadius, fromArc, toArc);
369: }
370:
371: /**
372: * inserts an image into the ymageMatrix
373: * @param bitmap the bitmap to be inserted
374: * @param x the x value of the upper left coordinate in the ymageMatrix where the bitmap will be placed
375: * @param y the y value of the upper left coordinate in the ymageMatrix where the bitmap will be placed
376: * @author Marc Nause
377: */
378: public void insertBitmap(BufferedImage bitmap, int x, int y) {
379: insertBitmap(bitmap, x, y, -1);
380: }
381:
382: /**
383: * inserts an image into the ymageMatrix
384: * @param bitmap the bitmap to be inserted
385: * @param x the x value of the upper left coordinate in the ymageMatrix where the bitmap will be placed
386: * @param y the y value of the upper left coordinate in the ymageMatrix where the bitmap will be placed
387: * @param filter chooses filter
388: * @author Marc Nause
389: */
390: public void insertBitmap(BufferedImage bitmap, int x, int y,
391: byte filter) {
392: insertBitmap(bitmap, x, y, -1, filter);
393: }
394:
395: /**
396: * inserts an image into the ymageMatrix where all pixels that have the same RGB value as the
397: * pixel at (xx, yy) are transparent
398: * @param bitmap the bitmap to be inserted
399: * @param x the x value of the upper left coordinate in the ymageMatrix where the bitmap will be placed
400: * @param y the y value of the upper left coordinate in the ymageMatrix where the bitmap will be placed
401: * @param xx the x value of the pixel that determines which color is transparent
402: * @param yy the y value of the pixel that determines which color is transparent
403: * @author Marc Nause
404: */
405: public void insertBitmap(BufferedImage bitmap, int x, int y,
406: int xx, int yy) {
407: insertBitmap(bitmap, x, y, bitmap.getRGB(xx, yy));
408: }
409:
410: /**
411: * inserts an image into the ymageMatrix where all pixels that have the same RGB value as the
412: * pixel at (xx, yy) are transparent
413: * @param bitmap the bitmap to be inserted
414: * @param x the x value of the upper left coordinate in the ymageMatrix where the bitmap will be placed
415: * @param y the y value of the upper left coordinate in the ymageMatrix where the bitmap will be placed
416: * @param xx the x value of the pixel that determines which color is transparent
417: * @param yy the y value of the pixel that determines which color is transparent
418: * @param filter chooses filter
419: * @author Marc Nause
420: */
421: public void insertBitmap(BufferedImage bitmap, int x, int y,
422: int xx, int yy, byte filter) {
423: insertBitmap(bitmap, x, y, bitmap.getRGB(xx, yy), filter);
424: }
425:
426: /**
427: * inserts an image into the ymageMatrix where all pixels that have a special RGB value
428: * pixel at (xx, yy) are transparent
429: * @param bitmap the bitmap to be inserted
430: * @param x the x value of the upper left coordinate in the ymageMatrix where the bitmap will be placed
431: * @param y the y value of the upper left coordinate in the ymageMatrix where the bitmap will be placed
432: * @param rgb the RGB value that will be transparent
433: * @author Marc Nause
434: */
435: public void insertBitmap(BufferedImage bitmap, int x, int y,
436: int transRGB) {
437: int heightSrc = bitmap.getHeight();
438: int widthSrc = bitmap.getWidth();
439: int heightTgt = height;
440: int widthTgt = width;
441:
442: int rgb;
443: for (int i = 0; i < heightSrc; i++) {
444: for (int j = 0; j < widthSrc; j++) {
445: // pixel in legal area?
446: if (j + x >= 0 && i + y >= 0 && i + y < heightTgt
447: && j + x < widthTgt) {
448: rgb = bitmap.getRGB(j, i);
449: if (rgb != transRGB) {
450: image.setRGB(j + x, i + y, rgb);
451: }
452: }
453: }
454: }
455: }
456:
457: /**
458: * inserts an image into the ymageMatrix where all pixels that have a special RGB value
459: * pixel at (xx, yy) are transparent
460: * @param bitmap the bitmap to be inserted
461: * @param x the x value of the upper left coordinate in the ymageMatrix where the bitmap will be placed
462: * @param y the y value of the upper left coordinate in the ymageMatrix where the bitmap will be placed
463: * @param rgb the RGB value that will be transparent
464: * @param filter chooses filter
465: * @author Marc Nause
466: */
467: public void insertBitmap(BufferedImage bitmap, int x, int y,
468: int transRGB, byte filter) {
469: insertBitmap(bitmap, x, y, transRGB);
470:
471: int bitmapWidth = bitmap.getWidth();
472: int bitmapHeight = bitmap.getHeight();
473:
474: if (filter == FILTER_ANTIALIASING) {
475:
476: int transX = -1;
477: int transY = -1;
478: int imageWidth = image.getWidth();
479: int imageHeight = image.getHeight();
480:
481: // find first pixel in bitmap that equals transRGB
482: // and also lies in area of image that will be covered by bitmap
483: int i = 0;
484: int j = 0;
485: boolean found = false;
486: while ((i < bitmapWidth) && (i + x < imageWidth) && !found) {
487: while ((j < bitmapHeight) && (j + y < imageHeight)
488: && !found) {
489: if (bitmap.getRGB(i, j) == transRGB) {
490: transX = i;
491: transY = j;
492: }
493: j++;
494: }
495: i++;
496: }
497:
498: // if there is a transparent pixel in the bitmap that covers an area
499: // of the image, the fiter will be used. If no such pixel has been found that
500: // means that there either is no transparent pixel in the bitmap or part
501: // of the bitmap that covers part of tha image is not within the borders of
502: // the image (i.e. bitmap is larger than image)
503: if (transX != -1) {
504: filter(x - 1, y - 1, x + bitmapWidth, y + bitmapHeight,
505: filter, image.getRGB(transX + x, transY + y));
506: }
507:
508: } else {
509: filter(x - 1, y - 1, x + bitmapWidth, y + bitmapHeight,
510: filter, -1);
511: }
512:
513: }
514:
515: /**
516: * antialiasing filter for a square part of the ymageMatrix
517: * @param lox x value for left upper coordinate
518: * @param loy y value for left upper coordinate
519: * @param rux x value for right lower coordinate
520: * @param ruy y value for right lower coordinate
521: * @param rgb color of background
522: * @author Marc Nause
523: */
524: public void antialiasing(int lox, int loy, int rux, int ruy,
525: int bgcolor) {
526: filter(lox, loy, rux, ruy, FILTER_ANTIALIASING, bgcolor);
527: }
528:
529: /**
530: * blur filter for a square part of the ymageMatrix
531: * @param lox x value for left upper coordinate
532: * @param loy y value for left upper coordinate
533: * @param rux x value for right lower coordinate
534: * @param ruy y value for right lower coordinate
535: * @author Marc Nause
536: */
537: public void blur(int lox, int loy, int rux, int ruy) {
538: filter(lox, loy, rux, ruy, FILTER_BLUR, -1);
539: }
540:
541: /**
542: * invert filter for a square part of the ymageMatrix
543: * @param lox x value for left upper coordinate
544: * @param loy y value for left upper coordinate
545: * @param rux x value for right lower coordinate
546: * @param ruy y value for right lower coordinate
547: * @author Marc Nause
548: */
549: public void invert(int lox, int loy, int rux, int ruy) {
550: filter(lox, loy, rux, ruy, FILTER_INVERT, -1);
551: }
552:
553: /**
554: * filter for a square part of the ymageMatrix
555: * @param lox x value for left upper coordinate
556: * @param loy y value for left upper coordinate
557: * @param rux x value for right lower coordinate
558: * @param ruy y value for right lower coordinate
559: * @param filter chooses filter
560: * @author Marc Nause
561: */
562: private void filter(int lox, int loy, int rux, int ruy,
563: byte filter, int bgcolor) {
564:
565: // taking care that all values are legal
566: if (lox < 0) {
567: lox = 0;
568: }
569: if (loy < 0) {
570: loy = 0;
571: }
572: if (rux < 0) {
573: rux = 0;
574: }
575: if (ruy < 0) {
576: ruy = 0;
577: }
578: if (lox > width) {
579: lox = width - 1;
580: }
581: if (loy > height) {
582: loy = height - 1;
583: }
584: if (rux > width) {
585: rux = width - 1;
586: }
587: if (ruy > height) {
588: ruy = height - 1;
589: }
590: if (lox > rux) {
591: int tmp = lox;
592: lox = rux;
593: rux = tmp;
594: }
595: if (loy > ruy) {
596: int tmp = loy;
597: loy = ruy;
598: ruy = tmp;
599: }
600:
601: int numberOfNeighbours = 0;
602: int rgbR = 0;
603: int rgbG = 0;
604: int rgbB = 0;
605: int rgb = 0;
606: int width2 = rux - lox + 1;
607: int height2 = ruy - loy + 1;
608: boolean border = false;
609: BufferedImage image2 = new BufferedImage(width2, height2,
610: BufferedImage.TYPE_INT_RGB);
611:
612: for (int i = lox; i < rux + 1; i++) {
613: for (int j = loy; j < ruy + 1; j++) {
614:
615: numberOfNeighbours = 0;
616: rgbR = 0;
617: rgbG = 0;
618: rgbB = 0;
619:
620: if (filter == FILTER_ANTIALIASING
621: || filter == FILTER_BLUR) {
622: // taking samples from neighbours of pixel
623: if (i > lox) {
624: rgb = image.getRGB(i - 1, j);
625: if (rgb == bgcolor) {
626: border = true;
627: }
628: rgbR += rgb >> 16 & 0xff;
629: rgbG += rgb >> 8 & 0xff;
630: rgbB += rgb & 0xff;
631: numberOfNeighbours++;
632: }
633: if (j > loy) {
634: rgb = image.getRGB(i, j - 1);
635: if (rgb == bgcolor) {
636: border = true;
637: }
638: rgbR += rgb >> 16 & 0xff;
639: rgbG += rgb >> 8 & 0xff;
640: rgbB += rgb & 0xff;
641: numberOfNeighbours++;
642: }
643: if (i < width - 1) {
644: rgb = image.getRGB(i + 1, j);
645: if (rgb == bgcolor) {
646: border = true;
647: }
648: rgbR += rgb >> 16 & 0xff;
649: rgbG += rgb >> 8 & 0xff;
650: rgbB += rgb & 0xff;
651: numberOfNeighbours++;
652: }
653: if (i < height - 1) {
654: rgb = image.getRGB(i, j + 1);
655: if (rgb == bgcolor) {
656: border = true;
657: }
658: rgbR += rgb >> 16 & 0xff;
659: rgbG += rgb >> 8 & 0xff;
660: rgbB += rgb & 0xff;
661: numberOfNeighbours++;
662: }
663:
664: }
665:
666: rgb = image.getRGB(i, j);
667:
668: // add value of pixel
669: // in case filter is used for antialiasing this will only be done if
670: // the pixel is on the edge to the background color
671: if ((filter == FILTER_ANTIALIASING && border)
672: || (filter == FILTER_BLUR)) {
673: rgbR += (rgb >> 16 & 0xff);
674: rgbG += (rgb >> 8 & 0xff);
675: rgbB += (rgb & 0xff);
676: numberOfNeighbours++;
677: border = false;
678: }
679: // set to value of pixel => keep value
680: else if (filter == FILTER_ANTIALIASING) {
681: rgbR = (rgb >> 16 & 0xff);
682: rgbG = (rgb >> 8 & 0xff);
683: rgbB = (rgb & 0xff);
684: numberOfNeighbours = 1;
685: }
686: // set value of pixel to inverted value (using XOR)
687: else if (filter == FILTER_INVERT) {
688: rgb = rgb ^ 0xffffff;
689: rgbR = (rgb >> 16 & 0xff);
690: rgbG = (rgb >> 8 & 0xff);
691: rgbB = (rgb & 0xff);
692: numberOfNeighbours = 1;
693: }
694:
695: // calculating the average
696: rgbR = (int) (rgbR / numberOfNeighbours);
697: rgbG = (int) (rgbG / numberOfNeighbours);
698: rgbB = (int) (rgbB / numberOfNeighbours);
699:
700: rgb = (rgbR << 16) | (rgbG << 8) | rgbB;
701:
702: image2.setRGB(i - lox, j - loy, rgb);
703: }
704: }
705:
706: // insert new version of area into image
707: insertBitmap(image2, lox, loy);
708:
709: }
710:
711: public static void demoPaint(ymageMatrix m) {
712: m.setColor(GREY);
713: m.line(0, 70, 100, 70);
714: ymageToolPrint.print(m, 0, 65, 0, "Grey", -1);
715: m.line(65, 0, 65, 300);
716: m.setColor(RED);
717: m.line(0, 90, 100, 90);
718: ymageToolPrint.print(m, 0, 85, 0, "Red", -1);
719: m.line(70, 0, 70, 300);
720: m.setColor(GREEN);
721: m.line(0, 110, 100, 110);
722: ymageToolPrint.print(m, 0, 105, 0, "Green", -1);
723: m.line(75, 0, 75, 300);
724: m.setColor(BLUE);
725: m.line(0, 130, 100, 130);
726: ymageToolPrint.print(m, 0, 125, 0, "Blue", -1);
727: m.line(80, 0, 80, 300);
728: }
729:
730: /*
731: private static class imageBuffer {
732: protected BufferedImage image;
733: protected long access;
734: public imageBuffer(BufferedImage image) {
735: this.image = image;
736: this.access = System.currentTimeMillis();
737: }
738: public boolean sameSize(int width, int height) {
739: return (this.image.getWidth() == width) && (this.image.getHeight() == height);
740: }
741: public boolean olderThan(long timeout) {
742: return System.currentTimeMillis() - this.access > timeout;
743: }
744: }
745: private static final ArrayList imagePool = new ArrayList();
746: private static BufferedImage imageFromPool(int width, int height, long timeout) {
747: // returns an Image object from the image pool
748: // if the pooled Image was created recently (before timeout), it is not used
749: synchronized (imagePool) {
750: imageBuffer buffer;
751: for (int i = 0; i < imagePool.size(); i++) {
752: buffer = (imageBuffer) imagePool.get(i);
753: if ((buffer.sameSize(width, height)) && (buffer.olderThan(timeout))) {
754: // use this buffer
755: System.out.println("### using imageBuffer from pool " + i);
756: buffer.access = System.currentTimeMillis();
757: return buffer.image;
758: }
759: }
760: // no buffered image found, create a new one
761: buffer = new imageBuffer(new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB));
762: imagePool.add(buffer);
763: return buffer.image;
764: }
765: }
766: */
767: private static class sbbBuffer {
768: protected serverByteBuffer buffer;
769: protected int pixel;
770: protected long access;
771:
772: public sbbBuffer(int width, int height) {
773: this .buffer = new serverByteBuffer();
774: this .access = System.currentTimeMillis();
775: this .pixel = width * height;
776: }
777:
778: public boolean enoughSize(int width, int height) {
779: return this .pixel >= width * height;
780: }
781:
782: public boolean olderThan(long timeout) {
783: return System.currentTimeMillis() - this .access > timeout;
784: }
785: }
786:
787: private static final ArrayList<sbbBuffer> sbbPool = new ArrayList<sbbBuffer>();
788:
789: private static serverByteBuffer sbbFromPool(int width, int height,
790: long timeout) {
791: // returns an Image object from the image pool
792: // if the pooled Image was created recently (before timeout), it is not used
793: synchronized (sbbPool) {
794: sbbBuffer b;
795: for (int i = 0; i < sbbPool.size(); i++) {
796: b = sbbPool.get(i);
797: if ((b.enoughSize(width, height))
798: && (b.olderThan(timeout))) {
799: // use this buffer
800: b.access = System.currentTimeMillis();
801: b.buffer.clear(); // this makes only sense if the byteBuffer keeps its buffer
802: return b.buffer;
803: }
804: }
805: // no buffered image found, create a new one
806: b = new sbbBuffer(width, height);
807: sbbPool.add(b);
808: return b.buffer;
809: }
810: }
811:
812: public static serverByteBuffer exportImage(BufferedImage image,
813: String targetExt) {
814: // generate an byte array from the given image
815: //serverByteBuffer baos = new serverByteBuffer();
816: serverByteBuffer baos = sbbFromPool(image.getWidth(), image
817: .getHeight(), 1000);
818: try {
819: ImageIO.write(image, targetExt, baos);
820: return baos;
821: } catch (IOException e) {
822: // should not happen
823: e.printStackTrace();
824: return null;
825: }
826: }
827:
828: public static void main(String[] args) {
829: // go into headless awt mode
830: System.setProperty("java.awt.headless", "true");
831:
832: ymageMatrix m = new ymageMatrix(200, 300, MODE_SUB, "FFFFFF");
833: demoPaint(m);
834: File file = new File("/Users/admin/Desktop/testimage.png");
835: try {
836: FileOutputStream fos = new FileOutputStream(file);
837: ImageIO.write(m.getImage(), "png", fos);
838: fos.close();
839: } catch (IOException e) {
840: }
841:
842: // open file automatically, works only on Mac OS X
843: /*
844: Process p = null;
845: try {
846: p = Runtime.getRuntime().exec(new String[] {"/usr/bin/osascript", "-e", "open \"" + args[0] + "\""});
847: } catch (java.io.IOException e) {
848: e.printStackTrace();
849: }
850: try {
851: p.waitFor();
852: } catch (InterruptedException e) {
853: e.printStackTrace();
854: }
855: */
856: }
857:
858: }
|