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