使用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
相关产品推荐
相关产品推荐

