Work at SourceForge, help us to make it a better place! We have an immediate need for a Support Technician in our San Francisco or Denver office.

Close

#989 SWT print ChartComposite

closed-accepted
David Gilbert
None
5
2012-07-05
2010-03-04
jonibal
No

Charts that have been rendered with SWT instead of AWT could not be printed until now. The method createChartPrintJob() on org.jfree.experimental.chart.swt.ChartComposite was simply not implemented for SWT.

This is a proposal how to do it:

//============================= BUGFIX START ===================================================
public void createChartPrintJob() {
PrintDialog dialog = new PrintDialog(getShell());
PrinterData printerData = dialog.open();
if (printerData == null) {
return; // User has aborted.
}

    final double BORDER = 0.8; // Border on the paper not to print on in inches:

    Printer printer = new Printer\(printerData\);
    try \{
        printer.startJob\("PrintJob"\);
        printer.startPage\(\);

        Rectangle trim = printer.computeTrim\(0, 0, 0, 0\);
        int leftMargin = \(int\) \(BORDER \* printer.getDPI\(\).x + trim.x\);
        int topMargin = \(int\) \(BORDER \* printer.getDPI\(\).y + trim.y\);

        int srcWidth = getSize\(\).x;
        int srcHeight = getSize\(\).y;
        int availWidth = printer.getClientArea\(\).width - 2 \* leftMargin;
        int availHeight = printer.getClientArea\(\).height - 2 \* topMargin;
        double scaleFactor = Math.min\(\(double\) availHeight / srcHeight, \(double\) availWidth / srcWidth\);

        Image image = new Image\(getDisplay\(\), srcWidth, srcHeight\);
        try \{
            GC imageGC = new GC\(image\);
            try \{
                print\(imageGC\);

                int trgHeight = \(int\) Math.ceil\(srcHeight \* scaleFactor\);
                int trgWidth = \(int\) Math.ceil\(srcWidth \* scaleFactor\);

                GC gc = new GC\(printer\);
                try \{
                    gc.drawImage\(image, 0, 0, srcWidth, srcHeight, leftMargin, topMargin, trgWidth, trgHeight\);
                    printer.endPage\(\);

                \} finally \{
                    gc.dispose\(\);
                \}

            \} finally \{
                imageGC.dispose\(\);
            \}
        \} finally \{
            image.dispose\(\);
        \}

        printer.endJob\(\);

    \} finally \{
        printer.dispose\(\);
    \}
\}

//============================= BUGFIX END ===================================================

Discussion

  • The current solution provided by version 1.0.13 does not work for me either on Windows 7. However, this bugfix solves the problem for me. I would very much appreciate that it found its way into the distribution. Thanks.

     
  • @herrminator

    I've changed my implementation since the posting above because it didn't work perfectly for me. For example scaling the chart didn't work as required. So you might be interested in a better code snippet to print a ChartComposite.

    I've extracted the functionality into a new class, which can be called from within the ChartComposite method createChartPrintJob like this:
    // ==================== CODE SNIPPET START ======================================
    public void createChartPrintJob() {
    new ChartPrintJob("PlotPrint").print(this);
    }
    // ===================== CODE SNIPPET END =======================================

    Now, the ChartPrintJob class I implemented like this:

    // ==================== CODE SNIPPET START ======================================
    import org.eclipse.swt.graphics.GC;
    import org.eclipse.swt.graphics.Image;
    import org.eclipse.swt.graphics.Point;
    import org.eclipse.swt.graphics.Rectangle;
    import org.eclipse.swt.printing.PrintDialog;
    import org.eclipse.swt.printing.Printer;
    import org.eclipse.swt.printing.PrinterData;
    import org.eclipse.swt.widgets.Composite;

    public class ChartPrintJob {

    /\*\*
     \* Border on the paper not to print on \(in inches\)
     \*/
    private static final double BORDER = 0.8;
    
    private String jobName;
    
    /\*\*
     \* @param jobName
     \*          this will be the name of the print job or the default name of the file \(if printed to a file\).
     \*/
    public ChartPrintJob\(String jobName\) \{
        this.jobName = jobName;
    \}
    
    /\*\*
     \* @param elementToPrint
     \*          the \{@link Composite\} to be printed
     \*/
    public void print\(Composite elementToPrint\) \{
        PrintDialog dialog = new PrintDialog\(elementToPrint.getShell\(\)\);
        PrinterData printerData = dialog.open\(\);
        if \(printerData == null\) \{
            return; // Anwender hat abgebrochen.
        \}
    
        startPrintJob\(elementToPrint, printerData\);
    \}
    
    protected void startPrintJob\(Composite elementToPrint, PrinterData printerData\) \{
        Printer printer = new Printer\(printerData\);
        try \{
            printer.startJob\(jobName\);
    
            GC gc = new GC\(printer\);
            try \{
                Rectangle printArea = getPrintableArea\(printer, BORDER\);
    
                printer.startPage\(\);
                printComposite\(elementToPrint, gc, printArea\);
                printer.endPage\(\);
    
            \} finally \{
                gc.dispose\(\);
            \}
    
            printer.endJob\(\);
    
        \} finally \{
            printer.dispose\(\);
        \}
    \}
    
    /\*\*
     \* @param printer
     \* @param safetyBorder
     \* @return the rectangle in pixels to print on \(and which is also supported by the printer hardware\)
     \*/
    private Rectangle getPrintableArea\(Printer printer, double safetyBorder\) \{
        int safetyBorderWidth = \(int\) \(safetyBorder \* printer.getDPI\(\).x\);
        int safetyBorderHeight = \(int\) \(safetyBorder \* printer.getDPI\(\).y\);
    
        Rectangle trim = printer.computeTrim\(0, 0, 0, 0\);
        int trimLeft = -trim.x;
        int trimTop = -trim.y;
        int trimRight = trim.x + trim.width;
        int trimBottom = trim.y + trim.height;
    
        int marginLeft = Math.max\(trimLeft, safetyBorderWidth\);
        int marginRight = Math.max\(trimRight, safetyBorderWidth\);
        int marginTop = Math.max\(trimTop, safetyBorderHeight\);
        int marginBottom = Math.max\(trimBottom, safetyBorderHeight\);
    
        int availWidth = printer.getClientArea\(\).width - marginLeft - marginRight;
        int availHeight = printer.getClientArea\(\).height - marginTop - marginBottom;
        return new Rectangle\(marginLeft, marginTop, availWidth, availHeight\);
    \}
    
    private void printComposite\(Composite elementToPrint, GC gc, Rectangle printArea\) \{
        Image image = new Image\(elementToPrint.getDisplay\(\), elementToPrint.getSize\(\).x, elementToPrint.getSize\(\).y\);
        try \{
            GC imageGC = new GC\(image\);
            try \{
                elementToPrint.print\(imageGC\);
    
                Point fittedSize = calcFittedSize\(printArea, elementToPrint.getSize\(\)\);
                gc.drawImage\(image, 0, 0, elementToPrint.getSize\(\).x, elementToPrint.getSize\(\).y, printArea.x, printArea.y, fittedSize.x, fittedSize.y\);
    
            \} finally \{
                imageGC.dispose\(\);
            \}
        \} finally \{
            image.dispose\(\);
        \}
    \}
    
    /\*\*
     \* The object to print should be scaled up or down to fit horizontally and vertically the available space.
     \* 
     \* @param printArea
     \* @param originalSize
     \* @return the fitted size of the object to print
     \*/
    Point calcFittedSize\(Rectangle printArea, Point originalSize\) \{
        double scaleFactor = Math.min\(\(double\) printArea.height / originalSize.y, \(double\) printArea.width / originalSize.x\);
        int trgHeight = \(int\) Math.ceil\(originalSize.y \* scaleFactor\);
        int trgWidth = \(int\) Math.ceil\(originalSize.x \* scaleFactor\);
        return new Point\(trgWidth, trgHeight\);
    \}
    

    }

    // ===================== CODE SNIPPET END =======================================

     
  • David Gilbert
    David Gilbert
    2012-07-05

    • assigned_to: nobody --> mungady
    • status: open --> closed-accepted
     
  • David Gilbert
    David Gilbert
    2012-07-05

    Thanks. I committed the code from the comment field, for inclusion in the 1.0.15 release.