org.andrill.coretools.graphics.driver.pdf.PDFDriver.java Source code

Java tutorial

Introduction

Here is the source code for org.andrill.coretools.graphics.driver.pdf.PDFDriver.java

Source

/*
 * Copyright (c) Josh Reed, 2009.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.andrill.coretools.graphics.driver.pdf;

import java.awt.Color;
import java.awt.Font;
import java.awt.geom.AffineTransform;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Stack;

import javax.imageio.ImageIO;

import org.andrill.coretools.Platform;
import org.andrill.coretools.graphics.GraphicsContext;
import org.andrill.coretools.graphics.RasterGraphics;
import org.andrill.coretools.graphics.driver.Driver;
import org.andrill.coretools.graphics.fill.ColorFill;
import org.andrill.coretools.graphics.fill.Fill;
import org.andrill.coretools.graphics.util.Paper;

import com.lowagie.text.BadElementException;
import com.lowagie.text.Document;
import com.lowagie.text.DocumentException;
import com.lowagie.text.Image;
import com.lowagie.text.pdf.DefaultFontMapper;
import com.lowagie.text.pdf.FontMapper;
import com.lowagie.text.pdf.PdfContentByte;
import com.lowagie.text.pdf.PdfWriter;

/**
 * A driver implementation for iText.
 * 
 * @author Josh Reed (jareed@andrill.org)
 */
public class PDFDriver implements Driver {
    public class Arc extends Shape {
        Rectangle2D r;
        double start, extent;
        ArcStyle style;

        public Arc(final Rectangle2D r, final double start, final double extent, final ArcStyle style) {
            this.r = r;
            this.start = start;
            this.extent = extent;
            this.style = style;
        }

        @Override
        public void outline(final PdfContentByte content) {
            switch (style) {
            case OPEN:
                outlineOpen(content);
                break;
            case CLOSED:
                outlineClosed(content);
                break;
            case SECTOR:
                outlineSector(content);
                break;
            }
        }

        protected void outlineClosed(final PdfContentByte content) {
            content.arc(x(r.getMinX()), y(r.getMinY()), x(r.getMaxX()), y(r.getMaxY()), (float) start,
                    (float) extent);
            content.closePath();
        }

        protected void outlineOpen(final PdfContentByte content) {
            content.arc(x(r.getMinX()), y(r.getMinY()), x(r.getMaxX()), y(r.getMaxY()), (float) start,
                    (float) extent);
        }

        protected void outlineSector(final PdfContentByte content) {
            content.arc(x(r.getMinX()), y(r.getMinY()), x(r.getMaxX()), y(r.getMaxY()), (float) start,
                    (float) extent);
            content.lineTo(x(r.getCenterX()), y(r.getCenterY()));
            content.closePath();
        }
    }

    public class Line extends Shape {
        Point2D p1, p2;

        public Line(final Point2D p2, final Point2D p1) {
            this.p1 = p1;
            this.p2 = p2;
        }

        @Override
        public void outline(final PdfContentByte content) {
            content.moveTo(x(p1.getX()), y(p1.getY()));
            content.lineTo(x(p2.getX()), y(p2.getY()));
        }
    }

    public class Oval extends Shape {
        Rectangle2D r;

        public Oval(final Rectangle2D rect) {
            r = rect;
        }

        @Override
        public void outline(final PdfContentByte content) {
            content.ellipse(x(r.getMinX()), y(r.getMinY()), x(r.getMaxX()), y(r.getMaxY()));
        }
    }

    public class Polygon extends Shape {
        List<Point2D> points;

        public Polygon(final List<Point2D> points) {
            this.points = points;
        }

        @Override
        public void outline(final PdfContentByte content) {
            if (points.size() > 1) {
                Point2D p = points.get(0);
                content.moveTo(x(p.getX()), y(p.getY()));
                for (int i = 1; i < points.size(); i++) {
                    p = points.get(i);
                    content.lineTo(x(p.getX()), y(p.getY()));
                }
                content.closePath();
            }
        }
    }

    public class Rectangle extends Shape {
        Rectangle2D r;

        public Rectangle(final Rectangle2D rect) {
            r = rect;
        }

        @Override
        public void outline(final PdfContentByte content) {
            content.rectangle(x(r.getMinX()), y(r.getMaxY()), (float) r.getWidth(), (float) r.getHeight());
        }
    }

    public abstract class Shape {
        public abstract void outline(PdfContentByte content);
    }

    protected static class State {
        Fill fill = null;
        Color lineColor = null;
        LineStyle lineStyle = LineStyle.SOLID;
        int lineThickness = 1;
    }

    protected static final float LINE_DASH[] = { 18, 9 };
    protected static final float LINE_DASH_DOT[] = { 9, 3, 3, 3 };
    protected static final float LINE_DOT[] = { 3, 3 };

    private static void drawTest(final GraphicsContext graphics) throws Exception {
        Platform.start();

        // point, line, rectangle
        graphics.drawPoint(350, 0);
        graphics.drawLine(0, 0, 300, 0);
        graphics.drawRectangle(400, 0, 50, 100);

        graphics.setLineThickness(5);
        graphics.drawPoint(350, 10);
        graphics.drawLine(0, 10, 300, 10);
        graphics.drawRectangle(410, 10, 50, 100);

        graphics.setLineColor(Color.blue);
        graphics.drawPoint(350, 20);
        graphics.drawLine(0, 20, 300, 20);
        graphics.drawRectangle(420, 20, 50, 100);

        graphics.setLineStyle(LineStyle.DASHED);
        graphics.setLineColor(Color.black);
        graphics.setLineThickness(1);
        graphics.drawPoint(350, 30);
        graphics.drawLine(0, 30, 300, 30);
        graphics.drawRectangle(430, 30, 50, 100);

        graphics.setLineStyle(LineStyle.DOTTED);
        graphics.drawPoint(350, 40);
        graphics.drawLine(0, 40, 300, 40);
        graphics.drawRectangle(440, 40, 50, 100);

        graphics.setLineStyle(LineStyle.DASH_DOTTED);
        graphics.drawPoint(350, 50);
        graphics.drawLine(0, 50, 300, 50);
        graphics.drawRectangle(450, 50, 50, 100);

        graphics.setLineStyle(LineStyle.SOLID);
        graphics.drawPoint(350, 60);
        graphics.drawLine(0, 60, 300, 60);
        graphics.drawRectangle(460, 60, 50, 100);

        // arc, circles, ovals
        graphics.drawArc(0, 100, 100, 50, 0, 30, ArcStyle.SECTOR);
        graphics.drawArc(0, 100, 100, 50, 35, 30, ArcStyle.OPEN);
        graphics.drawArc(0, 100, 100, 50, 70, 90, ArcStyle.CLOSED);

        graphics.drawOval(150, 100, 100, 50);

        graphics.setLineStyle(LineStyle.DASHED);
        graphics.setLineColor(Color.blue);
        graphics.setLineThickness(3);
        graphics.drawOval(300, 100, 50, 50);

        // polygon
        graphics.setLineColor(Color.black);
        graphics.setLineStyle(LineStyle.SOLID);
        graphics.setLineThickness(1);
        List<Point2D> points = new ArrayList<Point2D>();
        points.add(new Point2D.Double(0, 200));
        points.add(new Point2D.Double(300, 200));
        points.add(new Point2D.Double(100, 220));
        points.add(new Point2D.Double(100, 230));
        points.add(new Point2D.Double(50, 240));
        points.add(new Point2D.Double(50, 250));
        points.add(new Point2D.Double(0, 250));
        graphics.drawPolygon(points);

        // text
        graphics.drawString(350, 250, new Font("SanSerif", Font.BOLD, 12), "drawString");

        Rectangle2D left = new Rectangle2D.Double(0, 300, 100, 50);
        graphics.drawRectangle(left);
        graphics.drawStringLeft(left, new Font("Serif", Font.ITALIC, 14), "Left");

        Rectangle2D center = new Rectangle2D.Double(150, 300, 100, 50);
        graphics.drawRectangle(center);
        graphics.drawStringCenter(center, new Font("Serif", Font.PLAIN, 14), "Center");

        Rectangle2D right = new Rectangle2D.Double(300, 300, 100, 50);
        graphics.drawRectangle(right);
        graphics.drawStringRight(right, new Font("Dialog", Font.PLAIN, 14), "Right");

        // images
        URL image = new File("icon.png").toURI().toURL();

        graphics.drawImage(new Point2D.Double(0, 400), image);

        Rectangle2D rect = new Rectangle2D.Double(300, 400, 50, 50);
        graphics.drawImage(rect, image);
        graphics.drawRectangle(rect);
    }

    public static void main(final String[] args) throws Exception {
        Paper paper = Paper.getDefault();

        // raster graphics
        RasterGraphics raster = new RasterGraphics(paper.getWidth(), paper.getHeight(), true);
        raster.pushTransform(AffineTransform.getTranslateInstance(36, 36));
        drawTest(raster);
        raster.write(new File("Test.png"));

        // pdf graphics
        Document document = new Document(new com.lowagie.text.Rectangle(paper.getWidth(), paper.getHeight()));
        PdfWriter writer = PdfWriter.getInstance(document, new FileOutputStream("Test.pdf"));
        document.open();
        drawTest(new GraphicsContext(new PDFDriver(writer.getDirectContent(), paper)));
        document.close();
        writer.close();
    }

    protected FontMapper fontMapper = new DefaultFontMapper();
    protected final PdfContentByte content;
    protected final Paper paper;
    protected Fill fill = new ColorFill(Color.white);
    protected Color lineColor = Color.black;
    protected LineStyle lineStyle = LineStyle.SOLID;
    protected int lineThickness = 1;
    protected Map<String, Image> imageCache = new HashMap<String, Image>();
    protected Stack<AffineTransform> transformStack = new Stack<AffineTransform>();
    protected Stack<State> stateStack = new Stack<State>();

    /**
     * Create a new PDF driver.
     * 
     * @param content
     *            the content.
     * @param paper
     *            the paper.
     */
    public PDFDriver(final PdfContentByte content, final Paper paper) {
        this.content = content;
        this.paper = paper;
        // AffineTransform tx = AffineTransform.getScaleInstance(1.0, -1.0);
        // tx.translate(paper.getPrintableX(), -paper.getHeight() + paper.getPrintableY());
        // content.transform(tx);
    }

    /**
     * {@inheritDoc}
     */
    public void dispose() {
        // do nothing
    }

    protected void draw(final Shape shape) {
        content.setLineWidth(lineThickness);
        content.setColorStroke(lineColor);
        switch (lineStyle) {
        case SOLID:
            content.setLineDash(1);
            break;
        case DASHED:
            content.setLineDash(LINE_DASH, 0);
            break;
        case DOTTED:
            content.setLineDash(LINE_DOT, 0);
            break;
        case DASH_DOTTED:
            content.setLineDash(LINE_DASH_DOT, 0);
            break;
        }
        shape.outline(content);
        content.stroke();
    }

    /**
     * {@inheritDoc}
     */
    public void drawArc(final Rectangle2D bounds, final double start, final double extent, final ArcStyle style) {
        draw(new Arc(bounds, start, extent, style));
    }

    /**
     * {@inheritDoc}
     */
    public void drawImage(final Point2D point, final URL url) {
        Image image = getImage(url);
        try {
            content.addImage(image, image.getWidth(), 0, 0, image.getHeight(), x(point.getX()), y(point.getY()),
                    true);
        } catch (DocumentException e) {
            // TODO log
            e.printStackTrace();
        }
    }

    /**
     * {@inheritDoc}
     */
    public void drawImage(final Rectangle2D rect, final URL url) {
        Image image = getImage(url);
        try {
            content.addImage(image, (float) rect.getWidth(), 0, 0, (float) rect.getHeight(), x(rect.getX()),
                    y(rect.getY()), true);
        } catch (DocumentException e) {
            // TODO log
            e.printStackTrace();
        }
    }

    /**
     * {@inheritDoc}
     */
    public void embedImage(final Rectangle2D rect, final URL url) {
        // 2/15/2015 brg: to satisfy Driver - if we get PDFDriver up and running for PDF
        // export (we currently use Java2DDriver), we can remove Driver.embedImage(), since
        // this.drawImage() correctly embeds the full-resolution image instead of the scaled
        // image from the cache
    }

    /**
     * {@inheritDoc}
     */
    public void drawLine(final Point2D start, final Point2D end) {
        draw(new Line(start, end));
    }

    /**
     * {@inheritDoc}
     */
    public void drawOval(final Rectangle2D bounds) {
        draw(new Oval(bounds));
    }

    /**
     * {@inheritDoc}
     */
    public void drawPoint(final Point2D point) {
        double offset = lineThickness / 2.0;
        draw(new Line(new Point2D.Double(point.getX() - offset, point.getY()),
                new Point2D.Double(point.getX() + offset, point.getY())));
    }

    /**
     * {@inheritDoc}
     */
    public void drawPolygon(final List<Point2D> points) {
        draw(new Polygon(points));
    }

    /**
     * {@inheritDoc}
     */
    public void drawRectangle(final Rectangle2D rect) {
        draw(new Rectangle(rect));
    }

    /**
     * {@inheritDoc}
     */
    public void drawString(final Point2D point, final Font font, final String string) {
        content.setFontAndSize(fontMapper.awtToPdf(font), font.getSize2D());
        content.beginText();
        content.showTextAligned(PdfContentByte.ALIGN_LEFT, string, x(point.getX()),
                y(point.getY() + font.getSize2D()), 0);
        content.endText();
    }

    /**
     * {@inheritDoc}
     */
    public void drawStringRotated(final Point2D point, final Font font, final String string, final double theta) {
        // stub for now to satisfy compiler, PDFDriver isn't complete
    }

    protected void fill(final Shape shape) {

    }

    /**
     * {@inheritDoc}
     */
    public void fillArc(final Rectangle2D bounds, final double start, final double extent, final ArcStyle style) {
        fill(new Arc(bounds, start, extent, style));
    }

    /**
     * {@inheritDoc}
     */
    public void fillOval(final Rectangle2D bounds) {
        fill(new Oval(bounds));
    }

    /**
     * {@inheritDoc}
     */
    public void fillPolygon(final List<Point2D> points) {
        fill(new Polygon(points));
    }

    /**
     * {@inheritDoc}
     */
    public void fillRectangle(final Rectangle2D rect) {
        fill(new Rectangle(rect));
    }

    /**
     * {@inheritDoc}
     */
    public Rectangle2D getClip() {
        // TODO
        return null;
    }

    public Fill getFill() {
        return fill;
    }

    protected Image getImage(final URL url) {
        String key = url.toExternalForm();
        if (!imageCache.containsKey(key)) {
            try {
                // Image image = Image.getInstance(url);
                Image image = Image.getInstance(content, ImageIO.read(url), 0);
                imageCache.put(key, image);
            } catch (BadElementException e) {
                // TODO log
                e.printStackTrace();
            } catch (MalformedURLException e) {
                // TODO log
                e.printStackTrace();
            } catch (IOException e) {
                // TODO log
                e.printStackTrace();
            }
        }
        return imageCache.get(key);
    }

    /**
     * {@inheritDoc}
     */
    public Color getLineColor() {
        return lineColor;
    }

    /**
     * {@inheritDoc}
     */
    public LineStyle getLineStyle() {
        return lineStyle;
    }

    /**
     * {@inheritDoc}
     */
    public int getLineThickness() {
        return lineThickness;
    }

    /**
     * {@inheritDoc}
     */
    public Rectangle2D getStringBounds(final Font font, final String string) {
        content.setFontAndSize(fontMapper.awtToPdf(font), font.getSize2D());
        float w = content.getEffectiveStringWidth(string, false);
        float h = font.getSize();
        return new Rectangle2D.Double(0, h, w, h);
    }

    /**
     * {@inheritDoc}
     */
    public void popState() {
        if (!stateStack.isEmpty()) {
            State state = stateStack.pop();
            setFill(state.fill);
            setLineColor(state.lineColor);
            setLineStyle(state.lineStyle);
            setLineThickness(state.lineThickness);
        }
    }

    /**
     * {@inheritDoc}
     */
    public void popTransform() {
        // TODO
    }

    /**
     * {@inheritDoc}
     */
    public void pushState() {
        State state = new State();
        state.fill = getFill();
        state.lineColor = getLineColor();
        state.lineStyle = getLineStyle();
        state.lineThickness = getLineThickness();
        stateStack.push(state);
    }

    /**
     * {@inheritDoc}
     */
    public void pushTransform(final AffineTransform transform) {
        // TODO
    }

    /**
     * {@inheritDoc}
     */
    public void setClip(final Rectangle2D r) {
        // TODO
    }

    /**
     * {@inheritDoc}
     */
    public void setFill(final Fill fill) {
        this.fill = fill;
    }

    /**
     * {@inheritDoc}
     */
    public void setLineColor(final Color lineColor) {
        this.lineColor = lineColor;
    }

    /**
     * {@inheritDoc}
     */
    public void setLineStyle(final LineStyle lineStyle) {
        this.lineStyle = lineStyle;
    }

    /**
     * {@inheritDoc}
     */
    public void setLineThickness(final int lineThickness) {
        this.lineThickness = lineThickness;
    }

    protected float x(final double x) {
        return (float) x + paper.getPrintableX();
    }

    protected float y(final double y) {
        return paper.getPrintableHeight() - (float) y + paper.getPrintableY();
    }
}