1

I have some C# code that adds a simple text overlay with a border and semi-transparent background to an image. It works great, but I'm trying to get an equivalent result using Magick.NET. (The straight C# code drops the XMP tags from the original image, and I haven't found a way to deal with that.) Magick.NET handles the XMP tags well, but I'm having trouble replicating the original output.

Original code follows:

using (Image i = Image.FromStream(stream))
{
  int width = i.Width;
  int height = i.Height;

  using (Graphics graphics =  Graphics.FromImage(i))
  {
    string measureString = "my string";
    Size stringSize = graphics.MeasureString(measureString, stringFont).ToSize();
      
    Point drawLocation = new Point(width - stringSize.Width - 15, height - stringSize.Height - 15);
    Rectangle rect = new Rectangle(drawLocation.X, drawLocation.Y, stringSize.Width, stringSize.Height);
      
    graphics.DrawRectangle(blackPen, rect);
    graphics.FillRectangle(fillBrush, rect);
    graphics.DrawString(measureString, stringFont, Brushes.Yellow, drawLocation);
  }
  i.Save(outputFolder + Path.GetFileName(imgFileName));
}

I cobbled this together based on the Magick.NET examples. This get close to what I'm looking for, but adding the border removes the transparency value, and I'm left with a dark gray background, instead of the transparency.

 var settings = new MagickReadSettings{
                Font = "Calibri",
                FillColor=MagickColors.Yellow,
                StrokeColor=MagickColors.Black,
                TextGravity = Gravity.Center,
                BackgroundColor = new MagickColor("#66666699"),
                BorderColor = MagickColors.Black,
                Height = 250, // height of text box
                Width = 680 // width of text box
            };

using (var image = new MagickImage(inputFile))
{
  using (var caption = new MagickImage($"caption:{myString}", settings))
  {
    //adding this border removes transparency
    // caption.BorderColor = MagickColors.Black;
    // caption.Border(1);

    image.Composite(caption, Gravity.Southeast, CompositeOperator.Over);
    image.Write(outputFile);
  }
}
user120675
  • 313
  • 2
  • 7
  • Try with your border color as "000000FF" (black with opaque alpha). If that does not work, try the CompositeOperator as copy rather than over. – fmw42 Jan 24 '23 at 21:28
  • Thanks for the suggestions. Both result in the same solid gray background. – user120675 Jan 24 '23 at 22:10

2 Answers2

0

In command line ImageMagick, this seems to work for me in that the background color is transparent gray. The following the result may be what you want:

convert -font ubuntu -fill yellow -stroke black -gravity center -background "#66666699" -bordercolor black -size 250x680 caption:"This Is Some Text" result.png

Enter image description here

Note: I used -background, not -backgroundcolor. Also BorderColor is not the color for the outline of the text. That is the stroke. You have not used BorderColor, since you have not specified the Border amount (as in -border in command line), which would outline the image rectangle and not the text.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
fmw42
  • 46,825
  • 10
  • 62
  • 80
  • Yes, this produces the overlay that I'm looking for(transparent gray background, with black stroke and border). Unfortunately, I can't figure out how to translate this to ImageMagick.Net. I don't see an option for Background, only backgroundColor. – user120675 Jan 25 '23 at 05:50
  • Can you reproduce the last example at https://github.com/dlemstra/Magick.NET/blob/main/docs/Drawing.md and get a transparent background? – fmw42 Jan 25 '23 at 16:27
  • Yes, that was the sample code that I started with, and it's working as described. (text with 100% transparent background, and no border) – user120675 Jan 25 '23 at 17:24
  • I suppose that you should report that to the Imagemagick team on the Magick.Net GIT page at https://github.com/dlemstra/Magick.NET. By the way are you using the latest version of Magick.Net. If not, then perhaps you should try upgrading and testing again. – fmw42 Jan 25 '23 at 19:19
  • Yeah, this is with the current version. I'll take my question to their GitHub Discussions page. Thanks for the followup! – user120675 Jan 25 '23 at 19:35
0

Due to time constraints with my project, I took a slightly different path to make this work. I wound up creating the transparent overlay using my original .NET drawing code, and passing that as a memory stream to Magick.NET to handle the merge.

Workaround:

string measureString = "build custom string here";

using (var tmpStreamImg = new MemoryStream())
{
  // Call custom function to get length of my string
  System.Drawing.Size stringSize = MeasureString(measureString, stringFont).ToSize();
  Rectangle rect = new Rectangle(0, 0, stringSize.Width, stringSize.Height);

  using (Bitmap overlay = new Bitmap(rect.Width, rect.Height))
  {
    overlay.SetResolution(350, 350);
    using (Graphics overlayGraphic = Graphics.FromImage(overlay))
    {
      overlayGraphic.DrawRectangle(blackPen, rect);
      overlayGraphic.FillRectangle(fillBrush, rect);

      overlayGraphic.DrawString(measureString, stringFont, Brushes.Yellow, 3, 3);
    }
    overlay.Save(tmpStreamImg, ImageFormat.Png);
  }
  tmpStreamImg.Position= 0;

  using (var originalImage = new MagickImage(imgFileName))
  {
    using (var overlayImage = new MagickImage(tmpStreamImg))
    {
      originalImage.Composite(overlayImage, Gravity.Southeast, CompositeOperator.Over);
      originalImage.Write(outputFolder + Path.GetFileName(imgFileName));
    }
  }
}
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
user120675
  • 313
  • 2
  • 7