f343d5e7570c1dcd04a0fefa4b8c2f47ae666a35
[jalview.git] / src / org / jibble / epsgraphics / EpsDocument.java
1 /*
2  * Jalview - A Sequence Alignment Editor and Viewer (Version 2.8.2)
3  * Copyright (C) 2014 The Jalview Authors
4  * 
5  * This file is part of Jalview.
6  * 
7  * Jalview is free software: you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License 
9  * as published by the Free Software Foundation, either version 3
10  * of the License, or (at your option) any later version.
11  *  
12  * Jalview is distributed in the hope that it will be useful, but 
13  * WITHOUT ANY WARRANTY; without even the implied warranty 
14  * of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
15  * PURPOSE.  See the GNU General Public License for more details.
16  * 
17  * You should have received a copy of the GNU General Public License
18  * along with Jalview.  If not, see <http://www.gnu.org/licenses/>.
19  * The Jalview Authors are detailed in the 'AUTHORS' file.
20  */
21 package org.jibble.epsgraphics;
22
23 import java.io.*;
24 import java.util.*;
25
26 /**
27  * This represents an EPS document. Several EpsGraphics2D objects may point to
28  * the same EpsDocument.
29  * <p>
30  * Copyright Paul Mutton, <a
31  * href="http://www.jibble.org/">http://www.jibble.org/</a>
32  * 
33  */
34 public class EpsDocument
35 {
36
37   /**
38    * Constructs an empty EpsDevice.
39    */
40   public EpsDocument(String title)
41   {
42     _title = title;
43     minX = Float.POSITIVE_INFINITY;
44     minY = Float.POSITIVE_INFINITY;
45     maxX = Float.NEGATIVE_INFINITY;
46     maxY = Float.NEGATIVE_INFINITY;
47     _stringWriter = new StringWriter();
48     _bufferedWriter = new BufferedWriter(_stringWriter);
49   }
50
51   /**
52    * Constructs an empty EpsDevice that writes directly to a file. Bounds must
53    * be set before use.
54    */
55   public EpsDocument(String title, OutputStream outputStream, int minX,
56           int minY, int maxX, int maxY) throws IOException
57   {
58     _title = title;
59     this.minX = minX;
60     this.minY = minY;
61     this.maxX = maxX;
62     this.maxY = maxY;
63     _bufferedWriter = new BufferedWriter(new OutputStreamWriter(
64             outputStream));
65     write(_bufferedWriter);
66   }
67
68   /**
69    * Returns the title of the EPS document.
70    */
71   public synchronized String getTitle()
72   {
73     return _title;
74   }
75
76   /**
77    * Updates the bounds of the current EPS document.
78    */
79   public synchronized void updateBounds(double x, double y)
80   {
81     if (x > maxX)
82     {
83       maxX = (float) x;
84     }
85     if (x < minX)
86     {
87       minX = (float) x;
88     }
89     if (y > maxY)
90     {
91       maxY = (float) y;
92     }
93     if (y < minY)
94     {
95       minY = (float) y;
96     }
97   }
98
99   /**
100    * Appends a line to the EpsDocument. A new line character is added to the end
101    * of the line when it is added.
102    */
103   public synchronized void append(EpsGraphics2D g, String line)
104   {
105     if (_lastG == null)
106     {
107       _lastG = g;
108     }
109     else if (g != _lastG)
110     {
111       EpsGraphics2D lastG = _lastG;
112       _lastG = g;
113       // We are being drawn on with a different EpsGraphics2D context.
114       // We may need to update the clip, etc from this new context.
115       if (g.getClip() != lastG.getClip())
116       {
117         g.setClip(g.getClip());
118       }
119       if (!g.getColor().equals(lastG.getColor()))
120       {
121         g.setColor(g.getColor());
122       }
123       if (!g.getBackground().equals(lastG.getBackground()))
124       {
125         g.setBackground(g.getBackground());
126       }
127       // We don't need this, as this only affects the stroke and font,
128       // which are dealt with separately later on.
129       // if (!g.getTransform().equals(lastG.getTransform())) {
130       // g.setTransform(g.getTransform());
131       // }
132       if (!g.getPaint().equals(lastG.getPaint()))
133       {
134         g.setPaint(g.getPaint());
135       }
136       if (!g.getComposite().equals(lastG.getComposite()))
137       {
138         g.setComposite(g.getComposite());
139       }
140       if (!g.getComposite().equals(lastG.getComposite()))
141       {
142         g.setComposite(g.getComposite());
143       }
144       if (!g.getFont().equals(lastG.getFont()))
145       {
146         g.setFont(g.getFont());
147       }
148       if (!g.getStroke().equals(lastG.getStroke()))
149       {
150         g.setStroke(g.getStroke());
151       }
152     }
153     _lastG = g;
154
155     try
156     {
157       _bufferedWriter.write(line + "\n");
158     } catch (IOException e)
159     {
160       throw new EpsException("Could not write to the output file: " + e);
161     }
162   }
163
164   /**
165    * Outputs the contents of the EPS document to the specified Writer, complete
166    * with headers and bounding box.
167    */
168   public synchronized void write(Writer writer) throws IOException
169   {
170     float offsetX = -minX;
171     float offsetY = -minY;
172
173     writer.write("%!PS-Adobe-3.0 EPSF-3.0\n");
174     writer.write("%%Creator: Jalview "
175             + jalview.bin.Cache.getProperty("VERSION") + " \n");
176     writer.write("%%Title: " + _title + "\n");
177     writer.write("%%CreationDate: " + new Date() + "\n");
178     writer.write("%%BoundingBox: 0 0 " + ((int) Math.ceil(maxX + offsetX))
179             + " " + ((int) Math.ceil(maxY + offsetY)) + "\n");
180     writer.write("%%DocumentData: Clean7Bit\n");
181     writer.write("%%DocumentProcessColors: Black\n");
182     writer.write("%%ColorUsage: Color\n");
183     writer.write("%%Origin: 0 0\n");
184     writer.write("%%Pages: 1\n");
185     writer.write("%%Page: 1 1\n");
186     writer.write("%%EndComments\n\n");
187
188     writer.write("gsave\n");
189
190     if (_stringWriter != null)
191     {
192       writer.write(offsetX + " " + (offsetY) + " translate\n");
193
194       _bufferedWriter.flush();
195       StringBuffer buffer = _stringWriter.getBuffer();
196       for (int i = 0; i < buffer.length(); i++)
197       {
198         writer.write(buffer.charAt(i));
199       }
200
201       writeFooter(writer);
202     }
203     else
204     {
205       writer.write(offsetX + " " + ((maxY - minY) - offsetY)
206               + " translate\n");
207     }
208
209     writer.flush();
210   }
211
212   private void writeFooter(Writer writer) throws IOException
213   {
214     writer.write("grestore\n");
215     if (isClipSet())
216     {
217       writer.write("grestore\n");
218     }
219     writer.write("showpage\n");
220     writer.write("\n");
221     writer.write("%%EOF");
222     writer.flush();
223   }
224
225   public synchronized void flush() throws IOException
226   {
227     _bufferedWriter.flush();
228   }
229
230   public synchronized void close() throws IOException
231   {
232     if (_stringWriter == null)
233     {
234       writeFooter(_bufferedWriter);
235       _bufferedWriter.flush();
236       _bufferedWriter.close();
237     }
238   }
239
240   public boolean isClipSet()
241   {
242     return _isClipSet;
243   }
244
245   public void setClipSet(boolean isClipSet)
246   {
247     _isClipSet = isClipSet;
248   }
249
250   private float minX;
251
252   private float minY;
253
254   private float maxX;
255
256   private float maxY;
257
258   private boolean _isClipSet = false;
259
260   private String _title;
261
262   private StringWriter _stringWriter;
263
264   private BufferedWriter _bufferedWriter = null;
265
266   // We need to remember which was the last EpsGraphics2D object to use
267   // us, as we need to replace the clipping region if another EpsGraphics2D
268   // object tries to use us.
269   private EpsGraphics2D _lastG = null;
270
271 }