source: trunk/src/org/expeditee/io/PDF2Writer.java@ 919

Last change on this file since 919 was 919, checked in by jts21, 10 years ago

Added license headers to all files, added full GPL3 license file, moved license header generator script to dev/bin/scripts

File size: 11.9 KB
Line 
1/**
2 * PDF2Writer.java
3 * Copyright (C) 2010 New Zealand Digital Library, http://expeditee.org
4 *
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19package org.expeditee.io;
20
21import java.awt.Color;
22import java.awt.Dimension;
23import java.awt.Image;
24import java.awt.Polygon;
25import java.awt.geom.AffineTransform;
26import java.io.FileOutputStream;
27import java.io.IOException;
28import java.io.Writer;
29import java.util.Collection;
30import java.util.HashSet;
31import java.util.Iterator;
32import java.util.LinkedList;
33import java.util.List;
34import java.util.Set;
35
36import org.expeditee.gui.Frame;
37import org.expeditee.gui.FrameGraphics;
38import org.expeditee.items.Circle;
39import org.expeditee.items.Item;
40import org.expeditee.items.Line;
41import org.expeditee.items.Picture;
42import org.expeditee.items.Text;
43import org.expeditee.settings.UserSettings;
44
45import com.lowagie.text.Anchor;
46import com.lowagie.text.Chunk;
47import com.lowagie.text.Document;
48import com.lowagie.text.DocumentException;
49import com.lowagie.text.Font;
50import com.lowagie.text.FontFactory;
51import com.lowagie.text.Rectangle;
52import com.lowagie.text.pdf.ColumnText;
53import com.lowagie.text.pdf.PdfContentByte;
54import com.lowagie.text.pdf.PdfWriter;
55
56/**
57 * @author jts21
58 *
59 */
60public class PDF2Writer extends DefaultTreeWriter {
61
62 private class OrderedHashSet<T> implements Set<T> {
63 private List<T> _orderedList;
64 private HashSet<T> _hashSet;
65 public OrderedHashSet() {
66 super();
67 _orderedList = new LinkedList<T>();
68 _hashSet = new HashSet<T>();
69 }
70
71 @Override
72 public Iterator<T> iterator() {
73 return _orderedList.iterator();
74 }
75
76 @Override
77 public void clear() {
78 _hashSet.clear();
79 _orderedList.clear();
80 }
81
82 @Override
83 public boolean add(T o) {
84 return _hashSet.add(o) && _orderedList.add(o);
85 }
86
87 @Override
88 public boolean remove(Object o) {
89 return _hashSet.remove(o) && _orderedList.remove(o);
90 }
91
92 @Override
93 public int size() {
94 return _orderedList.size();
95 }
96
97 @Override
98 public boolean isEmpty() {
99 return _orderedList.isEmpty();
100 }
101
102 @Override
103 public boolean contains(Object o) {
104 return _hashSet.contains(o);
105 }
106
107 @Override
108 public Object[] toArray() {
109 return _orderedList.toArray();
110 }
111
112 @SuppressWarnings("hiding")
113 @Override
114 public <T> T[] toArray(T[] a) {
115 return _orderedList.toArray(a);
116 }
117
118 @Override
119 public boolean containsAll(Collection<?> c) {
120 return _hashSet.containsAll(c);
121 }
122
123 @Override
124 public boolean addAll(Collection<? extends T> c) {
125 return _hashSet.addAll(c) && _orderedList.addAll(c);
126 }
127
128 @Override
129 public boolean retainAll(Collection<?> c) {
130 return _hashSet.retainAll(c) && _orderedList.retainAll(c);
131 }
132
133 @Override
134 public boolean removeAll(Collection<?> c) {
135 return _hashSet.removeAll(c) && _orderedList.removeAll(c);
136 }
137 }
138
139 private Document _pdfDocument;
140 private Dimension _pageSize;
141 private PdfWriter _pdfWriter;
142 private float _height;
143 private boolean _first = true;
144 private OrderedHashSet<Frame> _frames = null;
145
146 public PDF2Writer() {
147 _pageSize = FrameGraphics.getMaxSize();
148 _pdfDocument = new Document(new Rectangle(_pageSize.width, _pageSize.height));
149 }
150
151 @Override
152 protected void initialise(Frame start, Writer writer) throws IOException {
153 _format = ".pdf";
154 super.initialise(start, writer);
155 try {
156 _pdfWriter = PdfWriter.getInstance(_pdfDocument,
157 new FileOutputStream(_filename));
158 _pdfDocument.open();
159 _pdfDocument.addCreationDate();
160 _pdfDocument.addAuthor(UserSettings.UserName.get());
161 _pdfDocument.addCreator("Expeditee");
162 _pdfDocument.addTitle(start.getTitle());
163 _height = _pdfWriter.getPageSize().getHeight();
164 } catch (DocumentException e) {
165 e.printStackTrace();
166 throw new IOException(e.getMessage());
167 }
168 }
169
170 @Override
171 protected String finalise() throws IOException {
172 _pdfDocument.close();
173 return super.finalise();
174 }
175
176 /**
177 * Used to make sure that only links with valid targets are used
178 * @param start
179 */
180 private boolean findValidLinksRecursive(Frame current, Set<Frame> known) {
181 if(current == null || known.contains(current))
182 return false;
183 known.add(current);
184
185 Frame child;
186 for(Item i : current.getItems()) {
187 if(i.isAnnotation())
188 continue;
189 if((child = i.getChild()) != null)
190 findValidLinksRecursive(child, known);
191 }
192
193 return true;
194 }
195
196 @Override
197 protected void outputTree(Frame toWrite) throws IOException {
198 if (toWrite == null)
199 return;
200 _frames = new OrderedHashSet<Frame>();
201
202 findValidLinksRecursive(toWrite, _frames);
203
204 for(Frame f : _frames) {
205 if(f == null)
206 continue;
207 writeStartFrame(f);
208 Text title = f.getTitleItem();
209 for(Item i : f.getItems()) {
210 if(i != title) {
211 this.writeItem(i);
212 }
213 }
214 // draw title last since it needs to be handled separately from other items,
215 // and also drawn on top of shapes
216 if (title != null) {
217 if (title.isAnnotation())
218 this.writeAnnotationTitle(title);
219 else
220 this.writeTitle(title, f.getItems());
221 }
222 }
223 }
224
225 @Override
226 protected void writeStartFrame(Frame starting) throws IOException {
227 // start a new page
228 if(!_first) {
229 _pdfDocument.newPage();
230 } else {
231 _first = false;
232 }
233 // set bg color
234 PdfContentByte cb = _pdfWriter.getDirectContent();
235 cb.setColorFill(starting.getPaintBackgroundColor());
236 cb.rectangle(0, 0, _pageSize.width, _pageSize.height);
237 cb.fill();
238 // super.writeStartFrame(starting);
239 }
240
241 private void drawPolygon(PdfContentByte cb, Polygon poly, Color fill, Color line, float lineThickness) {
242 if(poly != null) {
243 cb.moveTo(poly.xpoints[0], _height - poly.ypoints[0]);
244 for(int i = 1; i < poly.npoints; i++) {
245 cb.lineTo(poly.xpoints[i], _height - poly.ypoints[i]);
246 }
247 cb.closePath();
248 if(fill != null) {
249 cb.setColorFill(fill);
250 if(lineThickness > 0) {
251 cb.setLineWidth(lineThickness);
252 cb.setColorStroke(line);
253 cb.fillStroke();
254 } else {
255 cb.fill();
256 }
257 } else {
258 cb.setLineWidth(lineThickness);
259 cb.setColorStroke(line);
260 cb.stroke();
261 }
262 }
263 }
264
265 private void drawMark(PdfContentByte cb, Item i, float x, float y) {
266 if(i == null) return;
267 boolean hasLink = i.getLink() != null;
268
269 if (hasLink) {
270
271 Color lineColor = Color.BLACK, fillColor = null;
272 Polygon poly = i.getLinkPoly();
273 poly = new Polygon(poly.xpoints, poly.ypoints, poly.npoints);
274 poly.translate((int) (x - Item.LEFT_MARGIN), (int) (_height - y - i.getBoundsHeight() / 2));
275
276 drawPolygon(cb, poly, fillColor, lineColor, 0.5f);
277 }
278 }
279
280 private void writeAnchor(PdfContentByte cb, Item i, Anchor a, float x, float y) {
281 if(i.getParent() != null && i.getParent().getTitleItem()!=null && i.getParent().getTitleItem().equals(i)) {
282 a.setName(i.getParent().getName());
283 }
284 if(_frames != null && i.getChild() != null && _frames.contains(i.getChild())) {
285 a.setReference("#" + i.getAbsoluteLink());
286 drawMark(cb, i, x, y);
287 }
288
289 ColumnText.showTextAligned(cb, PdfContentByte.ALIGN_LEFT, a, x, y, 0);
290 }
291
292 @Override
293 protected void writeTitle(Text title, List<Item> items) throws IOException {
294 writeText(title);
295 }
296
297 @Override
298 protected void writeText(Text text) throws IOException {
299 PdfContentByte cb = _pdfWriter.getDirectContent();
300 Font font = FontFactory.getFont(
301 Conversion.getPdfFont(text.getFamily()), text.getSize(), text
302 .getPaintFont().getStyle(), text.getPaintColor());
303
304 // we draw some text on a certain position
305 float x = text.getX(), y = _pdfWriter.getPageSize().getHeight() - text.getY();
306 List<String> textLines = text.getTextList();
307 for(int i = 0; i < textLines.size(); i++){
308 Chunk chunk = new Chunk(textLines.get(i), font);
309 Anchor anchor = new Anchor(chunk);
310 writeAnchor(cb, text, anchor, x, y);
311 y -= text.getLineHeight();
312 }
313 }
314
315 @Override
316 protected void writePicture(Picture pic) throws IOException {
317 Image image = pic.getCroppedImage();
318 try {
319 PdfContentByte cb = _pdfWriter.getDirectContent();
320 com.lowagie.text.Image iTextImage = com.lowagie.text.Image.getInstance(image, null);
321 float angle = (float) (pic.getRotate() * Math.PI / 180);
322 double sin = Math.sin(angle), cos = Math.cos(angle);
323 int w = pic.getWidth(), h = pic.getHeight();
324 iTextImage.scalePercent(pic.getScale() * 100);
325 iTextImage.setRotation(-angle);
326 Chunk chunk = new Chunk(iTextImage, 0, 0);
327 Anchor anchor = new Anchor(chunk);
328 writeAnchor(cb, pic, anchor,
329 (float) (pic.getX() + (w - Math.abs(w * cos + h * sin)) / 2),
330 (float) (_height - pic.getY() - (h + Math.abs(w * sin + h * cos)) / 2));
331 // cb.addImage(iTextImage);
332 } catch (DocumentException e) {
333 e.printStackTrace();
334 }
335 }
336
337 @Override
338 protected void writeCircle(Circle circle) {
339 PdfContentByte cb = _pdfWriter.getDirectContent();
340 cb.circle(circle.getCenter().getX(), _pdfWriter.getPageSize().getHeight() - circle.getCenter().getY(), (float) circle.getRadius());
341 cb.setColorFill(circle.getFillColor());
342 if(circle.getThickness() > 0) {
343 cb.setLineWidth(circle.getThickness());
344 cb.setColorStroke(circle.getPaintColor());
345 cb.fillStroke();
346 } else {
347 cb.fill();
348 }
349 }
350
351 private List<Line> seenLines = new LinkedList<Line>();
352 @Override
353 protected void writeLine(Line line) throws IOException {
354 if(seenLines.contains(line)) {
355 return;
356 }
357 PdfContentByte cb = _pdfWriter.getDirectContent();
358 if(line.getStartItem().isEnclosed()) {
359 seenLines.add(line);
360 Line currentLine = line;
361 Item currentItem = line.getStartItem();
362 cb.moveTo(currentItem.getX(), _height - currentItem.getY());
363 for(;;) {
364 currentItem = currentLine.getOppositeEnd(currentItem);
365 cb.lineTo(currentItem.getX(), _height - currentItem.getY());
366 for(Line l : currentItem.getLines()) {
367 if(l.equals(currentLine)) {
368 continue;
369 }
370 currentLine = l;
371 break;
372 }
373 if(currentLine == null || currentLine.equals(line)) {
374 break;
375 }
376 seenLines.add(currentLine);
377 }
378 cb.closePath();
379 Color fill = currentItem.getFillColor();
380 if(fill != null) {
381 cb.setColorFill(fill);
382 if(currentItem.getThickness() > 0) {
383 cb.setLineWidth(currentItem.getThickness());
384 cb.setColorStroke(currentLine.getPaintColor());
385 cb.fillStroke();
386 } else {
387 cb.fill();
388 }
389 } else if(currentItem.getThickness() > 0) {
390 cb.setLineWidth(currentItem.getThickness());
391 cb.setColorStroke(currentLine.getPaintColor());
392 cb.stroke();
393 }
394 } else {
395 for(Item l : line.getStartItem().getAllConnected()) {
396 if(l instanceof Line && !seenLines.contains(l)) {
397 seenLines.add((Line) l);
398 Item start = ((Line) l).getStartItem();
399 Item end = ((Line) l).getEndItem();
400 cb.moveTo(start.getX(), _height - start.getY());
401 cb.lineTo(end.getX(), _height - end.getY());
402 cb.closePath();
403 if(l.getThickness() >= 0) {
404 cb.setLineWidth(l.getThickness());
405 cb.setColorStroke(l.getPaintColor());
406 cb.stroke();
407 }
408 drawPolygon(cb, ((Line) l).getStartArrow(), l.getPaintColor(), l.getPaintColor(), l.getThickness());
409 drawPolygon(cb, ((Line) l).getEndArrow(), l.getPaintColor(), l.getPaintColor(), l.getThickness());
410 }
411 }
412 }
413 }
414
415 @Override
416 protected Collection<Item> getItemsToWrite(Frame toWrite) {
417 return toWrite.getVisibleItems();
418 }
419}
Note: See TracBrowser for help on using the repository browser.