Showing posts with label pic. Show all posts
Showing posts with label pic. Show all posts

JFreeChart and PDFBox

In a previous post, I have created a pie chart with JFreeChart and I saved it as a file in PNG format. Let's now put it in a PDF file, using the Apache PDFBox library, version 2. And I stress version 2 because it is still young and has a few changes that also impact right in this area.

First thing, I have added a dependency to PDFBox in my POM file - it's a Maven project, as you have guessed:
<dependency>
 <groupId>org.apache.pdfbox</groupId>
 <artifactId>pdfbox</artifactId>
 <version>2.0.2</version>
</dependency>
For Gradle fueled project, your build.gradle should have this line among its dependencies:
compile group: 'org.apache.pdfbox', name: 'pdfbox', version: '2.0.2'
I suggest you to check the current version on the Apache PDFBox web site. Actually, this post is already slightly outdated since version 2.0.4 has already been released.

Since large part of the code I am about to use here has been already written, I have extracted the JFreeChart creation to a method, createPiePlotSimple(), that would return the object as seen before, without saving it to file. Then I created a createSimpleOnPdf() method that does the more interesting stuff.

Firstly, it creates a PDF document, and add a page to it.
PDDocument doc = new PDDocument();
PDPage page = new PDPage();
doc.addPage(page);
Then I call the createPiePlotSimple() to get the JFreeChart object, and create from it a buffered image.
JFreeChart chart = createPiePlotSimple();
BufferedImage bi = chart.createBufferedImage(500, 500);
Finally, in a try-catch block, since there are lot of IOException that could be thrown around in this piece of code, I convert the buffered image to a PDImageXObject, specific for the PDF format, using a specialized factory class. The image is drawn passing through a PDPageContentStream object, and then I can finally save my PDF file.
PDPageContentStream cs = new PDPageContentStream(doc, page);
PDImageXObject ximage = LosslessFactory.createFromImage(doc, bi);
cs.drawImage(ximage, 100, 100);
cs.close();
doc.save(new File("dump/pie.pdf"));
Pay attention that PDImageXObject and LosslessFactory are new in version 2. Before that we had PDXObjectImage and PDJpeg, PDPixelMap, and PDCCitt. I suggest to have a look at the migration page if you need more information.

I pushed the changes to GitHub.

Go to the full post

First Pie with JFreeChart

I have to generate charts from Java. Among the available possibility, JFreeChart has been chosen.
In this post I start from nothing to save a PNG with a pie chart in it.

Well, actually, I have something more than nothing, namely a windows box with Java 8 on it and Eclipse Neon as IDE. I create a Maven project, and I added a few dependencies. The most relevant here is the JFreeChart one, however, don't forget a test library, I'm using JUnit 4:
<dependency>
 <groupId>org.jfree</groupId>
 <artifactId>jfreechart</artifactId>
 <version>1.0.19</version>
</dependency>
<dependency>
 <groupId>junit</groupId>
 <artifactId>junit</artifactId>
 <version>4.12</version>
 <scope>test</scope>
</dependency>
I want to explore how to create pie charts, so I create a class Pie in a chart package with a static method in it, createSimple() that would return true if the process succeed.
package chart;

public class Pie {
    static boolean createSimple() {
        return false;
    }
}
Then I create a test case, that is going to be quite trivial, but at least clearly split the concern about writing the code and testing it in two different places. The alternative, giving a main function to the Pie class would have been more regrettable.
@Test
public void testCreate() {
    assertTrue(Pie.createSimple());
}
So, let's create a pie reporting a few elements in it, defined by a name and an associated value. We are going to use all the possible default provided, just to have a picture to display.
DefaultPieDataset dataset = new DefaultPieDataset(); // 1
dataset.setValue("Merlin", 2.50);
dataset.setValue("Tiger", 18.27);
dataset.setValue("Mustang", 41.33);
dataset.setValue("Dolphin", 72.02);

JFreeChart chart = ChartFactory.createPieChart("Versions", dataset); // 2
1. I create dataset, and I push a few description/value couples to it.
2. Then I create a pie chart going through the ChartFactory class. As parameter, this factory method requires just the name I want to give the chart and the data it should use to create it.

I want to put the image in a file, in the PNG format. This is easily done.
try {
    ChartUtilities.saveChartAsPNG(new File("dump/pie.png"), chart, 500, 500);
    return true;
} catch(IOException ioe) {
    log.error(ioe.getMessage());
    return false;
}
Be careful of passing to saveChartAsPNG() a file that could be created. If the path does not exist, you are going to get an exception. The other parameters are the chart that has to be created, and its size, width x height. Here is the result I've got:
Nice. However, I'd like not to see the tooltips. From the documentation, I read that I can have a better control on the generated picture calling the overload of createPieChart() that accepts three boolean more, ruling the display of legend, tooltips, and URLs. The shorter version I used above is equivalent to:
// legend and tooltips
JFreeChart chart = ChartFactory.createPieChart("Languages", dataset, true, true, false);
So we just set the second boolean to false to get rid of the tooltips, right? Well, not. For same strange reason, that flag does not work. Fortunately there is a workaround, we can disable the label generator.
// disable tooltips not working!
JFreeChart chart = ChartFactory.createPieChart("Versions", dataset, true, false, false);

PiePlot pp = (PiePlot) chart.getPlot();
// force tooltips off
pp.setLabelGenerator(null);
Try commenting the call to setLabelGenerator(), you will still see the tooltips on the pie, otherwise you'll have only the legend.
Say that I don't like the default color choice, and I want the Mustang slice in magenta. I can call setSectionPaint() on the PiePlot for that slice to change it:
pp.setSectionPaint("Mustang", Color.MAGENTA);
Notice that magenta replaced green for Mustang, but green is not out of the game, it has merely shifted to the next slice.

Last change I want to do here, let also the legend off:
JFreeChart chart = ChartFactory.createPieChart("Versions", dataset, false, false, false);

I have pushed the project on GitHub.

Go to the full post

Drawing lines and polylines

I need to create a PNG file where lines are drawn on a background that could be of a solid color or transparent. It's an easy job, but it requires to use a few Magick++ classes. As we are going to see, the Image class has a central role in it.

Background color

There are many ways of creating a Magick++ Color. Actually, there are even many Magick++ Color flavors, rigorized as classes that all derives from Magick::Color. Here my requirements are not very demanding, so I can easily settle for using the base class, and just a couple of its constructors.

For simple standard colors, ImageMagick uses the X11 name convention, so that I can define a very light orange background in this way:
Magick::Color background("papaya whip");
A full list of X11 color names is on wikipedia.

We can specify the level of transparency of a color at its creation time, calling the Color constructor that expects in input red, green, blue, and alpha (AKA, its transparency) quantums. That's how I create a fully transparent color:
Magick::Color background(0, 0, 0, QuantumRange);
I have already written something about the relation about Quantum, QuantumRange and Imagick++ in a previous post, so here I just assume you know what I am talking about.
Being fully transparent, it doesn't matter the quantum level for the first three components. A fully transparent black (that the one I picked up) does not differ from any other fully transparent color.

Creating an image

Once I have a background color, I can create an 50x50 Image object in this way:
Magick::Image image(Magick::Geometry(50, 50), background);
It is usually a smart idea to specify just after creation which kind of image we are interested in:
image.magick("PNG");
Another common early setting is about the kind of stroke I want to use. Here I set its width and the line cap shape:
image.strokeWidth(4);
image.strokeLineCap(Magick::RoundCap);
Drawing lines

I am about to draw the red/blue asterisk on transparent background that you see here aside.

Firstly I draw the red X, than I switch to blue and I draw a plus. In both case, what I actually draw are simple lines, two red ones and two blue ones, with no relation one to the others. It is all pretty easy:
image.strokeColor(Magick::Color("red")); // 1
image.draw(Magick::DrawableLine(10, 10, 40, 40)); // 2
image.draw(Magick::DrawableLine(40, 10, 10, 40));

image.strokeColor(Magick::Color("blue")); // 3
image.draw(Magick::DrawableLine(5, 25, 45, 25));
image.draw(Magick::DrawableLine(25, 5, 25, 45));
1. Select the red color.
2. Draw a first line from (10, 10) to (40, 40), then a second one from (40, 10) to (10, 40).
3. Then I switch to blue, and I draw the other couple of lines.

Drawing polylines

Things get a bit more complicated in case of polylines. If a line has just a beginning and an end, a polyline is defined by a number of points, each point describing an object vertex. I need to call the Image::draw() method on the entire collection of points. To do that, we use a STL list container parametrized for the Magick Coordinate class.

Before filling the list, I set a few other stroke options, and the filling color. More details below the code:
image.strokeAntiAlias(true); // 1
image.strokeLineJoin(Magick::RoundJoin); // 2
image.strokeColor(Magick::Color("red")); // 3
image.fillColor(background); // 4

std::list<Magick::Coordinate> line; // 5
line.push_back(Magick::Coordinate(11,4));
line.push_back(Magick::Coordinate(41,23));
line.push_back(Magick::Coordinate(27,42));
line.push_back(Magick::Coordinate(59,91));

image.draw(Magick::DrawablePolyline(line)); // 6
1. Activate the anti-aliasing. This means that Magick will do its best to avoid jaggies, trying to smoothing the drawing.
2. I say to Magick to round the join in the connection between parts of the polyline.
3. The foreground color is the bright standard X11 red.
4. If I don't say to Magick to use a specific color as filler, the stroke color will be used. Not what I want to get here.
5. Instantiate a list of Coordinates, and fill it with the points I need.
6. And finally, I convert the list in a drawable polyline, and I draw it.

Saving the image in a file

We need a last step, writing the image to a file:
image.write("/tmp/test.png");
Exceptions

The Magick++ exceptions are derived by the STL exception. So you could try/catch your Magick++ code just for the generic standard exception. If you want finer management you can add more catch blocks to your code. For instance, here I was interested in giving a specific message for the ErrorBlob exception:
try
{
  // Magick++ code goes here
}
catch(Magick::ErrorBlob& ex)
{
  std::cout << "Magick ErrorBlob: " << ex.what() << std::endl;
}
catch(std::exception& ex)
{
  std::cout << "Error: " << ex.what() << std::endl;
}

Go to the full post

A Quantum of ImageMagick

ImageMagick defines Quantum as the base type to represent color. To make the framework flexible, a constant named MAGICKCORE_QUANTUM_DEPTH (or its deprecated alias, QuantumDepth) determines the number of bits in a Quantum. It gets a value among 8, 16, 32, and 64. An higher depth gives better precision, and it is paid in term of heavier resource consumption.

In the current ImageMagick version, MAGICKCORE_QUANTUM_DEPTH is defaulted to 16, you should see it in the magick-type.h include file. This lead also to a type definition for Quantum as unsigned short.

In this context, QuantumRange, the highest value that could be assigned to a Quantum variable (it has a deprecated alias, too, MaxRGB), is defined as a symbolic constant in this way:
#define QuantumRange  ((Quantum) 65535)
When working in C++ through the Magick++ library, this could lead to an unfriendly behavior.

Say that we need a Quantum variable, and we want to initialize it to QuantumRange. You are probably bound to write a line of code like this:
Magick::Quantum quantum = QuantumRange;
Alas, this could not work. As we have seen, the value of QuantumRange is casted to Quantum in its definition. This works fine when developing in C, but when we are writing code through Magick++, we need to qualify each Magick type with its proper namespace.
The compiler needs to know where to look for the Quantum definition, otherwise we'll get a compile error like "'Quantum' was not declared in this scope".

We have at least a couple of alternative solutions to this issue:
using namespace Magick;

// ...
Magick::Quantum quantum = QuantumRange;
All the code between the using directive and the end of file would have access to the the Magick namespace. A bit dirty, isn't it?
Magick::Quantum quantum;
{
  using namespace Magick;
  quantum = QuantumRange;
}
Split declaration and definition of the variable, and perform the second in a tiny scope where we use the namespace directive. Cleaner, but more verbose, too.

Go to the full post

From GIF to PNG with ImageMagick

Once you have installed ImageMagick in your environment (on Ubuntu, you could simply install the imagemagick and libmagick++-dev packages via apt-get), it is quite easy write a simple application to test that you have anything ready to work with this handy library.

One of the easiest thing we can do, is converting an existing image from its original format to another one. Let's use this functionality to write a sort of "hello world" application.

I am working in C++ (that's why I have installed the libmagick++-dev package) on a 64 bit Linux-Debian machine (and the Debian part of this explains why I installed the package using apt-get). I am using the GCC C++ compiler, and Eclipse as IDE. So, be prepared to apply some changes to fit the example to your requirements.

I created a new C++ project, adding some information to let the IDE find depending includes and libraries.

In Properties, C/C++ Build, Settings

- In the GCC C++ Compiler, Includes page I added "/usr/include/ImageMagick"
- In the GCC C++ Linker, Libraries page I added:
-L: /usr/lib/x86_64-linux-gnu/
-l: Magick++

So, now Eclipse knows where to find the Magick include directories, and where to find the shareable object libMagick++.so that would be needed to my executable to properly run. If you run ldd on the resulting program file, you will see that it depends also on other Magick shareable objects, namely libMagickWand.so and libMagickCore.so.

I have put in my tmp directory a GIF file, and I want my (silly) little program to convert it to PNG. Here is the code.
#include <Magick++.h>

int main()
{
    Magick::Image image; // 1
    image.read("/tmp/simple.gif"); // 2
    image.write("/tmp/simple.png"); // 3
}
1. An empty Magick image.
2. ImageMagick loads the passed file in an image. What if such file does not exists? A Magick::ErrorBlob exception would be thrown. And since I don't have try-caught my code, this would result in a (small) catastrophe.
3. The image is saved to the new specified file (if the application can actually write it). Notice that Magick is smart enough to understand which format to use accordingly to the passed file name extension.

Go to the full post