问题:
我想在图像上打印水印。图像的大小各不相同,因此有时水印太大,有时太小。为了解决这个问题,我计算图像的大小并调整水印的大小。但是,调整图像大小后,其边缘周围会出现黑色边框。
代码
我在使用 .NET Core3.1
的 Mac 上使用两个 NuGet 包来帮助绘制图像/位图。一个是 System.Drawing.Common
,另一个是 runtime.osx.10.10x64.CoreCompat.System.Drawing
,因为我在 macOS 上。
我用来调整水印大小的代码创建here :
Bitmap watermarkNew = new Bitmap(watermark, new Size(image.Width / 10 * 3, image.Height / 10 * 3));
我必须使用 /10 * 3
,因为 Bitmap 构造函数不接受浮点值,因此我无法乘以 * 0.3
。
结果:
watermark before watermark after
最佳答案
要将一个图像叠加到另一个图像上,最好使用未缩放的图像,而不是预先根据所需大小生成新的位图。
▶ 这两个图像旨在混合,因此应执行其中一个图像(在本例中为水印图像)的缩放,同时使用 SourceOver
将要缩放的图像绘制在另一个图像上> 操作。
这样,内部 GDI+(这里是 GDI+ 副本)函数就可以正确计算混合过程。
这还可以防止副本显示使用 new Bitmap()
方法创建较小图像时生成的不完美的半透明像素(类似于暗光晕)。
▶ 另外,我们需要确保所有操作都在 32BitArgb 位图上执行。
最好创建目标图像的 32BitArgb 副本并在此副本上绘制水印。这样也能保证更好的结果。 GDI+ 功能在此类图像上效果更好。
在这里,CopyToArgb32()
方法负责这方面的工作,还将原始图像的 DPI 分辨率应用于副本。
▶ 此外,这会产生扭曲的图像(除非这是预期的结果):
Bitmap watermarkNew = new Bitmap(watermark, new Size(image.Width / 10 * 3, image.Height / 10 * 3));
应调整水印图像尺寸的大小,计算比例因子,该比例因子是所需分数(百分比或固定度量)或目标图像。
例如,占用的最大尺寸等于目标位图最小尺寸的三分之一。
换句话说,如果目标位图大小为 1500x600 px
,水印位图将按比例缩放,最大高度为 200px
:
float scale = (Math.Min(original.Width, original.Height) * .33f) /
Math.Min(watermark.Width, watermark.Height);
SizeF watermarkSize = new SizeF(watermark.Width * scale, watermark.Height * scale);
为了进一步改善混合效果,可以将水印设置得不那么不透明(或者更透明,如您所愿)。
这可以使用 ColorMatrix
简单地实现,如下所示:
How to apply a fade transition effect to Images
所有内容都组合在一个公开 Watermark([Bitmap], [Bitmap], [Imageformat])
静态方法的类对象中。
在示例代码中,水印缩放至目标图像最大尺寸的 1/3 并居中(只是通用放置,因为未指定水印的位置):
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
public class BitmapOperations
{
public static Bitmap Watermark(Bitmap watermark, Bitmap original, ImageFormat format)
{
var units = GraphicsUnit.Pixel;
float scale = (Math.Max(original.Width, original.Height) * .33f) /
Math.Max(watermark.Width, watermark.Height);
var watermarkSize = new SizeF(watermark.Width * scale, watermark.Height * scale);
var watermarkBounds = CenterRectangleOnRectangle(
new RectangleF(PointF.Empty, watermarkSize), original.GetBounds(ref units));
var workImage = CopyToArgb32(original);
// Using the SetOpacity() extension method described in the linked question
// watermark = watermark.SetOpacity(.5f, 1.05f);
using (var g = Graphics.FromImage(workImage)) {
g.PixelOffsetMode = PixelOffsetMode.Half;
g.InterpolationMode = InterpolationMode.HighQualityBicubic;
g.DrawImage(watermark, watermarkBounds);
return workImage;
}
}
private static Bitmap CopyToArgb32(Bitmap source)
{
var bitmap = new Bitmap(source.Width, source.Height, PixelFormat.Format32bppArgb);
bitmap.SetResolution(source.HorizontalResolution, source.VerticalResolution);
using (var g = Graphics.FromImage(bitmap)) {
g.DrawImage(source, new Rectangle(0, 0, bitmap.Width, bitmap.Height),
new Rectangle(0, 0, bitmap.Width, bitmap.Height), GraphicsUnit.Pixel);
g.Flush();
}
return bitmap;
}
private static RectangleF CenterRectangleOnRectangle(RectangleF source, RectangleF destination)
{
source.Location = new PointF((destination.Width - source.Width) / 2,
(destination.Height - source.Height) / 2);
return source;
}
}
结果:
应用 50% 的不透明度级别和 Gamma 值的小修正:
关于c# - 调整用作水印的位图大小,结果显示黑色边框,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61974626/