#2 High resolution images saving

open
nobody
None
8
2014-08-26
2003-07-25
Anonymous
No

Hello,

All charts get by default the same resolution when
saved to a file as shown on the screen... which is
insuficient (screen resolution is about 72-96 dots per
inch - dpi - whereas printer resolution is at last 300
dpi) - see related topic of the JFreeChartForum :
(http://www.jfree.org/phpBB2/viewtopic.php?t=4809
http://www.jfree.org/phpBB2/viewtopic.php?t=2703

Here are code to make the saving of a chart as PNG
image of Your desired resolution.

1) in chartPanel.java : add the constant and methods
indicated below.

2) upgrade the pngEncoder to write the resolution used
in the saved file (see attached file).

// ~~~~~~~~~~~~~~~~~~~~~~~~~
// code to include in org.jfree.chart.ChartPanel
// ~~~~~~~~~~~~~~~~~~~~~~~~~

/** The default resolution used for the saving of
charts into file (in dots per inch). */
static private int DPI_FILE_RESOLUTION = 300;

/**
* Opens a file chooser and gives the user an
opportunity to save the chart
* in PNG format.
*
* @throws IOException if there is an I/O error.
*/
public void doSaveAs() throws IOException {

JFileChooser fileChooser = new JFileChooser();
ExtensionFileFilter filter = new
ExtensionFileFilter(resources.getString("PNG_Image_Files"),

resources.getString(".png"));
fileChooser.addChoosableFileFilter(filter);

int option = fileChooser.showSaveDialog(this);
if (option == JFileChooser.APPROVE_OPTION) {
File file = fileChooser.getSelectedFile();

OutputStream out = new
BufferedOutputStream(new FileOutputStream(file));
PngEncoder encoder = new
PngEncoder(getHighResChartImage(DPI_FILE_RESOLUTION),
false, 0, 9);
encoder.setDpi(DPI_FILE_RESOLUTION,
DPI_FILE_RESOLUTION);
byte[] pngData = encoder.pngEncode();
out.write(pngData);
out.close();
}
}

/**
* Returns a high resolution BufferedImage of the
chart.
* Uses the default DPI_FILE_RESOLUTION.
*
* @return the buffered image.
*/
private BufferedImage getHighResChartImage() {
return getHighResChartImage(DPI_FILE_RESOLUTION);
}

/**
* Returns a high resolution BufferedImage of the
chart.
* Uses the default DPI_FILE_RESOLUTION.
*
* @param resolution The resolution, in dots per
inch, of the image to generate.
* @return the buffered image.
*/
private BufferedImage getHighResChartImage(int
resolution) {
int screenResolution =
Toolkit.getDefaultToolkit().getScreenResolution();
double scaleRatio = resolution / screenResolution;
int rasterWidth = (int) (getWidth() * scaleRatio);
int rasterHeight = (int) (getHeight() *
scaleRatio);

BufferedImage image = new
BufferedImage(rasterWidth, rasterHeight,
BufferedImage.TYPE_INT_RGB);

Graphics2D g2 = image.createGraphics();

g2.transform(AffineTransform.getScaleInstance(scaleRatio,
scaleRatio));
getChart().draw(g2, new Rectangle2D.Double(0,
0, getWidth(), getHeight()), null);
g2.dispose();

return image;
}

Discussion

  • updated version of PngEncoder.java

     
    Attachments
  • David Gilbert
    David Gilbert
    2004-02-02

    • priority: 5 --> 8
     
  • RonanKER
    RonanKER
    2006-05-31

    Logged In: YES
    user_id=1531163

    I can't understand anything... I'm using cewolf and a jar
    file for JFreeChart and i don't know how to use this solution...

    would it be possible to make an impovement in future
    releases to only have to modify a parameter.

    for now i disbled antialiasing in my post processor, it's
    not good but better than with antialiasing...

     
  • m.hilpert
    m.hilpert
    2008-02-12

    Logged In: YES
    user_id=667728
    Originator: NO

    How would you increase resolution by scaling??? You need to set the horizontal/vertical resolution to the final image size by calculating the width/height according to your DPI requirements:

    You first need to know how many pixels of the chart image is 1 inch. Then you have your pixelsPerInch/dotsPerInch factor. Then multiply your chart's width/height with this factor to get the desired resolution. (You can't squeeze more pixels/dots out of the same image just by scaling - it gets distorted.)

    The better approach is of course to use a vector image format like SVG:

    /**
    * Save chart as SVG file.
    * Required libs: Apache Batik (batik-svggen.jar, batik-dom.jar, dom.jar).
    *
    * @param chart JFreeChart to save.
    * @param fileName Name of file to save chart in.
    * @param width Width of chart graphic.
    * @param height Height of chart graphic.
    * @return Final file name used.
    * @throws IOException if failed.
    */
    static public final String saveChartToSVG(final JFreeChart chart, String fileName, final int width, final int height) throws IOException {
    String result = null;

    if (chart != null) {
    if (fileName == null) {
    final String chartTitle = chart.getTitle().getText();
    if (chartTitle != null) {
    fileName = chartTitle;
    } else {
    fileName = "chart";
    }
    }
    result = fileName + ".svg";

    final DOMImplementation domImpl = GenericDOMImplementation.getDOMImplementation();
    final Document document = domImpl.createDocument(null, "svg", null);
    final SVGGraphics2D svgGenerator = new SVGGraphics2D(document);

    // svgGenerator.getGeneratorContext().setEmbeddedFontsOn(true); //embed fonts

    //set anti-aliasing bug fix for SVG generator:
    //setting rendering hints of svgGenerator doesn't help as it seems to use the rendering hints from the chart
    final boolean antiAlias = isAntiAliasOn(chart);
    final RenderingHints rh = chart.getRenderingHints();

    if (antiAlias) {
    rh.put(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
    rh.put(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_OFF); //fix
    } else {
    rh.put(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_OFF);
    rh.put(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON); //fix
    }

    // svgGenerator.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
    // svgGenerator.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_OFF);
    // svgGenerator.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
    // svgGenerator.setRenderingHint(RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_QUALITY);
    // svgGenerator.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
    // svgGenerator.setRenderingHint(RenderingHints.KEY_ALPHA_INTERPOLATION, RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY);

    chart.draw(svgGenerator, new Rectangle2D.Double(0, 0, width, height), new ChartRenderingInfo());

    //undo anti-aliasing bugfix settings for chart to use correct settings:
    if (antiAlias) {
    rh.put(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
    rh.put(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
    } else {
    rh.put(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_OFF);
    rh.put(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_OFF);
    }

    final boolean useCSS = true;
    Writer out = null;
    try {
    out = new OutputStreamWriter(new BufferedOutputStream(new FileOutputStream(new File(result), false)),"iso-8859-1"); //UTF-8
    svgGenerator.stream(out, useCSS);
    } finally {
    svgGenerator.dispose();
    IOUtils.close(out);
    }
    }//else: input unavailable

    return result;
    }//saveChartToSVG()