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)); // 61. 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; }