You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Magick.NET实现带半透明背景文本标签:边框丢失透明问题

问题描述

我有一段基于GDI+的C#代码,能给图片添加带边框和半透明背景的文本叠加层,效果符合预期,但会丢失原图的XMP元数据标签,这个问题一直没解决。

改用Magick.NET后能完美保留XMP标签,但复现相同效果时遇到了问题:给文本框添加边框后,背景的透明度会丢失,变成深灰色。

原GDI+代码如下:

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));
}

我参考Magick.NET示例写的代码已经接近预期效果,但取消注释边框相关代码后就会丢失透明度:

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))
  {
    // 取消注释下面两行后,背景透明度丢失
    // caption.BorderColor = MagickColors.Black;
    // caption.Border(1);

    image.Composite(caption, Gravity.Southeast, CompositeOperator.Over);
    image.Write(outputFile);
  }
}
解决方案

问题出在Border()方法默认会用不透明背景填充边框扩展的区域,直接覆盖了原本的透明通道。要保留透明度,得换一种方式控制边框和背景的绘制逻辑,下面提供两种可行方案:

方案1:手动绘制背景与边框(推荐)

通过创建透明画布,手动绘制半透明背景和黑色边框,再叠加文本,完全控制样式和透明度:

var settings = new MagickReadSettings{
    Font = "Calibri",
    FillColor=MagickColors.Yellow,
    StrokeColor=MagickColors.Black,
    TextGravity = Gravity.Center,
    BackgroundColor = MagickColors.Transparent, // 先设为完全透明
    Height = 250,
    Width = 680
};

using (var image = new MagickImage(inputFile))
{
    using (var caption = new MagickImage($"caption:{myString}", settings))
    {
        // 创建比文本框大2px的画布,预留1px边框空间
        using (var canvas = new MagickImage(MagickColors.Transparent, caption.Width + 2, caption.Height + 2))
        {
            // 绘制半透明背景和黑色边框
            using (var drawables = new Drawables())
            {
                // 填充半透明背景(边框内侧区域)
                drawables.FillColor(new MagickColor("#66666699"))
                        .Rectangle(1, 1, caption.Width, caption.Height);
                // 绘制黑色边框(只描边,不填充)
                drawables.StrokeColor(MagickColors.Black)
                        .StrokeWidth(1)
                        .FillOpacity(0)
                        .Rectangle(0.5, 0.5, canvas.Width - 0.5, canvas.Height - 0.5);
                drawables.Draw(canvas);
            }

            // 将文本叠加到半透明背景上
            canvas.Composite(caption, 1, 1, CompositeOperator.Over);

            // 把最终文本框叠加到原图右下角
            image.Composite(canvas, Gravity.Southeast, CompositeOperator.Over);
            image.Write(outputFile);
        }
    }
}

方案2:修复Border()后的Alpha通道

如果坚持用Border()方法,可以先保存原始Alpha通道,添加边框后再恢复透明属性:

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

using (var image = new MagickImage(inputFile))
{
    using (var caption = new MagickImage($"caption:{myString}", settings))
    {
        // 保存原始文本区域的Alpha通道
        using (var alphaChannel = caption.AlphaChannel())
        {
            // 添加黑色边框
            caption.BorderColor = MagickColors.Black;
            caption.Border(1);

            // 恢复Alpha通道,同时保留边框的不透明度
            using (var newAlpha = new MagickImage(MagickColors.White, caption.Width, caption.Height))
            {
                newAlpha.Composite(alphaChannel, 1, 1, CompositeOperator.Over);
                caption.AlphaChannel(AlphaChannel.Set);
                caption.Composite(newAlpha, CompositeOperator.CopyOpacity);
            }
        }

        image.Composite(caption, Gravity.Southeast, CompositeOperator.Over);
        image.Write(outputFile);
    }
}

说明

  • 方案1逻辑更直观,完全自定义绘制流程,避免Magick.NET默认边框操作的坑,推荐使用。
  • 两种方案都能保留原图的XMP元数据,同时实现带半透明背景和黑色边框的文本叠加效果。

内容的提问来源于stack exchange,提问作者user120675

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.03 09:06:38