Package org.locationtech.udig.printing.ui.pdf

Source Code of org.locationtech.udig.printing.ui.pdf.ExportPDFWizard

/*
*    uDig - User Friendly Desktop Internet GIS client
*    http://udig.refractions.net
*    (C) 2012, Refractions Research Inc.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* (http://www.eclipse.org/legal/epl-v10.html), and the Refractions BSD
* License v1.0 (http://udig.refractions.net/files/bsd3-v10.html).
*/
package org.locationtech.udig.printing.ui.pdf;

import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.awt.print.PageFormat;
import java.awt.print.PrinterException;
import java.io.ByteArrayOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.URL;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;

import javax.imageio.ImageIO;

import org.locationtech.udig.catalog.IGeoResource;
import org.locationtech.udig.core.internal.Icons;
import org.locationtech.udig.printing.model.Box;
import org.locationtech.udig.printing.model.ModelFactory;
import org.locationtech.udig.printing.model.Page;
import org.locationtech.udig.printing.ui.Template;
import org.locationtech.udig.printing.ui.TemplateFactory;
import org.locationtech.udig.printing.ui.internal.Messages;
import org.locationtech.udig.printing.ui.internal.PrintingEngine;
import org.locationtech.udig.printing.ui.internal.PrintingPlugin;
import org.locationtech.udig.project.IBlackboard;
import org.locationtech.udig.project.internal.Layer;
import org.locationtech.udig.project.internal.Map;
import org.locationtech.udig.project.internal.command.navigation.SetViewportBBoxCommand;
import org.locationtech.udig.project.ui.ApplicationGIS;
import org.locationtech.udig.project.ui.BoundsStrategy;
import org.locationtech.udig.project.ui.SelectionStyle;
import org.locationtech.udig.project.ui.ApplicationGIS.DrawMapParameter;
import org.locationtech.udig.project.ui.internal.MapEditorInput;

import org.eclipse.draw2d.geometry.Dimension;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.jface.resource.ImageRegistry;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.wizard.Wizard;
import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.IExportWizard;
import org.eclipse.ui.IWorkbench;
import org.eclipse.ui.PlatformUI;
import org.opengis.coverage.grid.GridCoverageReader;

import com.lowagie.text.Document;
import com.lowagie.text.DocumentException;
import com.lowagie.text.Image;
import com.lowagie.text.PageSize;
import com.lowagie.text.Rectangle;
import com.lowagie.text.pdf.PdfContentByte;
import com.lowagie.text.pdf.PdfWriter;

/**
* A user interface for choosing an export template and other export options.
* The wizard is configurable by placing an ExportPDFWizardConfigBean on the
* map blackboard (see ExportPDFWizardConfigBean for the blackboard key).
* <p>
*
* </p>
* @author brocka
* @since 1.1.0
*/
public class ExportPDFWizard extends Wizard implements IExportWizard {
   
    private Map map;
    private ExportPDFWizardPage1 page1;
   
    public ExportPDFWizard(){
        PrintingPlugin plugin = PrintingPlugin.getDefault();
       
       
       
        java.util.Map<String, TemplateFactory> templateFactories = plugin.getTemplateFactories();
       
        setWindowTitle(Messages.ExportPDFWizard_Title);
       
        String key = Icons.WIZBAN +"exportpdf_wiz.gif"; //$NON-NLS-1$
        ImageRegistry imageRegistry = plugin.getImageRegistry();       
        ImageDescriptor image = imageRegistry.getDescriptor( key );
        if( image == null ){
            URL banURL = plugin.getBundle().getResource( "icons/" + key ); //$NON-NLS-1$
            image = ImageDescriptor.createFromURL( banURL );
            imageRegistry.put( key, image );
        }
        setDefaultPageImageDescriptor( image );       
       
        //get copy of map
        IEditorInput input = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage()
        .getActiveEditor().getEditorInput();
        map = (Map) ((MapEditorInput) input).getProjectElement();
       
        //get configuration for this wizard
        IBlackboard mapBlackboard = map.getBlackboard();
        ExportPDFWizardConfigBean config =
            (ExportPDFWizardConfigBean)mapBlackboard.get(ExportPDFWizardConfigBean.BLACKBOARD_KEY);
       
        page1 = new ExportPDFWizardPage1(templateFactories, config);
        addPage(page1);
    }
   
    @Override   
    public boolean canFinish() {
        return page1.isPageComplete();
    }
   
    @Override
    public boolean performFinish() {
       
        //create the document                
        Rectangle suggestedPageSize = getITextPageSize(page1.getPageSize());               
        Rectangle pageSize = rotatePageIfNecessary(suggestedPageSize); //rotate if we need landscape
       
        Document document = new Document(pageSize)
       
       
        try {
           
            //Basic setup of the Document, and get instance of the iText Graphics2D
            //   to pass along to uDig's standard "printing" code.
            String outputFile = page1.getDestinationDir()+
                System.getProperty("file.separator")+ //$NON-NLS-1$
                page1.getOutputFile();
            PdfWriter writer = PdfWriter.getInstance(document, new FileOutputStream(outputFile));
            document.open();           
            Graphics2D graphics = null;
            Template template = getTemplate();
           
            int i = 0;
            int numPages = 1;
            do {
               
                //sets the active page
                template.setActivePage(i);
               
                PdfContentByte cb = writer.getDirectContent();    
               
                Page page = makePage(pageSize, document, template);
               
                graphics = cb.createGraphics(pageSize.getWidth(), pageSize.getHeight());
                        
                //instantiate a PrinterEngine (pass in the Page instance)
                PrintingEngine engine = new PrintingEngine(page);
               
                //make page format
                PageFormat pageFormat = new PageFormat();
                pageFormat.setOrientation(PageFormat.PORTRAIT);
                java.awt.print.Paper awtPaper = new java.awt.print.Paper();
                awtPaper.setSize(pageSize.getWidth() * 3, pageSize.getHeight() *3);
                awtPaper.setImageableArea(0, 0, pageSize.getWidth(), pageSize.getHeight());
                pageFormat.setPaper(awtPaper);
               
                //run PrinterEngine's print function
                engine.print(graphics, pageFormat, 0);
                 
                graphics.dispose();
                document.newPage();
                if (i == 0) {
                    numPages = template.getNumPages();
                }
                i++;
               
            } while (i < numPages);
           
            //cleanup
            document.close();
            writer.close();
        }
        catch (DocumentException e) {
            e.printStackTrace();
            return false;
        }
        catch (IOException e) {
            e.printStackTrace();
            return false;
        } catch (PrinterException e) {
            e.printStackTrace();
        }        
        return true;
    }

    /**
     * converts a page size "name" (such as "A3" or "A4" into a
     * rectangle object that iText will understand.
     */
    private Rectangle getITextPageSize(String pageSizeName) {
        if (pageSizeName.equals("A3")) //$NON-NLS-1$
            return PageSize.A3;
        if (pageSizeName.equals("A4")) //$NON-NLS-1$
            return PageSize.A4;
        throw new IllegalArgumentException(pageSizeName + " is not a supported page size"); //$NON-NLS-1$
    }
   
   
    protected Rectangle rotatePageIfNecessary(Rectangle suggestedPageSize) {
        //rotate the page if dimensions are given as portrait, but template prefers landscape
        if (suggestedPageSize.getHeight() > suggestedPageSize.getWidth() && page1.isLandscape()) {
            float temp = suggestedPageSize.getWidth();
            float newWidth = suggestedPageSize.getHeight();
            float newHeight = temp;
            return new Rectangle(suggestedPageSize.getHeight(), suggestedPageSize.getWidth());
        }
        return suggestedPageSize;
    }
   
    /**
     * Creates a page based on the template selected in the wizard
     * **Note: this function may swap the width and height if the
     * template prefers different page orientation.
     *
     * @return a page
     */
    protected Page makePage(Rectangle pageSize, Document doc, Template template) {
       
        Map mapOnlyRasterLayers = null;
        Map mapNoRasterLayers = null;
       
        // **Note: the iText API doesn't render rasters at a high enough resolution if
        //they are written to the PDF via graphics2d.  To work around this problem, I
        //create two copies of the map: one with only the raster layers, and one with
        //everything else.
        //The "everything else" map gets drawn by a graphics2d.  The other layer must be
        //rasterized and inserted into the PDF via iText's API. 
       
        //make one copy of the map with no raster layers
        mapNoRasterLayers = (Map) ApplicationGIS.copyMap(map);
        List<Layer> layersNoRasters = mapNoRasterLayers.getLayersInternal();
        List<Layer> toRemove = new ArrayList<Layer>();
        for (Layer layer : layersNoRasters ) {
            for (IGeoResource resource : layer.getGeoResources()) {
                if (resource.canResolve(GridCoverageReader.class)) {
                    toRemove.add(layer);
                }
            }
        }
        layersNoRasters.removeAll(toRemove);            
       
       
        //adjust scale       
        double currentViewportScaleDenom = map.getViewportModel().getScaleDenominator();
        if (currentViewportScaleDenom == -1)
            throw new IllegalStateException("no scale denominator is available from the viewport model"); //$NON-NLS-1$
       
        if (page1.getScaleOption() == PrintWizardPage1.CUSTOM_MAP_SCALE) {
            float customScale = page1.getCustomScale();
            template.setMapScaleHint(customScale);
        }
        else if (page1.getScaleOption() == PrintWizardPage1.CURRENT_MAP_SCALE) {
           template.setMapScaleHint(currentViewportScaleDenom);           
        }
        else if (page1.getScaleOption() == PrintWizardPage1.ZOOM_TO_SELECTION) {
            template.setZoomToSelectionHint(true);
            template.setMapScaleHint(currentViewportScaleDenom);
       
       
        //3. make the page itself
        Page page = ModelFactory.eINSTANCE.createPage();
        page.setSize(new Dimension((int)pageSize.getWidth(), (int)pageSize.getHeight()));

        //page name stuff not required, because this page will just get discarded
        MessageFormat formatter = new MessageFormat(Messages.CreatePageAction_newPageName, Locale.getDefault());
        if (page.getName() == null || page.getName().length() == 0) {
            page.setName(formatter.format(new Object[] { mapNoRasterLayers.getName() }));
        }

        template.init(page, mapNoRasterLayers);
       
        if (page1.getRasterEnabled()) {
            //make another copy with only raster layers
            mapOnlyRasterLayers = (Map) ApplicationGIS.copyMap(map);
            List<Layer> layersOnlyRasters = mapOnlyRasterLayers.getLayersInternal();
            List<Layer> toRemove2 = new ArrayList<Layer>();
            for (Layer layer : layersOnlyRasters ) {
                for (IGeoResource resource : layer.getGeoResources()) {
                    if (!resource.canResolve(GridCoverageReader.class)) {
                        toRemove2.add(layer);
                    }
                }
            }
            layersOnlyRasters.removeAll(toRemove2);
           
            //set bounds to match the other map
            SetViewportBBoxCommand cmdBbox = new SetViewportBBoxCommand(mapNoRasterLayers.getViewportModel().getBounds());
            mapOnlyRasterLayers.sendCommandSync(cmdBbox);
           
            if (layersNoRasters.size() > 0) {
                writeRasterLayersOnlyToDocument(mapOnlyRasterLayers, template.getMapBounds(), doc, page.getSize(), /*currentViewportScaleDenom*/mapNoRasterLayers.getViewportModel().getScaleDenominator());
            }
        }
       
        //copy the boxes from the template into the page
        Iterator<Box> iter = template.iterator();       
        while (iter.hasNext()) {
            page.getBoxes().add(iter.next());
        }
        return page;
       
       
        //TODO Throw some sort of exception if the page can't be created

    }

   
    /**
     * Gets the template selected in the wizard.
     *
     * @return a template
     */
    private Template getTemplate() {
          
        TemplateFactory templateFactory = page1.getTemplateFactory();
        Template template = templateFactory.createTemplate();
               
        return template;
    }
   
    public void init( IWorkbench workbench, IStructuredSelection selection ) {
    }

    /**
     * double scaleDenom = page1.isCustomScale() ? page1.getCustomScale() : map.getViewportModel().getScaleDenominator();
     *
     * @param mapWithRasterLayersOnly a map with only raster layers
     * @param mapBoundsInTemplate a rectangle indicating the coordinates of the top left, width and height
     * (where the coordinate system has (0,0) in the top left.
     * @param doc the PDF document object
     */
    private void writeRasterLayersOnlyToDocument(Map mapWithRasterLayersOnly,
            org.eclipse.swt.graphics.Rectangle mapBoundsInTemplate,
            Document doc,
            Dimension pageSize,
            double currentViewportScaleDenom) {
       
        //set dimensions of the raster image to be the same ratio as
        //the required map bounds within the page, but scaled up so
        //we can achieve a higher DPI when we later insert the image
        //into the page (90 refers to the default DPI)
        int w = mapBoundsInTemplate.width * page1.getDpi()/90;
        int h = mapBoundsInTemplate.height * page1.getDpi()/90;
       
        BufferedImage imageOfRastersOnly = new BufferedImage(w,
                h,
                BufferedImage.TYPE_INT_RGB);
        Graphics2D g = imageOfRastersOnly.createGraphics();
       
        //define a DrawMapParameter object with a custom BoundsStrategy if a custom scale is set
        DrawMapParameter drawMapParameter = null;
       
        double scaleDenom = (page1.getScaleOption() == ExportPDFWizardPage1.CUSTOM_MAP_SCALE) ? page1.getCustomScale() : currentViewportScaleDenom;
       
        drawMapParameter =
            new DrawMapParameter(g,
                             new java.awt.Dimension(w, h),
                             mapWithRasterLayersOnly,
                             new BoundsStrategy(scaleDenom),
                             page1.getDpi(),
                             SelectionStyle.EXCLUSIVE_ALL,
                             null);

       
        try {
           
            //draw the map (at a high resolution as specified above)
            ApplicationGIS.drawMap(drawMapParameter);
            Image img = Image.getInstance(bufferedImage2ByteArray(imageOfRastersOnly));
           
            //scale the image down to fit into the page
            img.scaleAbsolute(mapBoundsInTemplate.width, mapBoundsInTemplate.height);
           
            //set the location of the image
            int left = mapBoundsInTemplate.x;
            int bottom = pageSize.height - mapBoundsInTemplate.height - mapBoundsInTemplate.y;
            img.setAbsolutePosition(left, bottom); //(0,0) is bottom left in the PDF coordinate system
        
            doc.add(img);
            addWhiteMapBorder(img, doc);
           
        }
        catch (Exception e) {
            //TODO: fail gracefully.
        }
       
    }
   
    /**
     * This function is used to draw very thin white borders over the outer
     * edge of the raster map.  It's necessary because the map edge "bleeds" into
     * the adjacent pixels, and we need to cover that.
     *
     * I think this quirky behaviour is possibly an iText bug
     */
    private void addWhiteMapBorder(Image img,
            Document doc) {

        try {
           
            Color color = Color.white;
            int borderWidth = 1;
           
            BufferedImage bufferedTop = new BufferedImage((int)img.getScaledWidth(),
                    borderWidth,
                    BufferedImage.TYPE_INT_RGB);
            Graphics2D g1 = bufferedTop.createGraphics();
            g1.setBackground(color);
            g1.clearRect(0, 0, bufferedTop.getWidth(),bufferedTop.getHeight());
            Image top = Image.getInstance(bufferedImage2ByteArray(bufferedTop));
            top.setAbsolutePosition(img.getAbsoluteX(), img.getAbsoluteY()+img.getScaledHeight()-bufferedTop.getHeight()/2);
           
            BufferedImage bufferedBottom = new BufferedImage((int)img.getScaledWidth(),
                    borderWidth,
                    BufferedImage.TYPE_INT_RGB);
            Graphics2D g2 = bufferedBottom.createGraphics();
            g2.setBackground(color);
            g2.clearRect(0, 0, bufferedBottom.getWidth(),bufferedBottom.getHeight());
            Image bottom = Image.getInstance(bufferedImage2ByteArray(bufferedBottom));
            bottom.setAbsolutePosition(img.getAbsoluteX(), img.getAbsoluteY()-bufferedTop.getHeight()/2);
           
            BufferedImage bufferedLeft = new BufferedImage(borderWidth,
                    (int)img.getScaledHeight(),
                    BufferedImage.TYPE_INT_RGB);
            Graphics2D g3 = bufferedLeft.createGraphics();
            g3.setBackground(color);
            g3.clearRect(0, 0, bufferedLeft.getWidth(),bufferedLeft.getHeight());
            Image left = Image.getInstance(bufferedImage2ByteArray(bufferedLeft));
            left.setAbsolutePosition(img.getAbsoluteX()-bufferedLeft.getWidth()/2, img.getAbsoluteY());
           
            BufferedImage bufferedRight = new BufferedImage(borderWidth,
                    (int)img.getScaledHeight(),
                    BufferedImage.TYPE_INT_RGB);
            Graphics2D g4 = bufferedRight.createGraphics();
            g4.setBackground(color);
            g4.clearRect(0, 0, bufferedRight.getWidth(),bufferedRight.getHeight());
            Image right = Image.getInstance(bufferedImage2ByteArray(bufferedRight));
            right.setAbsolutePosition(img.getAbsoluteX()+img.getScaledWidth()-bufferedRight.getWidth()/2, img.getAbsoluteY());
           
           
            doc.add(top);
            doc.add(bottom);
            doc.add(left);
            doc.add(right);
        }
        catch (Exception e) {
            e.printStackTrace();
        }
    }
   
    private static byte[] bufferedImage2ByteArray(BufferedImage img) {
        try {
            ByteArrayOutputStream baos = new ByteArrayOutputStream(1000);
            ImageIO.write(img, "png", baos); //$NON-NLS-1$
            baos.flush();
            byte[] result = baos.toByteArray();
            baos.close();
            return result;
        }
        catch(Exception e) {
            e.printStackTrace();
            return new byte[0];
        }
    }
   
   
}
TOP

Related Classes of org.locationtech.udig.printing.ui.pdf.ExportPDFWizard

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.