This project has moved and is read-only. For the latest updates, please go here.

Does Magick.Net support "caption:" functionality?

Jan 10, 2014 at 9:46 PM
I am playing around with Magick.NET to see if it might meet the needs of our software. So far it looks great. However, one of the requirements is to be able to draw a textbox of a specific width/height and place text inside the box so that the text is word-wrapped to fit inside the box. It looks like the ImageMagick "caption:" functionality meets this need, but I can't figure out how to get this to work with Magick.Net. I don't see "Caption" as an function or class in the API.

Any help is appreciated!

I am using Magick.NET 6.8.7.901, and I installed it via zip.
Jan 10, 2014 at 11:54 PM
If you want to use the caption: coder you should do the following:
// convert.exe caption:'ImageMagick Rules OK!' caption_centered.gif
using (MagickImage image = new MagickImage())
{
  // Set options like background / font / color
  image.Read("caption:\"ImageMagick Rules OK\"'");
  image.Write("caption_centered.gif");
}
Jan 11, 2014 at 3:31 AM
Thank you, this helps. However, your sample is creating a new image. I want to load an existing tiff, then draw a rectangle on it with a caption inside, then save as a new tiff. I'm not sure how I can do that with your example (?).

Also, for future reference, how would I have known that I can use the Read function with a caption? I just want to make sure I'm not missing some documentation somewhere (I did read through the Magick.Net examples). Thanks!
Jan 11, 2014 at 8:37 AM
I have added a link to a great ImageMagick examples page in the documentation. You can recognize that you need the Read method when you see a colon in the examples and no file is being read. For example this:
convert.exe caption:'ImageMagick Rules OK!' caption_centered.gif (http://www.imagemagick.org/Usage/text#caption)
convert.exe rose: rose.png (http://www.imagemagick.org/Usage/files/#special_formats)
If you want to draw text on an existing image you could use the Drawable classes to accomplish this. But because you want the word wrapping you will have to 'Read' the caption and compose it over your existing image.
using (MagickImage image = new MagickImage("image.tif"))
{
  using (MagickImage text = CreateCaption("caption:Magick.NET"))
  {
    // http://www.imagemagick.org/Usage/compose/#over
    image.Composite(text, 50, 50, CompositeOperator.Over);
  }
}
Jan 15, 2014 at 4:29 PM
How do you combine the caption functionality with gravity?

I need to be able to place text aligned left, centered or right. I have got it working using image.Draw with a collection of Drawable objects but calculating the font point size is a performance hit which I do not notice when using caption. (using FontTypeMetrics in a loop)
Jan 15, 2014 at 4:52 PM
Caption internally uses FontTypeMetrics to calculate the size so it is quite strange that this is causing such a huge performance problem. Can you provide me with a small example?
Jan 16, 2014 at 8:38 AM
Edited Jan 16, 2014 at 8:42 AM
I have done some more debugging and found that raising the FontPointSize with 0.1 was causing the performance hit. I've changed it to 1 and now Draw is actually faster.

I did see another thing with caption though. It does not honor line breaks so that an entire line can only fit on on a single line in the image (which is what i want).

Anyway my code sample:
string fontFamily = "Droid-Serif-Bold-Italic";
string content = "Hello World!\nsecond line\nThird g";
            
var bgColor   = new MagickColor("#F0F0F0");
var fillColor = new MagickColor("#000000");
using (MagickImage image = new MagickImage(bgColor, 500, 500))
{
    var gravity       = new DrawableGravity(Gravity.Northeast);
    var textAntialias = new DrawableTextAntialias(true);
    var text          = new DrawableText(0, 0, content);

    image.Font      = fontFamily;
    image.FillColor = fillColor;

    CalculateFontPointSize(image, content);

    image.Draw(
        textAntialias,
        text,
        gravity);
}

private void CalculateFontPointSize(MagickImage image, string text)
{
    // FontType Metrics only works for single lines?
    
    // set font size to smallest size
    image.FontPointsize = 0;
    double calculatedHeight = 0;
    double calculatedWidth  = 0;

    // get longest line
    var lines = text.Split(new [] {"\n" }, StringSplitOptions.None);
    var longestLine = lines.OrderByDescending(x => x.Length).First();

    var metrics = image.FontTypeMetrics(longestLine);

    while (calculatedWidth < image.Width && calculatedHeight < image.Height)
    {
        image.FontPointsize += 1;

        metrics = image.FontTypeMetrics(longestLine);

        calculatedHeight = metrics.TextHeight * lines.Length;
        calculatedWidth  = metrics.TextWidth;
    }
}
VS
using (MagickImage image = new MagickImage(bgColor, 500, 500))
{
    image.Font      = fontFamily;
    image.FillColor = fillColor;

    var textImage = CreateText(fontFamily, 500, 500, content);
    image.Composite(textImage, 0, 0, CompositeOperator.Over);

}

private MagickImage CreateText(string fontFamily, int width, int height, string text)
{
    var image = new MagickImage(MagickColor.Transparent, width, height);
    
    image.FillColor = new MagickColor("#000000");
    image.Font = fontFamily;

    image.Read(string.Format("caption:{0}", text));

    return image;
}
Jan 16, 2014 at 8:48 AM
There is a multi line FontTypeMetrics method available in ImageMagick and that is actual being used by the caption coder. I did not notice that before. I will make this available in the next release.
Jan 16, 2014 at 9:10 AM
This discussion has been copied to a work item. Click here to go to the work item and continue the discussion.