eps output facility
[jalview.git] / src / org / jibble / epsgraphics / EpsDocument.java
1 /* \r
2 Copyright Paul James Mutton, 2001-2004, http://www.jibble.org/\r
3 \r
4 This file is part of EpsGraphics2D.\r
5 \r
6 This software is dual-licensed, allowing you to choose between the GNU\r
7 General Public License (GPL) and the www.jibble.org Commercial License.\r
8 Since the GPL may be too restrictive for use in a proprietary application,\r
9 a commercial license is also provided. Full license information can be\r
10 found at http://www.jibble.org/licenses/\r
11 \r
12 $Author$\r
13 $Id$\r
14 \r
15 */\r
16 \r
17 package org.jibble.epsgraphics;\r
18 \r
19 import java.util.*;\r
20 import java.io.*;\r
21 \r
22 \r
23 /**\r
24  * This represents an EPS document. Several EpsGraphics2D objects may point\r
25  * to the same EpsDocument.\r
26  *  <p>\r
27  * Copyright Paul Mutton,\r
28  *           <a href="http://www.jibble.org/">http://www.jibble.org/</a>\r
29  * \r
30  */\r
31 public class EpsDocument {\r
32     \r
33     \r
34     /**\r
35      * Constructs an empty EpsDevice.\r
36      */\r
37     public EpsDocument(String title) {\r
38         _title = title;\r
39         minX = Float.POSITIVE_INFINITY;\r
40         minY = Float.POSITIVE_INFINITY;\r
41         maxX = Float.NEGATIVE_INFINITY;\r
42         maxY = Float.NEGATIVE_INFINITY;\r
43         _stringWriter = new StringWriter();\r
44         _bufferedWriter = new BufferedWriter(_stringWriter);\r
45     }\r
46     \r
47     /**\r
48      * Constructs an empty EpsDevice that writes directly to a file.\r
49      * Bounds must be set before use.\r
50      */\r
51     public EpsDocument(String title, OutputStream outputStream, int minX, int minY, int maxX, int maxY) throws IOException {\r
52         _title = title;\r
53         this.minX = minX;\r
54         this.minY = minY;\r
55         this.maxX = maxX;\r
56         this.maxY = maxY;\r
57         _bufferedWriter = new BufferedWriter(new OutputStreamWriter(outputStream));\r
58         write(_bufferedWriter);\r
59     }\r
60     \r
61     \r
62     /**\r
63      * Returns the title of the EPS document.\r
64      */\r
65     public synchronized String getTitle() {\r
66         return _title;\r
67     }\r
68     \r
69     \r
70     /**\r
71      * Updates the bounds of the current EPS document.\r
72      */\r
73     public synchronized void updateBounds(double x, double y) {\r
74         if (x > maxX) {\r
75             maxX = (float) x;\r
76         }\r
77         if (x < minX) {\r
78             minX = (float) x;\r
79         }\r
80         if (y > maxY) {\r
81             maxY = (float) y;\r
82         }\r
83         if (y < minY) {\r
84             minY = (float) y;\r
85         }\r
86     }\r
87     \r
88     \r
89     /**\r
90      * Appends a line to the EpsDocument.  A new line character is added\r
91      * to the end of the line when it is added.\r
92      */\r
93     public synchronized void append(EpsGraphics2D g, String line) {\r
94         if (_lastG == null) {\r
95             _lastG = g;\r
96         }\r
97         else if (g != _lastG) {\r
98             EpsGraphics2D lastG = _lastG;\r
99             _lastG = g;\r
100             // We are being drawn on with a different EpsGraphics2D context.\r
101             // We may need to update the clip, etc from this new context.\r
102             if (g.getClip() != lastG.getClip()) {\r
103                 g.setClip(g.getClip());\r
104             }\r
105             if (!g.getColor().equals(lastG.getColor())) {\r
106                 g.setColor(g.getColor());\r
107             }\r
108             if (!g.getBackground().equals(lastG.getBackground())) {\r
109                 g.setBackground(g.getBackground());\r
110             }\r
111             // We don't need this, as this only affects the stroke and font,\r
112             // which are dealt with separately later on.\r
113             //if (!g.getTransform().equals(lastG.getTransform())) {\r
114             //    g.setTransform(g.getTransform());\r
115             //}\r
116             if (!g.getPaint().equals(lastG.getPaint())) {\r
117                 g.setPaint(g.getPaint());\r
118             }\r
119             if (!g.getComposite().equals(lastG.getComposite())) {\r
120                 g.setComposite(g.getComposite());\r
121             }\r
122             if (!g.getComposite().equals(lastG.getComposite())) {\r
123                 g.setComposite(g.getComposite());\r
124             }\r
125             if (!g.getFont().equals(lastG.getFont())) {\r
126                 g.setFont(g.getFont());\r
127             }\r
128             if (!g.getStroke().equals(lastG.getStroke())) {\r
129                 g.setStroke(g.getStroke());\r
130             }\r
131         }\r
132         _lastG = g;\r
133         \r
134         try {\r
135             _bufferedWriter.write(line + "\n");\r
136         }\r
137         catch (IOException e) {\r
138             throw new EpsException("Could not write to the output file: " + e);\r
139         }\r
140     }\r
141     \r
142     \r
143     /**\r
144      * Outputs the contents of the EPS document to the specified\r
145      * Writer, complete with headers and bounding box.\r
146      */\r
147     public synchronized void write(Writer writer) throws IOException {\r
148         float offsetX = -minX;\r
149         float offsetY = -minY;\r
150         \r
151         writer.write("%!PS-Adobe-3.0 EPSF-3.0\n");\r
152         writer.write("%%Creator: EpsGraphics2D " + EpsGraphics2D.VERSION + " by Paul Mutton, http://www.jibble.org/\n");\r
153         writer.write("%%Title: " + _title + "\n");\r
154         writer.write("%%CreationDate: " + new Date() + "\n");\r
155         writer.write("%%BoundingBox: 0 0 " + ((int) Math.ceil(maxX + offsetX)) + " " + ((int) Math.ceil(maxY + offsetY)) + "\n");\r
156         writer.write("%%DocumentData: Clean7Bit\n");\r
157         writer.write("%%DocumentProcessColors: Black\n");\r
158         writer.write("%%ColorUsage: Color\n");\r
159         writer.write("%%Origin: 0 0\n");\r
160         writer.write("%%Pages: 1\n");\r
161         writer.write("%%Page: 1 1\n");\r
162         writer.write("%%EndComments\n\n");\r
163         \r
164         writer.write("gsave\n");\r
165         \r
166         if (_stringWriter != null) {\r
167             writer.write(offsetX + " " + (offsetY) + " translate\n");\r
168             \r
169             _bufferedWriter.flush();\r
170             StringBuffer buffer = _stringWriter.getBuffer();\r
171             for (int i = 0; i < buffer.length(); i++) {\r
172                 writer.write(buffer.charAt(i));\r
173             }\r
174             \r
175             writeFooter(writer);\r
176         }\r
177         else {\r
178             writer.write(offsetX + " " + ((maxY - minY) - offsetY) + " translate\n");\r
179         }\r
180         \r
181         writer.flush();\r
182     }\r
183     \r
184     \r
185     private void writeFooter(Writer writer) throws IOException {\r
186         writer.write("grestore\n");\r
187         if (isClipSet()) {\r
188             writer.write("grestore\n");\r
189         }\r
190         writer.write("showpage\n");\r
191         writer.write("\n");\r
192         writer.write("%%EOF");\r
193         writer.flush();\r
194     }\r
195     \r
196     \r
197     public synchronized void flush() throws IOException {\r
198         _bufferedWriter.flush();\r
199     }\r
200     \r
201     public synchronized void close() throws IOException {\r
202         if (_stringWriter == null) {\r
203             writeFooter(_bufferedWriter);\r
204             _bufferedWriter.flush();\r
205             _bufferedWriter.close();\r
206         }\r
207     }\r
208     \r
209     \r
210     public boolean isClipSet() {\r
211         return _isClipSet;\r
212     }\r
213     \r
214     public void setClipSet(boolean isClipSet) {\r
215         _isClipSet = isClipSet;\r
216     }\r
217     \r
218     \r
219     private float minX;\r
220     private float minY;\r
221     private float maxX;\r
222     private float maxY;\r
223     \r
224     private boolean _isClipSet = false;\r
225 \r
226     private String _title;\r
227     private StringWriter _stringWriter;\r
228     private BufferedWriter _bufferedWriter = null;\r
229     \r
230     // We need to remember which was the last EpsGraphics2D object to use\r
231     // us, as we need to replace the clipping region if another EpsGraphics2D\r
232     // object tries to use us.\r
233     private EpsGraphics2D _lastG = null;\r
234     \r
235 }