gpt4 book ai didi

c# - 如何在图像上绘制透明形状

转载 作者:行者123 更新时间:2023-12-04 02:33:52 26 4
gpt4 key购买 nike

如何在图像上绘制形状以覆盖那里的内容并使其透明?
就像下图中间的透明孔一样。
enter image description here
编辑:
我一般用Graphics.FromImage(image)绘图时,即

Graphics.FromImage(image).DrawRectangle(...) 
但我想在图像中间制作一个透明的孔或矩形。

最佳答案

此方法使用两个 GraphicsPath对象和 TextureBrush在位图中绘制透明孔(参见 Worker methods 部分中对该功能的描述)。
当我们要使用的位图被加载时,(这里,使用 File.ReadAllBytes()MemoryStream 以避免锁定磁盘上的图像文件),它被分配到一个私有(private)字段 drawingBitmap 然后将其克隆以创建 PictureBox.Image 中所示的对象属性(原始图像总是以某种方式复制,我们从不修改它)。
selectionRect 字段跟踪所选区域(使用不同的方式,如视觉示例中所示)。
shapeOfHole Field 是一个枚举器,它指定 selectionRect 的形状类型。正在描述(这里是矩形或椭圆形,但它可以是任何其他形状:使用 GraphicsPaths 作为容器可以更简单地添加多边形形状)。
preserveImage boolean Field 是一个选择器,用于确定是在现有Image中添加新孔还是每次都创建一个新孔。
在这里的示例代码中,两个按钮, btnLoadImage btnPaintHole 用于激活主要功能(加载和分配图像并在选定的位图中绘制一个或多个孔)。
picCanvas 是用于显示图像的 PictureBox。

Private drawingBitmap As Image = Nothing
Private selectionRect As RectangleF = New RectangleF(100, 100, 50, 50)
Private shapeOfHole As ShapeType = ShapeType.Rectangle
Private preserveImage as Boolean = False

Private Sub btnLoadImage_Click(sender As Object, e As EventArgs) Handles btnLoadImage.Click
Dim imagePath As String = [Your Image Path]
drawingBitmap = Image.FromStream(New MemoryStream(File.ReadAllBytes(imagePath)))
picCanvas.Image?.Dispose()
picCanvas.Image = DirectCast(drawingBitmap.Clone(), Bitmap)
End Sub

Private Sub btnPaintHole_Click(sender As Object, e As EventArgs) Handles btnPaintHole.Click
Dim newImage As Image = Nothing
If preserveImage AndAlso picCanvas.Image IsNot Nothing Then
newImage = DrawHole(picCanvas.Image, picCanvas, selectionRect, shapeOfHole)
Else
newImage = DrawHole(drawingBitmap, picCanvas, selectionRect, shapeOfHole)
End If

If newImage IsNot Nothing Then
picCanvas.Image?.Dispose()
picCanvas.Image = newImage
End If
End Sub
功能的视觉示例 :
GraphicsPath Draw Holes
Image used as the PictureBox.BackgroundImage模拟经典的透明背景。
工作方法 :
DrawHole() 方法使用两个 GraphicsPath对象。
imagePath 对象的大小与原始图像相同, selectionPath 对象的大小为当前选择区域(之后将缩放以匹配图像的实际大小)。
使用 FillMode.Alternate模式, imagePath.AddPath(selectionPath, True)方法设置 connect True 的参数,指定添加的 selectionPath成为 imagePath 的一部分.由于 FillMode.Alternate是 XOR 操作,我们在 imagePath 中创建一个洞.
Graphics.FillPath()然后方法使用 TextureBrush用 Bitmap 对象填充 GraphicsPath,除了 XOR-ed 部分,该对象将包含一个消除锯齿的透明区域(Graphics 对象使用 SmoothingMode.AntiAlias 模式)。
GetScaledSelectionRect() 方法使用技巧来简化缩放图像内选择矩形的未缩放坐标的计算(PictureBox 控件 SizeMode 很可能设置为 PictureBoxSizeMode.Zoom):它读取 .Net PictureBox 类 ImageRectangle属性(谁知道为什么, private),确定图像缩放边界并根据此度量计算选择矩形的偏移量和比例。
Imports System.Drawing
Imports System.Drawing.Drawing2D
Imports System.Drawing.Imaging
Imports System.IO
Imports System.Reflection

Friend Enum ShapeType
Rectangle
Ellipse
End Enum

Friend Function DrawHole(srcImage As Image, canvas As PictureBox, holeShape As RectangleF, typeOfShape As ShapeType) As Image
Dim cropped = New Bitmap(srcImage.Width, srcImage.Height, PixelFormat.Format32bppArgb)

Dim imageRect = New RectangleF(Point.Empty, srcImage.Size)
Dim selectionRect = GetScaledSelectionRect(canvas, holeShape)

Using tBrush = New TextureBrush(srcImage),
imagePath = New GraphicsPath(FillMode.Alternate),
selectionPath = New GraphicsPath(),
g = Graphics.FromImage(cropped)

Select Case typeOfShape
Case ShapeType.Ellipse
selectionPath.AddEllipse(selectionRect)
Case ShapeType.Rectangle
selectionPath.AddRectangle(selectionRect)
End Select
imagePath.AddRectangle(imageRect)
imagePath.AddPath(selectionPath, True)
g.SmoothingMode = SmoothingMode.AntiAlias
g.FillPath(tBrush, imagePath)
Return cropped
End Using
End Function

Friend Function GetScaledSelectionRect(canvas As PictureBox, selectionRect As RectangleF) As RectangleF
If canvas.Image Is Nothing Then Return selectionRect
Dim flags = BindingFlags.NonPublic Or BindingFlags.Instance Or BindingFlags.GetProperty

Dim imageRect = DirectCast(canvas.GetType().GetProperty("ImageRectangle", flags).GetValue(canvas), Rectangle)

Dim scaleX = CSng(canvas.Image.Width) / imageRect.Width
Dim scaleY = CSng(canvas.Image.Height) / imageRect.Height

Dim selectionOffset = RectangleF.Intersect(imageRect, selectionRect)
selectionOffset.Offset(-imageRect.X, -imageRect.Y)
Return New RectangleF(selectionOffset.X * scaleX, selectionOffset.Y * scaleY,
selectionOffset.Width * scaleX, selectionOffset.Height * scaleY)
End Function

C#版本 :

private Image drawingBitmap = null;
private RectangleF selectionRect = new RectangleF(100, 100, 50, 50);
private ShapeType shapeOfHole = ShapeType.Rectangle;
private bool preserveImage = false;

private void btnLoadImage_Click(object sender, EventArgs e)
{
string imagePath = [Your Image Path];
drawingBitmap = Image.FromStream(new MemoryStream(File.ReadAllBytes(imagePath)));
picCanvas.Image?.Dispose();
picCanvas.Image = drawingBitmap.Clone() as Bitmap;
}

private void btnPaintHole_Click(object sender, EventArgs e)
{
Image newImage = null;
if (preserveImage && picCanvas.Image != null) {
newImage = DrawHole(picCanvas.Image, picCanvas, selectionRect, shapeOfHole);
}
else {
newImage = DrawHole(drawingBitmap, picCanvas, selectionRect, shapeOfHole);
}

if (newImage != null) {
picCanvas.Image?.Dispose();
picCanvas.Image = newImage;
}
}
工作方法 :
注: GetScaledSelectionRect() ,如前所述,使用反射来读取 PictureBox private ImageRectangle .Net 控件的属性。
由于此方法是从绘图过程中调用的,因此最好在自定义 PictureBox 控件中重新实现此方法,或者在不调用 the underlying method 的情况下执行计算。 (反射并不像有时宣传的那么慢,但它当然比直接使用一些数学要慢,这里)。
这里展示了一些可能的实现(例如):
Zoom and translate an Image from the mouse location
Translate Rectangle Position in a Picturebox with SizeMode.Zoom
internal enum ShapeType {
Rectangle,
Ellipse
}

internal Image DrawHole(Image srcImage, PictureBox canvas, RectangleF holeShape, ShapeType typeOfShape)
{
var cropped = new Bitmap(srcImage.Width, srcImage.Height, PixelFormat.Format32bppArgb);
var imageRect = new RectangleF(Point.Empty, srcImage.Size);
RectangleF selectionRect = GetScaledSelectionRect(canvas, holeShape);

using (var tBrush = new TextureBrush(srcImage))
using (var imagePath = new GraphicsPath(FillMode.Alternate))
using (var selectionPath = new GraphicsPath())
using (var g = Graphics.FromImage(cropped)) {

switch (typeOfShape) {
case ShapeType.Ellipse:
selectionPath.AddEllipse(selectionRect);
break;
case ShapeType.Rectangle:
selectionPath.AddRectangle(selectionRect);
break;
}
imagePath.AddRectangle(imageRect);
imagePath.AddPath(selectionPath, true);

g.SmoothingMode = SmoothingMode.AntiAlias;
g.FillPath(tBrush, imagePath);
return cropped;
}
}

internal RectangleF GetScaledSelectionRect(PictureBox canvas, RectangleF selectionRect)
{
if (canvas.Image == null) return selectionRect;
var flags = BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.GetProperty;

var imageRect = (Rectangle)canvas.GetType().GetProperty("ImageRectangle", flags).GetValue(canvas);
var scaleX = (float)canvas.Image.Width / imageRect.Width;
var scaleY = (float)canvas.Image.Height / imageRect.Height;

var selectionOffset = RectangleF.Intersect(imageRect, selectionRect);
selectionOffset.Offset(-imageRect.X, -imageRect.Y);

return new RectangleF(selectionOffset.X * scaleX, selectionOffset.Y * scaleY,
selectionOffset.Width * scaleX, selectionOffset.Height * scaleY);
}

关于c# - 如何在图像上绘制透明形状,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62720826/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com