1 /* ============================================================
2  * JRobin : Pure java implementation of RRDTool's functionality
3  * ============================================================
4  *
5  * Project Info:  http://www.jrobin.org
6  * Project Lead:  Sasa Markovic (saxon@jrobin.org)
7  *
8  * Developers:    Sasa Markovic (saxon@jrobin.org)
9  *
10  *
11  * (C) Copyright 2003-2005, by Sasa Markovic.
12  *
13  * This library is free software; you can redistribute it and/or modify it under the terms
14  * of the GNU Lesser General Public License as published by the Free Software Foundation;
15  * either version 2.1 of the License, or (at your option) any later version.
16  *
17  * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
18  * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
19  * See the GNU Lesser General Public License for more details.
20  *
21  * You should have received a copy of the GNU Lesser General Public License along with this
22  * library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
23  * Boston, MA 02111-1307, USA.
24  */

25 package org.jrobin.graph;
26
27 import com.sun.image.codec.jpeg.JPEGCodec;
28 import com.sun.image.codec.jpeg.JPEGEncodeParam;
29 import com.sun.image.codec.jpeg.JPEGImageEncoder;
30
31 import javax.imageio.ImageIO;
32 import java.awt.*;
33 import java.awt.font.LineMetrics;
34 import java.awt.geom.AffineTransform;
35 import java.awt.image.BufferedImage;
36 import java.io.*;
37
38 class ImageWorker {
39     private static final String DUMMY_TEXT = "Dummy";
40
41     private BufferedImage img;
42     private Graphics2D gd;
43     private int imgWidth, imgHeight;
44     private AffineTransform aftInitial;
45
46     ImageWorker(int width, int height) {
47         resize(width, height);
48     }
49
50     void resize(int width, int height) {
51         if (gd != null) {
52             gd.dispose();
53         }
54         this.imgWidth = width;
55         this.imgHeight = height;
56         this.img = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
57         this.gd = img.createGraphics();
58         this.aftInitial = gd.getTransform();
59         this.setAntiAliasing(false);
60     }
61
62     void clip(int x, int y, int width, int height) {
63         gd.setClip(x, y, width, height);
64     }
65
66     void transform(int x, int y, double angle) {
67         gd.translate(x, y);
68         gd.rotate(angle);
69     }
70
71     void reset() {
72         gd.setTransform(aftInitial);
73         gd.setClip(0, 0, imgWidth, imgHeight);
74     }
75
76     void fillRect(int x, int y, int width, int height, Paint paint) {
77         gd.setPaint(paint);
78         gd.fillRect(x, y, width, height);
79     }
80
81     void fillPolygon(int[] x, int[] y, Paint paint) {
82         gd.setPaint(paint);
83         gd.fillPolygon(x, y, x.length);
84     }
85
86     void fillPolygon(double[] x, double yBottom, double[] yTop, Paint paint) {
87         gd.setPaint(paint);
88         PathIterator path = new PathIterator(yTop);
89         for (int[] pos = path.getNextPath(); pos != null; pos = path.getNextPath()) {
90             int start = pos[0], end = pos[1], n = end - start;
91             int[] xDev = new int[n + 2], yDev = new int[n + 2];
92             for (int i = start; i < end; i++) {
93                 xDev[i - start] = (int) x[i];
94                 yDev[i - start] = (int) yTop[i];
95             }
96             xDev[n] = xDev[n - 1];
97             xDev[n + 1] = xDev[0];
98             yDev[n] = yDev[n + 1] = (int) yBottom;
99             gd.fillPolygon(xDev, yDev, xDev.length);
100             gd.drawPolygon(xDev, yDev, xDev.length);
101         }
102     }
103
104     void fillPolygon(double[] x, double[] yBottom, double[] yTop, Paint paint) {
105         gd.setPaint(paint);
106         PathIterator path = new PathIterator(yTop);
107         for (int[] pos = path.getNextPath(); pos != null; pos = path.getNextPath()) {
108             int start = pos[0], end = pos[1], n = end - start;
109             int[] xDev = new int[n * 2], yDev = new int[n * 2];
110             for (int i = start; i < end; i++) {
111                 int ix1 = i - start, ix2 = n * 2 - 1 - i + start;
112                 xDev[ix1] = xDev[ix2] = (int) x[i];
113                 yDev[ix1] = (int) yTop[i];
114                 yDev[ix2] = (int) yBottom[i];
115             }
116             gd.fillPolygon(xDev, yDev, xDev.length);
117             gd.drawPolygon(xDev, yDev, xDev.length);
118         }
119     }
120
121
122     void drawLine(int x1, int y1, int x2, int y2, Paint paint, Stroke stroke) {
123         gd.setStroke(stroke);
124         gd.setPaint(paint);
125         gd.drawLine(x1, y1, x2, y2);
126     }
127
128     void drawPolyline(int[] x, int[] y, Paint paint, Stroke stroke) {
129         gd.setStroke(stroke);
130         gd.setPaint(paint);
131         gd.drawPolyline(x, y, x.length);
132     }
133
134     void drawPolyline(double[] x, double[] y, Paint paint, Stroke stroke) {
135         gd.setPaint(paint);
136         gd.setStroke(stroke);
137         PathIterator path = new PathIterator(y);
138         for (int[] pos = path.getNextPath(); pos != null; pos = path.getNextPath()) {
139             int start = pos[0], end = pos[1];
140             int[] xDev = new int[end - start], yDev = new int[end - start];
141             for (int i = start; i < end; i++) {
142                 xDev[i - start] = (int) x[i];
143                 yDev[i - start] = (int) y[i];
144             }
145             gd.drawPolyline(xDev, yDev, xDev.length);
146         }
147     }
148
149     void drawString(String text, int x, int y, Font font, Paint paint) {
150         gd.setFont(font);
151         gd.setPaint(paint);
152         gd.drawString(text, x, y);
153     }
154
155     double getFontAscent(Font font) {
156         LineMetrics lm = font.getLineMetrics(DUMMY_TEXT, gd.getFontRenderContext());
157         return lm.getAscent();
158     }
159
160     double getFontHeight(Font font) {
161         LineMetrics lm = font.getLineMetrics(DUMMY_TEXT, gd.getFontRenderContext());
162         return lm.getAscent() + lm.getDescent();
163     }
164
165     double getStringWidth(String text, Font font) {
166         return font.getStringBounds(text, 0, text.length(), gd.getFontRenderContext()).getBounds().getWidth();
167     }
168
169     void setAntiAliasing(boolean enable) {
170         gd.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
171                 enable ? RenderingHints.VALUE_ANTIALIAS_ON : RenderingHints.VALUE_ANTIALIAS_OFF);
172         gd.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
173         gd.setRenderingHint(RenderingHints.KEY_RENDERING,RenderingHints.VALUE_RENDER_QUALITY);
174     }
175
176     void dispose() {
177         gd.dispose();
178     }
179
180     void saveImage(OutputStream stream, String type, float quality) throws IOException {
181         if (type.equalsIgnoreCase("png")) {
182             ImageIO.write(img, "png", stream);
183         }
184         else if (type.equalsIgnoreCase("gif")) {
185             GifEncoder gifEncoder = new GifEncoder(img);
186             gifEncoder.encode(stream);
187         }
188         else if (type.equalsIgnoreCase("jpg") || type.equalsIgnoreCase("jpeg")) {
189             JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(stream);
190             JPEGEncodeParam param = encoder.getDefaultJPEGEncodeParam(img);
191             param.setQuality(quality, false);
192             encoder.setJPEGEncodeParam(param);
193             encoder.encode(img);
194         }
195         else {
196             throw new IOException("Unsupported image format: " + type);
197         }
198         stream.flush();
199     }
200
201     byte[] saveImage(String path, String type, float quality) throws IOException {
202         byte[] bytes = getImageBytes(type, quality);
203         RandomAccessFile f = new RandomAccessFile(path, "rw");
204         try {
205             f.write(bytes);
206             return bytes;
207         }
208         finally {
209             f.close();
210         }
211     }
212
213     byte[] getImageBytes(String type, float quality) throws IOException {
214         ByteArrayOutputStream stream = new ByteArrayOutputStream();
215         try {
216             saveImage(stream, type, quality);
217             return stream.toByteArray();
218         }
219         finally {
220             stream.close();
221         }
222     }
223
224     public void loadImage(String imageFile) throws IOException {
225         BufferedImage wpImage = ImageIO.read(new File(imageFile));
226         TexturePaint paint = new TexturePaint(wpImage, new Rectangle(0, 0, wpImage.getWidth(), wpImage.getHeight()));
227         gd.setPaint(paint);
228         gd.fillRect(0, 0, wpImage.getWidth(), wpImage.getHeight());
229     }
230 }
231