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

Last change on this file since 1415 was 1415, checked in by bln4, 5 years ago

Renamed Frame.getItems() to Frame.getSortedItems() to better represent its functionality.

-> org.apollo.ApolloGestureActions
-> org.apollo.ApolloSystem
-> org.expeditee.actions.Actions
-> org.expeditee.actions.Debug
-> org.expeditee.actions.ExploratorySearchActions
-> org.expeditee.actions.JfxBrowserActions
-> org.expeditee.actions.Misc
-> org.expeditee.actions.Navigation
-> org.expeditee.actions.ScriptBase
-> org.expeditee.actions.Simple
-> org.expeditee.agents.ComputeTree
-> org.expeditee.agents.CopyTree
-> org.expeditee.agents.DisplayComet
-> org.expeditee.agents.DisplayTree
-> org.expeditee.agents.DisplayTreeLeaves
-> org.expeditee.agents.GraphFramesetLinks
-> org.expeditee.agents.TreeProcessor
-> org.expeditee.gio.gesture.StandardGestureActions
-> org.expeditee.gui.DisplayController
-> org.expeditee.gui.FrameCreator
-> org.expeditee.gui.FrameIO
-> org.expeditee.io.DefaultTreeWriter
-> org.expeditee.io.JavaWriter
-> org.expeditee.io.PDF2Writer
-> org.expeditee.io.TXTWriter
-> org.expeditee.io.WebParser
-> org.expeditee.io.flowlayout.XGroupItem
-> org.expeditee.items.Dot
-> org.expeditee.items.Item
-> org.expeditee.items.ItemUtils
-> org.expeditee.network.FrameShare
-> org.expeditee.stats.TreeStats


Created ItemsList class to wrap ArrayList<Item>. Frames now use this new class to store its body list (used for display) as well as its primaryBody and surrogateBody.

-> org.expeditee.agents.Format
-> org.expeditee.agents.HFormat
-> org.expeditee.gio.gesture.StandardGestureActions
-> org.expeditee.gui.Frame
-> org.expeditee.gui.FrameUtils


Refactorted Frame.setResort(bool) to Frame.invalidateSorted() to better function how it is intended to with a more accurate name.

-> org.expeditee.agents.Sort


When writing out .exp files and getting attributes to respond to LEFT + RIGHT click, boolean items are by default true. This has always been the case. An ammendment to this is that defaults can now be established.
Also added 'EnterClick' functionality. If cursored over a item with this property and you press enter, it acts as if you have clicked on it instead.

-> org.expeditee.assets.resources-public.framesets.authentication.1.exp to 6.exp
-> org.expeditee.gio.gesture.StandardGestureActions
-> org.expeditee.gio.input.KBMInputEvent
-> org.expeditee.gio.javafx.JavaFXConversions
-> org.expeditee.gio.swing.SwingConversions
-> org.expeditee.gui.AttributeUtils
-> org.expeditee.io.Conversion
-> org.expeditee.io.DefaultFrameWriter
-> org.expeditee.items.Item


Fixed a bug caused by calling Math.abs on Integer.MIN_VALUE returning unexpected result. Due to zero being a thing, you cannot represent Math.abs(Integer.MIN_VALUE) in a Integer object. The solution is to use Integer.MIN_VALUE + 1 instead of Integer.MIN_VALUE.

-> org.expeditee.core.bounds.CombinationBounds
-> org.expeditee.io.flowlayout.DimensionExtent


Recoded the contains function in EllipticalBounds so that intersection tests containing circles work correctly.

-> org.expeditee.core.bounds.EllipticalBounds


Added toString() to PolygonBounds to allow for useful printing during debugging.

-> org.expeditee.core.bounds.PolygonBounds

Implemented Surrogate Mode!

-> org.expeditee.encryption.io.EncryptedExpReader
-> org.expeditee.encryption.io.EncryptedExpWriter
-> org.expeditee.encryption.items.surrogates.EncryptionDetail
-> org.expeditee.encryption.items.surrogates.Label
-> org.expeditee.gui.FrameUtils
-> org.expeditee.gui.ItemsList
-> org.expeditee.items.Item
-> org.expeditee.items.Text


???? Use Integer.MAX_VALUE cast to a float instead of Float.MAX_VALUE. This fixed some bug which I cannot remember.

-> org.expeditee.gio.TextLayoutManager
-> org.expeditee.gio.swing.SwingTextLayoutManager


Improved solution for dealing with the F10 key taking focus away from Expeditee due to it being a assessibility key.

-> org.expeditee.gio.swing.SwingInputManager


Renamed variable visibleItems in FrameGraphics.paintFrame to itemsToPaintCanditates to better represent functional intent.

-> org.expeditee.gui.FrameGraphics


Improved checking for if personal resources exist before recreating them

-> org.expeditee.gui.FrameIO


Repeated messages to message bay now have a visual feedback instead of just a beep. This visual feedback is in the form of a count of the amount of times it has repeated.

-> org.expeditee.gui.MessageBay


Updated comment on the Vector class to explain what vectors are.

-> org.expeditee.gui.Vector


Added constants to represent all of the property keys in DefaultFrameReader and DefaultFrameWriter.

-> org.expeditee.io.DefaultFrameReader
-> org.expeditee.io.DefaultFrameWriter


Updated the KeyList setting to be more heirarcial with how users will store their Secrets.

-> org.expeditee.settings.identity.secrets.KeyList

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