Package org.gephi.io.exporter.preview

Source Code of org.gephi.io.exporter.preview.PDFExporter

/*
Copyright 2008-2010 Gephi
Authors : Jeremy Subtil <jeremy.subtil@gephi.org>,
Mathieu Bastian <mathieu.bastian@gephi.org>
Website : http://www.gephi.org

This file is part of Gephi.

Gephi is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.

Gephi is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU Affero General Public License for more details.

You should have received a copy of the GNU Affero General Public License
along with Gephi.  If not, see <http://www.gnu.org/licenses/>.
*/
package org.gephi.io.exporter.preview;

import com.itextpdf.text.BaseColor;
import com.itextpdf.text.Document;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.PageSize;
import com.itextpdf.text.Rectangle;
import com.itextpdf.text.pdf.BaseFont;
import com.itextpdf.text.pdf.DefaultFontMapper;
import com.itextpdf.text.pdf.FontMapper;
import com.itextpdf.text.pdf.PdfContentByte;
import com.itextpdf.text.pdf.PdfWriter;
import java.awt.Font;
import java.awt.GraphicsEnvironment;
import java.awt.geom.AffineTransform;
import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import org.gephi.io.exporter.spi.ByteExporter;
import org.gephi.io.exporter.spi.VectorExporter;
import org.gephi.preview.api.BidirectionalEdge;
import org.gephi.preview.api.Color;
import org.gephi.preview.api.CubicBezierCurve;
import org.gephi.preview.api.DirectedEdge;
import org.gephi.preview.api.Edge;
import org.gephi.preview.api.EdgeArrow;
import org.gephi.preview.api.EdgeLabel;
import org.gephi.preview.api.EdgeMiniLabel;
import org.gephi.preview.api.Graph;
import org.gephi.preview.api.GraphRenderer;
import org.gephi.preview.api.GraphSheet;
import org.gephi.preview.api.Node;
import org.gephi.preview.api.NodeLabel;
import org.gephi.preview.api.NodeLabelBorder;
import org.gephi.preview.api.Point;
import org.gephi.preview.api.PreviewController;
import org.gephi.preview.api.SelfLoop;
import org.gephi.preview.api.UndirectedEdge;
import org.gephi.preview.api.UnidirectionalEdge;
import org.gephi.utils.longtask.spi.LongTask;
import org.gephi.utils.progress.Progress;
import org.gephi.utils.progress.ProgressTicket;
import org.gephi.project.api.Workspace;
import org.openide.util.Exceptions;
import org.openide.util.Lookup;
import org.openide.util.Utilities;
import sun.font.FontManager;

/**
* Class exporting the preview graph as a PDF file.
*
* @author Jérémy Subtil <jeremy.subtil@gephi.org>
* @author Mathieu Bastian
*/
public class PDFExporter implements GraphRenderer, ByteExporter, VectorExporter, LongTask {

    private ProgressTicket progress;
    private Workspace workspace;
    private OutputStream stream;
    private boolean cancel = false;
    private PdfContentByte cb;
    private Document document;
    //Parameters
    private float marginTop = 18f;
    private float marginBottom = 18f;
    private float marginLeft = 18f;
    private float marginRight = 18f;
    private boolean landscape = false;
    private Rectangle pageSize = PageSize.A4;
    private FontMapper fontMapper;

    static {
        //Required in Headless to not get NPE on FontManager.getFileNameForFontName()
        GraphicsEnvironment e = GraphicsEnvironment.getLocalGraphicsEnvironment();
        e.getAllFonts();
    }

    public boolean execute() {
        // fetches the preview graph sheet
        PreviewController controller = Lookup.getDefault().lookup(PreviewController.class);
        GraphSheet graphSheet = controller.getGraphSheet();
        Graph graph = graphSheet.getGraph();
        try {
            exportData(graph);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }

        return !cancel;
    }

    /**
     * Does export the preview graph as an SVG image.
     *
     * @param file         the output SVG file
     * @throws Exception
     */
    private void exportData(Graph graph) throws Exception {
        Progress.start(progress);

        // calculates progress units count
        int max = 0;
        if (graph.showNodes()) {
            max += graph.countNodes();
        }
        if (graph.showEdges()) {
            max += graph.countUnidirectionalEdges() + graph.countBidirectionalEdges();
            if (graph.showSelfLoops()) {
                max += graph.countSelfLoops();
            }
        }

        Progress.switchToDeterminate(progress, max);

        Rectangle size = new Rectangle(pageSize);
        if (landscape) {
            size = new Rectangle(pageSize.rotate());
        }
        size.setBackgroundColor(new BaseColor(Lookup.getDefault().lookup(PreviewController.class).getModel().getBackgroundColor()));
        document = new Document(size);
        PdfWriter pdfWriter = PdfWriter.getInstance(document, stream);
        document.open();
        cb = pdfWriter.getDirectContent();
        cb.saveState();

        //Limits
        float minX = Float.POSITIVE_INFINITY;
        float maxX = Float.NEGATIVE_INFINITY;
        float minY = Float.POSITIVE_INFINITY;
        float maxY = Float.NEGATIVE_INFINITY;
        for (Node n : graph.getNodes()) {
            minX = Math.min(minX, n.getPosition().getX() - n.getRadius() - n.getBorderWidth());
            maxX = Math.max(maxX, n.getPosition().getX() + n.getRadius() + n.getBorderWidth());
            minY = Math.min(minY, -n.getPosition().getY() - n.getRadius() - n.getBorderWidth());
            maxY = Math.max(maxY, -n.getPosition().getY() + n.getRadius() + n.getBorderWidth());
        }

        double graphWidth = maxX - minX;
        double graphHeight = maxY - minY;
        double centerX = minX + graphWidth / 2.;
        double centerY = minY + graphHeight / 2.;

        //Transform
        double pageWidth = size.getWidth() - marginLeft - marginRight;
        double pageHeight = size.getHeight() - marginTop - marginBottom;
        double ratioWidth = pageWidth / graphWidth;
        double ratioHeight = pageHeight / graphHeight;
        double scale = ratioWidth < ratioHeight ? ratioWidth : ratioHeight;
        double translateX = (marginLeft + pageWidth / 2.) / scale;
        double translateY = (marginBottom + pageHeight / 2.) / scale;
        cb.transform(AffineTransform.getTranslateInstance(-centerX * scale, -centerY * scale));
        cb.transform(AffineTransform.getScaleInstance(scale, scale));
        cb.transform(AffineTransform.getTranslateInstance(translateX, translateY));

        renderGraph(graph);
        Progress.switchToIndeterminate(progress);

        cb.restoreState();
        document.close();

        Progress.finish(progress);
    }

    public boolean cancel() {
        cancel = true;
        return true;
    }

    public void renderGraph(Graph graph) {
        if (graph.showEdges()) {
            renderGraphEdges(graph);
        }

        if (graph.showNodes()) {
            renderGraphNodes(graph);
        }

        renderGraphLabels(graph);

        renderGraphLabelBorders(graph);
    }

    public void renderGraphEdges(Graph graph) {
        renderGraphUnidirectionalEdges(graph);
        renderGraphBidirectionalEdges(graph);
        renderGraphUndirectedEdges(graph);

        if (graph.showSelfLoops()) {
            renderGraphSelfLoops(graph);
        }
    }

    public void renderGraphSelfLoops(Graph graph) {
        for (SelfLoop sl : graph.getSelfLoops()) {
            renderSelfLoop(sl);
        }
    }

    public void renderGraphUnidirectionalEdges(Graph graph) {
        for (UnidirectionalEdge edge : graph.getUnidirectionalEdges()) {
            renderDirectedEdge(edge);
        }
    }

    public void renderGraphBidirectionalEdges(Graph graph) {
        for (BidirectionalEdge edge : graph.getBidirectionalEdges()) {
            renderDirectedEdge(edge);
        }
    }

    public void renderGraphUndirectedEdges(Graph graph) {
        for (UndirectedEdge e : graph.getUndirectedEdges()) {
            renderEdge(e);
        }
    }

    public void renderGraphNodes(Graph graph) {
        for (Node n : graph.getNodes()) {
            renderNode(n);
        }
    }

    public void renderGraphLabels(Graph graph) {
        for (UnidirectionalEdge e : graph.getUnidirectionalEdges()) {
            if (!e.isCurved()) {
                if (e.showLabel() && e.hasLabel() && e.getLabel().getFont() != null) {
                    renderEdgeLabel(e.getLabel());
                }

                if (e.showMiniLabels()) {
                    renderEdgeMiniLabels(e);
                }
            }
        }

        for (BidirectionalEdge e : graph.getBidirectionalEdges()) {
            if (!e.isCurved()) {
                if (e.showLabel() && e.hasLabel() && e.getLabel().getFont() != null) {
                    renderEdgeLabel(e.getLabel());
                }

                if (e.showMiniLabels()) {
                    renderEdgeMiniLabels(e);
                }
            }
        }

        for (UndirectedEdge e : graph.getUndirectedEdges()) {
            if (e.showLabel() && !e.isCurved() && e.hasLabel() && e.getLabel().getFont() != null) {
                renderEdgeLabel(e.getLabel());
            }
        }

        for (Node n : graph.getNodes()) {
            if (n.showLabel() && n.hasLabel() && n.getLabel().getFont() != null) {
                renderNodeLabel(n.getLabel());
            }
        }
    }

    public void renderGraphLabelBorders(Graph graph) {
    }

    public void renderNode(Node node) {
        Point center = node.getPosition();
        Color c = node.getColor();
        Color bc = node.getBorderColor();

        cb.setRGBColorStroke(bc.getRed(), bc.getGreen(), bc.getBlue());
        cb.setLineWidth(node.getBorderWidth());
        cb.setRGBColorFill(c.getRed(), c.getGreen(), c.getBlue());
        cb.circle(center.getX(), -center.getY(), node.getRadius());
        cb.fillStroke();
    }

    public void renderNodeLabel(NodeLabel label) {
        Point p = label.getPosition();
        Font font = label.getFont();

        setFillColor(label.getColor());

        try {
            BaseFont bf = genBaseFont(font);
            float ascent = bf.getAscentPoint(label.getValue(), font.getSize());
            float descent = bf.getDescentPoint(label.getValue(), font.getSize());
            float textHeight = (ascent - descent) / 2f;

            cb.beginText();
            cb.setFontAndSize(bf, font.getSize());
            cb.showTextAligned(PdfContentByte.ALIGN_CENTER, label.getValue(), p.getX(), -p.getY() - textHeight, 0);
            cb.endText();
        } catch (Exception ex) {
            Exceptions.printStackTrace(ex);
        }
    }

    public void renderNodeLabelBorder(NodeLabelBorder border) {
    }

    public void renderSelfLoop(SelfLoop selfLoop) {
        cubicBezierCurve(selfLoop.getCurve());
        setStrokeColor(selfLoop.getColor());
        cb.setLineWidth(selfLoop.getThickness() * selfLoop.getScale());
        cb.stroke();
    }

    public void renderDirectedEdge(DirectedEdge edge) {
        renderEdge(edge);

        if (!edge.isCurved() && edge.showArrows()) {
            renderEdgeArrows(edge);
        }
    }

    public void renderEdge(Edge edge) {
        if (edge.isCurved()) {
            renderCurvedEdge(edge);
        } else {
            renderStraightEdge(edge);
        }

        Progress.progress(progress);
    }

    public void renderStraightEdge(Edge edge) {
        line(edge.getNode1().getPosition(), edge.getNode2().getPosition());
        setStrokeColor(edge.getColor());
        cb.setLineWidth(edge.getThickness() * edge.getScale());
        cb.stroke();
    }

    public void renderCurvedEdge(Edge edge) {
        for (CubicBezierCurve c : edge.getCurves()) {
            cubicBezierCurve(c);
            setStrokeColor(edge.getColor());
            cb.setLineWidth(edge.getThickness() * edge.getScale());
            cb.stroke();
        }
    }

    public void renderEdgeArrows(DirectedEdge edge) {
        for (EdgeArrow a : edge.getArrows()) {
            renderEdgeArrow(a);
        }
    }

    public void renderEdgeMiniLabels(DirectedEdge edge) {
        for (EdgeMiniLabel ml : edge.getMiniLabels()) {
            renderEdgeMiniLabel(ml);
        }
    }

    public void renderEdgeArrow(EdgeArrow arrow) {
        Point pt1 = arrow.getPt1();
        Point pt2 = arrow.getPt2();
        Point pt3 = arrow.getPt3();

        cb.moveTo(pt1.getX(), -pt1.getY());
        cb.lineTo(pt2.getX(), -pt2.getY());
        cb.lineTo(pt3.getX(), -pt3.getY());
        cb.closePath();

        setFillColor(arrow.getColor());
        cb.fill();
    }

    public void renderEdgeLabel(EdgeLabel label) {
        Point p = label.getPosition();
        Font font = label.getFont();

        setFillColor(label.getColor());

        try {
            BaseFont bf = genBaseFont(font);

            cb.beginText();
            cb.setFontAndSize(bf, font.getSize());
            cb.showTextAligned(PdfContentByte.ALIGN_CENTER, label.getValue(), p.getX(), -p.getY(), (float) (Math.toDegrees(-label.getAngle())));
            cb.endText();
        } catch (Exception ex) {
            Exceptions.printStackTrace(ex);
        }
    }

    public void renderEdgeMiniLabel(EdgeMiniLabel miniLabel) {
        Point p = miniLabel.getPosition();
        Font font = miniLabel.getFont();

        setFillColor(miniLabel.getColor());

        try {
            BaseFont bf = genBaseFont(font);

            cb.beginText();
            cb.setFontAndSize(bf, font.getSize());
            cb.showTextAligned(miniLabel.getHAlign().toIText(), miniLabel.getValue(), p.getX(), -p.getY(), (float) (Math.toDegrees(-miniLabel.getAngle())));
            cb.endText();
        } catch (Exception ex) {
            Exceptions.printStackTrace(ex);
        }
    }

    /**
     * Generates an iText BaseFont object from a Java Font one.
     *
     * @param font  the reference font
     * @return      the generated BaseFont
     * @throws      DocumentException
     * @throws      IOException
     */
    private BaseFont genBaseFont(java.awt.Font font) throws DocumentException, IOException {
        if (font != null) {
            try {
                loadFont(font);
            } catch (Exception e) {
                e.printStackTrace();
                return BaseFont.createFont();
            }

            return fontMapper.awtToPdf(font);
        }
        return BaseFont.createFont();
    }

    private void loadFont(java.awt.Font font) throws Exception {
        if (fontMapper == null) {
            fontMapper = new DefaultFontMapper();
        }
        if (fontMapper instanceof DefaultFontMapper) {
            if (Utilities.isMac()) {
                String fontName = font.getName();
                if (!((DefaultFontMapper) fontMapper).getMapper().containsKey(fontName)) {
                    File homeLibraryFonts = new File(System.getProperty("user.home") + "/Library/Fonts");
                    File systemLibraryFonts = new File("/System/Library/Fonts");
                    File libraryFonts = new File("/Library/Fonts");
                    File fontResult = lookFor(fontName, homeLibraryFonts);
                    fontResult = fontResult != null ? fontResult : lookFor(fontName, systemLibraryFonts);
                    fontResult = fontResult != null ? fontResult : lookFor(fontName, libraryFonts);
                    if (fontResult != null) {
                        fontName = fontResult.getName();
                        String fontFilePath = fontResult.getAbsolutePath();
                        loadFont(fontName, fontFilePath);
                    }
                }
            } else {
                String fontName = FontManager.getFileNameForFontName(font.getFontName());
                if (!((DefaultFontMapper) fontMapper).getMapper().containsKey(fontName)) {
                    String fontFilePath = FontManager.getFontPath(false);
                    fontFilePath = fontFilePath + "/" + fontName;
                    loadFont(fontName, fontFilePath);
                }
            }
        }
    }

    private void loadFont(String fontName, String fontFilePath) throws Exception {
        if (fontName != null && !fontName.isEmpty()) {
            fontName = fontName.toLowerCase();
            if (fontFilePath != null && !fontFilePath.isEmpty()) {
                if (fontName.endsWith(".ttf") || fontName.endsWith(".otf") || fontName.endsWith(".afm")) {
                    Object allNames[] = BaseFont.getAllFontNames(fontFilePath, BaseFont.CP1252, null);
                    ((DefaultFontMapper) fontMapper).insertNames(allNames, fontFilePath);
                } else if (fontName.endsWith(".ttc")) {
                    String ttcs[] = BaseFont.enumerateTTCNames(fontFilePath);
                    for (int j = 0; j < ttcs.length; ++j) {
                        String nt = fontFilePath + "," + j;
                        Object allNames[] = BaseFont.getAllFontNames(nt, BaseFont.CP1252, null);
                        ((DefaultFontMapper) fontMapper).insertNames(allNames, nt);
                    }
                }
            }
        }
    }

    private File lookFor(String fileName, File folder) {
        if (!folder.isDirectory()) {
            return null;
        }
        File lookFile = new File(folder, fileName + ".ttf");
        if (lookFile.exists()) {
            return lookFile;
        }
        lookFile = new File(folder, fileName + ".otf");
        if (lookFile.exists()) {
            return lookFile;
        }
        lookFile = new File(folder, fileName + ".ttc");
        if (lookFile.exists()) {
            return lookFile;
        }
        lookFile = new File(folder, fileName + ".afm");
        if (lookFile.exists()) {
            return lookFile;
        }
        return null;
    }

    /**
     * Draws a line.
     *
     * @param start  the start of the line to draw
     * @param end    the end of the line to draw
     */
    private void line(Point start, Point end) {
        cb.moveTo(start.getX(), -start.getY());
        cb.lineTo(end.getX(), -end.getY());
    }

    /**
     * Draws a cubic bezier curve.
     *
     * @param curve  the curve to draw
     */
    private void cubicBezierCurve(CubicBezierCurve curve) {
        Point pt1 = curve.getPt1();
        Point pt2 = curve.getPt2();
        Point pt3 = curve.getPt3();
        Point pt4 = curve.getPt4();

        cb.moveTo(pt1.getX(), -pt1.getY());
        cb.curveTo(pt2.getX(), -pt2.getY(), pt3.getX(), -pt3.getY(), pt4.getX(), -pt4.getY());
    }

    /**
     * Defines the stroke color.
     *
     * @param color  the stroke color to set
     */
    private void setStrokeColor(Color color) {
        cb.setRGBColorStroke(color.getRed(), color.getGreen(), color.getBlue());
    }

    /**
     * Defines the filling color.
     *
     * @param color  the filling color to set
     */
    private void setFillColor(Color color) {
        cb.setRGBColorFill(color.getRed(), color.getGreen(), color.getBlue());
    }

    public float getMarginBottom() {
        return marginBottom;
    }

    public void setMarginBottom(float marginBottom) {
        this.marginBottom = marginBottom;
    }

    public float getMarginLeft() {
        return marginLeft;
    }

    public void setMarginLeft(float marginLeft) {
        this.marginLeft = marginLeft;
    }

    public float getMarginRight() {
        return marginRight;
    }

    public void setMarginRight(float marginRight) {
        this.marginRight = marginRight;
    }

    public float getMarginTop() {
        return marginTop;
    }

    public void setMarginTop(float marginTop) {
        this.marginTop = marginTop;
    }

    public boolean isLandscape() {
        return landscape;
    }

    public void setLandscape(boolean landscape) {
        this.landscape = landscape;
    }

    public Rectangle getPageSize() {
        return pageSize;
    }

    public void setPageSize(Rectangle pageSize) {
        this.pageSize = pageSize;
    }

    public void setProgressTicket(ProgressTicket progressTicket) {
        this.progress = progressTicket;
    }

    public void setOutputStream(OutputStream stream) {
        this.stream = stream;
    }

    public Workspace getWorkspace() {
        return workspace;
    }

    public void setWorkspace(Workspace workspace) {
        this.workspace = workspace;
    }

    public void setFontMapper(FontMapper fontMapper) {
        this.fontMapper = fontMapper;
    }

    public FontMapper getFontMapper() {
        return fontMapper;
    }
}
TOP

Related Classes of org.gephi.io.exporter.preview.PDFExporter

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.