调整用作水印的位图的大小结果显示深色边框
Resizing a Bitmap used as watermark the result shows dark borders
问题:
我有一个要打印在图像上的水印。图像大小不一,因此有时水印太大,有时太小。为了解决这个问题,我计算了图像的大小并调整了水印的大小。但是,调整图像大小后,其边缘出现黑色边框。
代码
我正在 Mac 使用 .NET Core3.1
并且我正在使用两个有助于绘制图像/位图的 NuGet 包。一个是 System.Drawing.Common
另一个,因为我在 macOS 上是 runtime.osx.10.10x64.CoreCompat.System.Drawing
.
我用来调整水印大小的代码创建here:
Bitmap watermarkNew = new Bitmap(watermark, new Size(image.Width / 10 * 3, image.Height / 10 * 3));
我必须使用 / 10 * 3
因为位图构造函数不接受浮点值,所以我不能乘以 * 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);
为了进一步改善混合效果,水印可以做得更少不透明(或者,更多透明,如您所愿).
这可以简单地使用 as ColorMatrix
来实现,如下所示:
所有组合在一个 class 对象中,该对象公开了一个 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% 的不透明度和小的伽玛校正:
问题:
我有一个要打印在图像上的水印。图像大小不一,因此有时水印太大,有时太小。为了解决这个问题,我计算了图像的大小并调整了水印的大小。但是,调整图像大小后,其边缘出现黑色边框。
代码
我正在 Mac 使用 .NET Core3.1
并且我正在使用两个有助于绘制图像/位图的 NuGet 包。一个是 System.Drawing.Common
另一个,因为我在 macOS 上是 runtime.osx.10.10x64.CoreCompat.System.Drawing
.
我用来调整水印大小的代码创建here:
Bitmap watermarkNew = new Bitmap(watermark, new Size(image.Width / 10 * 3, image.Height / 10 * 3));
我必须使用 / 10 * 3
因为位图构造函数不接受浮点值,所以我不能乘以 * 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);
为了进一步改善混合效果,水印可以做得更少不透明(或者,更多透明,如您所愿).
这可以简单地使用 as ColorMatrix
来实现,如下所示:
所有组合在一个 class 对象中,该对象公开了一个 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% 的不透明度和小的伽玛校正: