Changeset 821


Ignore:
Timestamp:
02/04/14 15:33:39 (10 years ago)
Author:
jts21
Message:

Add support for writetree to PDF2,
Links followed by writetree are clickable in the PDF (and have the Expeditee linkmark next to them).
To Fix:

  • The clickable bounding box of rotated images is just a non-rotated rectangle covering the entire rotated image (and also covering the whitespace or any other items around the corners of the image). This is due to anchors apparently not working when they're rotated (seriously, there's a way to rotate them, but once rotated they can't be clicked to follow their link)
  • Currently polygons don't get linked, because there doesn't seem to be a way to make a non-rectangular anchor, nor to actually put a polygon inside an anchor (I suppose it could be done by just putting an empty anchor of the correct dimensions over the top of the polygon)
Location:
trunk/src/org/expeditee
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/org/expeditee/io/PDF2Writer.java

    r820 r821  
    55import java.awt.Image;
    66import java.awt.Polygon;
     7import java.awt.geom.AffineTransform;
    78import java.io.FileOutputStream;
    89import java.io.IOException;
    910import java.io.Writer;
    1011import java.util.Collection;
     12import java.util.HashSet;
     13import java.util.Iterator;
    1114import java.util.LinkedList;
    1215import java.util.List;
     16import java.util.Set;
    1317
    1418import org.expeditee.gui.Frame;
     
    2125import org.expeditee.settings.UserSettings;
    2226
     27import com.lowagie.text.Anchor;
     28import com.lowagie.text.Chunk;
    2329import com.lowagie.text.Document;
    2430import com.lowagie.text.DocumentException;
     
    2632import com.lowagie.text.FontFactory;
    2733import com.lowagie.text.Rectangle;
     34import com.lowagie.text.pdf.ColumnText;
    2835import com.lowagie.text.pdf.PdfContentByte;
    2936import com.lowagie.text.pdf.PdfWriter;
    3037
    3138/**
    32  *
    33  * @author root
     39 * @author jts21
    3440 *
    3541 */
    36 public class PDF2Writer extends DefaultFrameWriter {
    37 
     42public class PDF2Writer extends DefaultTreeWriter {
     43       
     44        private class OrderedHashSet<T> implements Set<T> {
     45                private List<T> _orderedList;
     46                private HashSet<T> _hashSet;
     47                public OrderedHashSet() {
     48                        super();
     49                        _orderedList = new LinkedList<T>();
     50                        _hashSet = new HashSet<T>();
     51                }
     52               
     53                @Override
     54                public Iterator<T> iterator() {
     55                        return _orderedList.iterator();
     56                }
     57               
     58                @Override
     59                public void clear() {
     60                        _hashSet.clear();
     61                        _orderedList.clear();
     62                }
     63               
     64                @Override
     65                public boolean add(T o) {
     66                        return _hashSet.add(o) && _orderedList.add(o);
     67                }
     68               
     69                @Override
     70        public boolean remove(Object o) {
     71                return _hashSet.remove(o) && _orderedList.remove(o);
     72        }
     73
     74                @Override
     75        public int size() {
     76                return _orderedList.size();
     77        }
     78
     79                @Override
     80        public boolean isEmpty() {
     81                return _orderedList.isEmpty();
     82        }
     83
     84                @Override
     85        public boolean contains(Object o) {
     86                return _hashSet.contains(o);
     87        }
     88
     89                @Override
     90        public Object[] toArray() {
     91                return _orderedList.toArray();
     92        }
     93
     94                @SuppressWarnings("hiding")
     95        @Override
     96        public <T> T[] toArray(T[] a) {
     97                return _orderedList.toArray(a);
     98        }
     99
     100                @Override
     101        public boolean containsAll(Collection<?> c) {
     102                return _hashSet.containsAll(c);
     103        }
     104
     105                @Override
     106        public boolean addAll(Collection<? extends T> c) {
     107                return _hashSet.addAll(c) && _orderedList.addAll(c);
     108        }
     109
     110                @Override
     111        public boolean retainAll(Collection<?> c) {
     112                return _hashSet.retainAll(c) && _orderedList.retainAll(c);
     113        }
     114
     115                @Override
     116        public boolean removeAll(Collection<?> c) {
     117                return _hashSet.removeAll(c) && _orderedList.removeAll(c);
     118        }
     119        }
     120       
    38121        private Document _pdfDocument;
    39122        private Dimension _pageSize;
    40123        private PdfWriter _pdfWriter;
    41124        private float _height;
     125        private boolean _first = true;
     126        private OrderedHashSet<Frame> _frames = null;
    42127
    43128        public PDF2Writer() {
     
    57142                        _pdfDocument.addAuthor(UserSettings.UserName.get());
    58143                        _pdfDocument.addCreator("Expeditee");
     144                        _pdfDocument.addTitle(start.getTitle());
    59145                        _height = _pdfWriter.getPageSize().getHeight();
    60                         // set bg color
    61                         PdfContentByte cb = _pdfWriter.getDirectContent();
    62                         cb.setColorFill(start.getPaintBackgroundColor());
    63                         System.out.println(start.getBackgroundColor());
    64                         cb.rectangle(0, 0, _pageSize.width, _pageSize.height);
    65                         cb.fillStroke();
    66146                } catch (DocumentException e) {
    67147                        e.printStackTrace();
     
    69149                }
    70150        }
    71 
    72         @Override
    73         protected void writeTitle(Text toWrite, List<Item> items)
    74                         throws IOException {
    75                 _pdfDocument.addTitle(toWrite.getText());
    76                 writeText(toWrite);
    77         }
    78 
     151       
    79152        @Override
    80153        protected String finalise() throws IOException {
     
    82155                return super.finalise();
    83156        }
    84 
     157       
     158        /**
     159         * Used to make sure that only links with valid targets are used
     160         * @param start
     161         */
     162        private boolean findValidLinksRecursive(Frame current, Set<Frame> known) {
     163                if(current == null || known.contains(current))
     164                        return false;
     165                known.add(current);
     166               
     167                Frame child;
     168                for(Item i : current.getItems()) {
     169                        if(i.isAnnotation())
     170                                continue;
     171                        if((child = i.getChild()) != null)
     172                                findValidLinksRecursive(child, known);
     173                }
     174               
     175                return true;
     176        }
     177       
     178        @Override
     179        protected void outputTree(Frame toWrite) throws IOException {
     180                if (toWrite == null)
     181                        return;
     182                _frames = new OrderedHashSet<Frame>();
     183               
     184                findValidLinksRecursive(toWrite, _frames);
     185               
     186                System.out.println(_frames);
     187               
     188                for(Frame f : _frames) {
     189                        if(f == null)
     190                                continue;
     191                        writeStartFrame(f);
     192                Text title = f.getTitleItem();
     193                for(Item i : f.getItems()) {
     194                        if(i != title) {
     195                                this.writeItem(i);
     196                        }
     197                }
     198                // draw title last since it needs to be handled separately from other items,
     199                // and also drawn on top of shapes
     200                if (title != null) {
     201                        if (title.isAnnotation())
     202                                this.writeAnnotationTitle(title);
     203                        else
     204                                this.writeTitle(title, f.getItems());
     205                }
     206                }
     207        }
     208       
     209        @Override
     210        protected void writeStartFrame(Frame starting) throws IOException {
     211                // start a new page
     212                if(!_first) {
     213                        _pdfDocument.newPage();
     214                } else {
     215                        _first = false;
     216                }
     217                // set bg color
     218                PdfContentByte cb = _pdfWriter.getDirectContent();
     219                cb.setColorFill(starting.getPaintBackgroundColor());
     220                System.out.println(starting.getBackgroundColor());
     221                cb.rectangle(0, 0, _pageSize.width, _pageSize.height);
     222                cb.fill();
     223                // super.writeStartFrame(starting);
     224        }
     225       
     226        private void drawPolygon(PdfContentByte cb, Polygon poly, Color fill, Color line, float lineThickness) {
     227                if(poly != null) {
     228                        cb.moveTo(poly.xpoints[0], _height - poly.ypoints[0]);
     229                        for(int i = 1; i < poly.npoints; i++) {
     230                                cb.lineTo(poly.xpoints[i], _height - poly.ypoints[i]);
     231                        }
     232                        cb.closePath();
     233                        if(fill != null) {
     234                                cb.setColorFill(fill);
     235                                if(lineThickness > 0) {
     236                                cb.setLineWidth(lineThickness);
     237                                cb.setColorStroke(line);
     238                                cb.fillStroke();
     239                        } else {
     240                                cb.fill();
     241                        }
     242                        } else {
     243                                cb.setLineWidth(lineThickness);
     244                                cb.setColorStroke(line);
     245                                cb.stroke();
     246                        }
     247                }
     248        }
     249       
     250        private void drawMark(PdfContentByte cb, Item i, float x, float y) {
     251                if(i == null) return;
     252                boolean hasLink = i.getLink() != null;
     253               
     254                if (hasLink) {
     255                       
     256                        Color lineColor = Color.BLACK, fillColor = null;
     257                        Polygon poly = i.getLinkPoly();
     258                        poly = new Polygon(poly.xpoints, poly.ypoints, poly.npoints);
     259                        poly.translate((int) (x - Item.LEFT_MARGIN), (int) (_height - y - i.getBoundsHeight() / 2));
     260                       
     261                        drawPolygon(cb, poly, fillColor, lineColor, 0.5f);
     262                }
     263        }
     264       
     265        private void writeAnchor(PdfContentByte cb, Item i, Anchor a, float x, float y) {
     266                if(i.getParent() != null && i.getParent().getTitleItem().equals(i)) {
     267                        a.setName(i.getParent().getName());
     268                }
     269                if(_frames != null && i.getChild() != null && _frames.contains(i.getChild())) {
     270                        a.setReference("#" + i.getAbsoluteLink());
     271                        drawMark(cb, i, x, y);
     272                }
     273               
     274                ColumnText.showTextAligned(cb, PdfContentByte.ALIGN_LEFT, a, x, y, 0);
     275        }
     276       
     277        @Override
     278        protected void writeTitle(Text title, List<Item> items) throws IOException {
     279                writeText(title);
     280        }
     281       
    85282        @Override
    86283        protected void writeText(Text text) throws IOException {
    87284                PdfContentByte cb = _pdfWriter.getDirectContent();
    88                 // we tell the ContentByte we're ready to draw text
    89                 cb.beginText();
    90285                Font font = FontFactory.getFont(
    91286                                Conversion.getPdfFont(text.getFamily()), text.getSize(), text
    92287                                                .getPaintFont().getStyle(), text.getPaintColor());
    93                 cb.setFontAndSize(font.getBaseFont(), text.getSize());
    94                 // cb.setColorStroke(text.getPaintColor());
    95                 cb.setColorFill(text.getPaintColor());
    96 
     288               
    97289                // we draw some text on a certain position
    98                 cb.setTextMatrix(text.getX(), _pdfWriter.getPageSize().getHeight() - text.getY());
     290                float x = text.getX(), y = _pdfWriter.getPageSize().getHeight() - text.getY();
    99291                List<String> textLines = text.getTextList();
    100                 //cb.showText(textLines.get(0));
    101292                for(int i = 0; i < textLines.size(); i++){
    102                         cb.showText(textLines.get(i));
    103                         cb.moveText(0, -text.getLineHeight());
    104                 }
    105                
    106                 // we tell the contentByte, we've finished drawing text
    107                 cb.endText();
     293                        Chunk chunk = new Chunk(textLines.get(i), font);
     294                        Anchor anchor = new Anchor(chunk);
     295                        writeAnchor(cb, text, anchor, x, y);
     296                        y -= text.getLineHeight();
     297                }
    108298        }
    109299
     
    117307                        double sin = Math.sin(angle), cos = Math.cos(angle);
    118308                        int w = pic.getWidth(), h = pic.getHeight();
    119                         iTextImage.setAbsolutePosition((float) (pic.getX() + (w - Math.abs(w * cos + h * sin)) / 2),
    120                                         (float) (_pdfWriter.getPageSize().getHeight() - pic.getY() - (h + Math.abs(w * sin + h * cos)) / 2));
    121309                        iTextImage.scalePercent(pic.getScale() * 100);
    122310                        iTextImage.setRotation(-angle);
    123                         cb.addImage(iTextImage);
     311                        Chunk chunk = new Chunk(iTextImage, 0, 0);
     312                        Anchor anchor = new Anchor(chunk);
     313                        writeAnchor(cb, pic, anchor,
     314                                        (float) (pic.getX() + (w - Math.abs(w * cos + h * sin)) / 2),
     315                                        (float) (_height - pic.getY() - (h + Math.abs(w * sin + h * cos)) / 2));
     316                        // cb.addImage(iTextImage);
    124317                } catch (DocumentException e) {
    125318                        e.printStackTrace();
     
    138331                } else {
    139332                        cb.fill();
    140                 }
    141         }
    142        
    143         private void fillPolygon(PdfContentByte cb, Polygon poly, Color fill, Color line, float lineThickness) {
    144                 if(poly != null) {
    145                         cb.moveTo(poly.xpoints[0], _height - poly.ypoints[0]);
    146                         for(int i = 1; i < poly.npoints; i++) {
    147                                 cb.lineTo(poly.xpoints[i], _height - poly.ypoints[i]);
    148                         }
    149                         cb.closePath();
    150                         cb.setColorFill(fill);
    151                         if(lineThickness > 0) {
    152                                 cb.setLineWidth(lineThickness);
    153                                 cb.setColorStroke(line);
    154                                 cb.fillStroke();
    155                         } else {
    156                                 cb.fill();
    157                         }
    158333                }
    159334        }
     
    216391                                                cb.stroke();
    217392                                        }
    218                                         fillPolygon(cb, ((Line) l).getStartArrow(), l.getPaintColor(), l.getPaintColor(), l.getThickness());
    219                                         fillPolygon(cb, ((Line) l).getEndArrow(), l.getPaintColor(), l.getPaintColor(), l.getThickness());
     393                                        drawPolygon(cb, ((Line) l).getStartArrow(), l.getPaintColor(), l.getPaintColor(), l.getThickness());
     394                                        drawPolygon(cb, ((Line) l).getEndArrow(), l.getPaintColor(), l.getPaintColor(), l.getThickness());
    220395                                }
    221396                        }
  • trunk/src/org/expeditee/items/Item.java

    r812 r821  
    638638
    639639        // TODO draw the link with a circle rather than a polygon!!
    640         protected Polygon getLinkPoly() {
     640        public Polygon getLinkPoly() {
    641641                if (_circle == null) {
    642642                        int points = 16;
Note: See TracChangeset for help on using the changeset viewer.