【学习笔记】Windows GDI绘图(十一)Graphics详解(下)

2024-06-05 01:20

本文主要是介绍【学习笔记】Windows GDI绘图(十一)Graphics详解(下),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

文章目录

  • Graphics的方法
    • Graphics.FromImage
    • SetClip设置裁切区域
    • IntersectClip更新为相交裁切区域
    • TranslateClip平移裁切区域
    • IsVisible判断点或矩形是否在裁切区域内
    • MeasureCharacterRanges测量字符区域
    • MeasureString测量文本大小
    • MultiplyTransform矩阵变换

Graphics的方法

Graphics.FromImage

原型:

public static System.Drawing.Graphics FromImage (System.Drawing.Image image);

作用:从图像创建Graphics对象,后续可以在该对象上绘制图形等内容。

using (var image = Image.FromFile("AIWoman.png"))
{using (var newGraphics = Graphics.FromImage(image)){newGraphics.FillEllipse(Brushes.LightGreen, new Rectangle(50, 50, 200, 200));e.Graphics.DrawImage(image, 50, 50, 600, 600);}
}

1、从图像文件创建Image对象
2、从Image对象创建Graphics对象
3、在Graphics对象上绘制圆形
4、将上面的内容绘制到当前Graphics上。
FromImage
注意,不能从如下索引色图像创建Graphics对象:Format1bppIndexed、Format4bppIndexed、Format8bppIndexed,对索引色图像可使用Image.Save保存为其他格式。也不能从以下图像格式创建Graphics对象:Undefined、DontCare、Format16bppArgb1555和Format16bppGrayScale。
切记,在使用FromImage创建的Graphics对象后,要调用Dispose()方法。

SetClip设置裁切区域

原型:

public void SetClip (System.Drawing.Region region, System.Drawing.Drawing2D.CombineMode combineMode);
public void SetClip (System.Drawing.RectangleF rect, System.Drawing.Drawing2D.CombineMode combineMode);
public void SetClip (System.Drawing.Rectangle rect, System.Drawing.Drawing2D.CombineMode combineMode);
public void SetClip (System.Drawing.Graphics g, System.Drawing.Drawing2D.CombineMode combineMode);
public void SetClip (System.Drawing.RectangleF rect);
public void SetClip (System.Drawing.Rectangle rect);
public void SetClip (System.Drawing.Graphics g);
public void SetClip (System.Drawing.Drawing2D.GraphicsPath path);
public void SetClip (System.Drawing.Drawing2D.GraphicsPath path, System.Drawing.Drawing2D.CombineMode combineMode);

CombineMode枚举

说明
Complement现有区域被排除在新区域之外
Exclude新区域被排除在现有区域之外
Intersect两个区域的相交部分
Replace新区域替换现有区域
Union两个区域的合集
Xor取只属性某一区域的合并部分
var values = Enum.GetValues(typeof(CombineMode)) as CombineMode[];
CombineModeIndex= (CombineModeIndex+1) % values.Length;//原裁切区域
var originRect = new Rectangle(100, 100, 200, 100);
//另一裁切区域
var newRect = new Rectangle(250, 150, 200, 100);
e.Graphics.SetClip(originRect);Region clipRegion = new Region(newRect);
e.Graphics.SetClip(clipRegion, values[CombineModeIndex]);//查看组合后的裁切区域(亮绿色部分)
e.Graphics.FillRectangle(Brushes.LightGreen,e.Graphics.VisibleClipBounds);// 重置裁切区域
e.Graphics.ResetClip();// 区域两个区域的矩形
e.Graphics.DrawRectangle(new Pen(Color.Black), originRect);
e.Graphics.DrawRectangle(new Pen(Color.Red), newRect);
e.Graphics.DrawString($"CombineMode:{values[CombineModeIndex]},亮绿区域:SetClip组合的效果", Font, Brushes.Red, new PointF(20, 20));e.Graphics.DrawString($"黑色框:原裁切区域", Font, Brushes.Black, originRect.X, originRect.Y - 20);
e.Graphics.DrawString($"红色框:另一裁切区域", Font, Brushes.Red, newRect.X, newRect.Bottom + 10);

1、获取CombineMode的各枚举值
2、定义两个矩形,一个设为当前裁切区域,另一个为组合区域,测试不同CombineMode的值的效果
3、在重置裁切区域,将两个区域的矩形绘制显示,方便观察效果。
SetClip组合

IntersectClip更新为相交裁切区域

原型:

public void IntersectClip (System.Drawing.Rectangle rect);
public void IntersectClip (System.Drawing.RectangleF rect);
public void IntersectClip (System.Drawing.Region region);

作用:将当前裁切区域更新为与指定区域的交集。

TranslateClip平移裁切区域

原型:

public void TranslateClip (int dx, int dy);
public void TranslateClip (float dx, float dy);

作用:平移裁切区域

//原裁切区域
var originRect = new Rectangle(100, 100, 200, 100);
//另一裁切区域
var newRect = new Rectangle(250, 150, 200, 100);
e.Graphics.SetClip(originRect);Region clipRegion = new Region(newRect);
e.Graphics.IntersectClip(clipRegion);//查看组合后的裁切区域(亮绿色部分)
e.Graphics.FillRectangle(Brushes.LightGreen, e.Graphics.VisibleClipBounds);
//平移裁切区域亮蓝部分)
e.Graphics.TranslateClip(50, 50);
e.Graphics.FillRectangle(Brushes.LightBlue, e.Graphics.VisibleClipBounds);
// 重置裁切区域
e.Graphics.ResetClip();// 区域两个区域的矩形
e.Graphics.DrawRectangle(new Pen(Color.Black), originRect);
e.Graphics.DrawRectangle(new Pen(Color.Red), newRect);e.Graphics.DrawString($"IntersectClip方法,与SetClip的Intersect相同,亮绿部分", Font, Brushes.Red, new PointF(20, 20));
e.Graphics.DrawString($"平移后裁切区域,亮蓝部分", Font, Brushes.Red, new PointF(20, 35));
e.Graphics.DrawString($"黑色框:原裁切区域", Font, Brushes.Black, originRect.X, originRect.Y - 20);
e.Graphics.DrawString($"红色框:另一裁切区域", Font, Brushes.Red, newRect.X, newRect.Bottom + 10);

IntersectClip等同于SetClip方法的参数为CombineMode.Intersect时的效果。

IntersectClip与TranslateClip

IsVisible判断点或矩形是否在裁切区域内

原型:

public bool IsVisible (System.Drawing.Point point);
public bool IsVisible (System.Drawing.PointF point);
public bool IsVisible (System.Drawing.Rectangle rect);
public bool IsVisible (System.Drawing.RectangleF rect);
public bool IsVisible (int x, int y);
public bool IsVisible (float x, float y);
public bool IsVisible (int x, int y, int width, int height);
public bool IsVisible (float x, float y, float width, float height);

作用:判断一个点或一个矩形是否在裁切区域内(相交也算在区域内)

[System.ComponentModel.Description("Graphics的IsVisible方法")]
public void Demo11_04(PaintEventArgs e)
{//原裁切区域var clipRect = new Rectangle(100, 100, 200, 200);e.Graphics.SetClip(clipRect);e.Graphics.FillRectangle(Brushes.LightGreen, e.Graphics.VisibleClipBounds);//注意,这里的宽、高要减1e.Graphics.DrawRectangle(Pens.Red, clipRect.X, clipRect.Y, clipRect.Width - 1, clipRect.Height - 1);//区域外var ptA = new Point(80, 80);var isPtAVisiable = e.Graphics.IsVisible(ptA);//区域内var ptB = new Point(120, 120);var isPtBVisiable = e.Graphics.IsVisible(ptB);//边上,也算区域内var ptC = new Point(100, 100);var isPtCVisiable = e.Graphics.IsVisible(ptC);//另一边要减1,所以这里不算var ptD = new Point(clipRect.X + clipRect.Width, clipRect.Y + clipRect.Height);var isPtDVisiable = e.Graphics.IsVisible(ptD);var rectA = new Rectangle(320, 80, 50, 50);var isRectAVisiable = e.Graphics.IsVisible(rectA);var rectB = new Rectangle(180, 180, 50, 50);var isRectBVisiable = e.Graphics.IsVisible(rectB);var rectC = new Rectangle(280, 280, 50, 50);var isRectCVisiable = e.Graphics.IsVisible(rectC);var clipBounds = e.Graphics.ClipBounds;e.Graphics.ResetClip();DrawPointIsVisiable(e, ptA, isPtAVisiable);DrawPointIsVisiable(e, ptB, isPtBVisiable);DrawPointIsVisiable(e, ptC, isPtCVisiable);DrawPointIsVisiable(e, ptD, isPtDVisiable);DrawRectIsVisiable(e, rectA, isRectAVisiable);DrawRectIsVisiable(e, rectB, isRectBVisiable);DrawRectIsVisiable(e, rectC, isRectCVisiable);e.Graphics.DrawString($"有效裁切区域:({clipBounds.X},{clipBounds.Y},{clipBounds.Width},{clipBounds.Height})", Font, Brushes.Red, new Point(20, 20));           
}//显示点是否可见
private void DrawPointIsVisiable(PaintEventArgs e, Point pt, bool isVisable)
{e.Graphics.FillEllipse(Brushes.Red, pt.X - 3, pt.Y - 3, 6, 6);e.Graphics.DrawString($"Pt({pt.X},{pt.Y}),是否可见:{isVisable}", Font, Brushes.Red, pt.X + 10, pt.Y);
}//显示矩形是否可见
private void DrawRectIsVisiable(PaintEventArgs e,Rectangle rect,bool isVisable)
{e.Graphics.DrawRectangle(Pens.Blue, rect);e.Graphics.DrawString($"Rect({rect.X},{rect.Y},{rect.Width},{rect.Height}),是否可见:{isVisable}", Font, Brushes.Blue, rect.Right + 10, rect.Y);
}

1、分别测试点在区域外、区域边缘、区域内的情况
2、分别测试矩形在区域外、区域相交、区域内的情况
IsVisable

MeasureCharacterRanges测量字符区域

原型:

public System.Drawing.Region[] MeasureCharacterRanges (string text, System.Drawing.Font font, System.Drawing.RectangleF layoutRect, System.Drawing.StringFormat stringFormat);

作用:给定一个文字绘制布局(需够长足以绘制文字),测量相应的文字的绘制范围。

// 设置一段文字
string measureString = "Hello,这是一段测试范围的文字";
using (Font stringFont = new Font("宋体", 16.0F))
{// 设置"Hello","测试范围"的字符范围CharacterRange[] characterRanges = { new CharacterRange(0, 5), new CharacterRange(10, 4) };// Create rectangle for layout.float x = 50.0F;float y = 50.0F;float width = 75.0F;float height = 500.0F;//注意,这个范围要能完整含文字在RectangleF layoutRect = new RectangleF(x, y, width, height);e.Graphics.DrawRectangle(Pens.LightGreen, Rectangle.Round(layoutRect));// 设置文字格式StringFormat stringFormat = new StringFormat();stringFormat.FormatFlags = StringFormatFlags.DirectionVertical;stringFormat.SetMeasurableCharacterRanges(characterRanges);// 绘制文字e.Graphics.DrawString(measureString, stringFont, Brushes.Black, x, y, stringFormat);// 绘制两个文字的区域Region[] stringRegions = e.Graphics.MeasureCharacterRanges(measureString,stringFont, layoutRect, stringFormat);// 绘制第一个文字区域RectangleF measureRect1 = stringRegions[0].GetBounds(e.Graphics);e.Graphics.DrawRectangle(new Pen(Color.Red, 1), Rectangle.Round(measureRect1));// 绘制第二个文字区域RectangleF measureRect2 = stringRegions[1].GetBounds(e.Graphics);e.Graphics.DrawRectangle(new Pen(Color.Blue, 1), Rectangle.Round(measureRect2));
}  

1、定义一段要测量的文字“Hello,这是一段测试范围的文字”,其中要测试"Hello"与"测试范围"两个字符串区域
2、定义文字绘制矩形布局
3、绘制文字
4、测量文字的范围
5、将测量范围用两个矩形框绘制到文字处。
MeasureCharacterRanges

MeasureString测量文本大小

原型:

public System.Drawing.SizeF MeasureString (string text, System.Drawing.Font font);
public System.Drawing.SizeF MeasureString (string text, System.Drawing.Font font, System.Drawing.SizeF layoutArea);
public System.Drawing.SizeF MeasureString (string text, System.Drawing.Font font, int width);
public System.Drawing.SizeF MeasureString (string text, System.Drawing.Font font, System.Drawing.PointF origin, System.Drawing.StringFormat stringFormat);
public System.Drawing.SizeF MeasureString (string text, System.Drawing.Font font, System.Drawing.SizeF layoutArea, System.Drawing.StringFormat stringFormat);
public System.Drawing.SizeF MeasureString (string text, System.Drawing.Font font, int width, System.Drawing.StringFormat format);
public System.Drawing.SizeF MeasureString (string text, System.Drawing.Font font, System.Drawing.SizeF layoutArea, System.Drawing.StringFormat stringFormat, out int charactersFitted, out int linesFilled);

作用:测量文本的范围,或限制宽度时,可自动计算行换后的高度,也统计字符个数,行数。

//设置文本和字体‌
string measureString = "待测试的文字还包含English";
Font stringFont = new Font("宋体", 16);//测量文本大小
var stringSize = e.Graphics.MeasureString(measureString, stringFont);
var insertPt = new PointF(20, 20);
//绘制文本大小的矩形
e.Graphics.DrawRectangle(new Pen(Color.Red, 1), insertPt.X, insertPt.Y, stringSize.Width, stringSize.Height);
//绘制文本
e.Graphics.DrawString(measureString, stringFont, Brushes.Black, insertPt);e.Graphics.TranslateTransform(100, 100);
// Set point for upper-left corner of string.
float x = 50.0F;
float y = 50.0F;
PointF ulCorner = new PointF(x, y);// Set string format.
StringFormat newStringFormat = new StringFormat();
newStringFormat.FormatFlags = StringFormatFlags.DirectionVertical;// Measure string.
stringSize = e.Graphics.MeasureString(measureString, stringFont, ulCorner, newStringFormat);// Draw rectangle representing size of string.
e.Graphics.DrawRectangle(new Pen(Color.Red, 1), x, y, stringSize.Width, stringSize.Height);// Draw string to screen.
e.Graphics.DrawString(measureString, stringFont, Brushes.Black, ulCorner, newStringFormat);e.Graphics.TranslateTransform(100, 0);// Set maximum layout size.
var layoutSize = new SizeF(100.0F, 300.0F);// Set string format.
newStringFormat.FormatFlags = StringFormatFlags.DirectionVertical;// Measure string.
stringSize = e.Graphics.MeasureString(measureString, stringFont, layoutSize, newStringFormat);// Draw rectangle representing size of string.
e.Graphics.DrawRectangle(new Pen(Color.Red, 1), 0.0F, 0.0F, stringSize.Width, stringSize.Height);// Draw string to screen.
e.Graphics.DrawString(measureString, stringFont, Brushes.Black, new PointF(0, 0), newStringFormat);e.Graphics.TranslateTransform(100, 0);// Set maximum width of string.
int stringWidth = 100;// Set string format.
newStringFormat.FormatFlags = StringFormatFlags.DirectionVertical;// Measure string.
stringSize = e.Graphics.MeasureString(measureString, stringFont, stringWidth, newStringFormat);// Draw rectangle representing size of string.
e.Graphics.DrawRectangle(new Pen(Color.Red, 1), 0.0F, 0.0F, stringSize.Width, stringSize.Height);// Draw string to screen.
e.Graphics.DrawString(measureString, stringFont, Brushes.Black, new PointF(0, 0), newStringFormat);//============
e.Graphics.TranslateTransform(100, 0);
// Set maximum layout size.
layoutSize = new SizeF(100.0F, 300.0F);// Set string format.
newStringFormat.FormatFlags = StringFormatFlags.DirectionVertical;// Measure string.
int charactersFitted;
int linesFilled;
stringSize = e.Graphics.MeasureString(measureString, stringFont, layoutSize, newStringFormat, out charactersFitted, out linesFilled);// Draw rectangle representing size of string.
e.Graphics.DrawRectangle(new Pen(Color.Red, 1), 0.0F, 0.0F, stringSize.Width, stringSize.Height);// Draw string to screen.
e.Graphics.DrawString(measureString, stringFont, Brushes.Black, new PointF(0, 0), newStringFormat);// Draw output parameters to screen.
string outString = "chars " + charactersFitted + ", lines " + linesFilled;
e.Graphics.DrawString(outString, stringFont, Brushes.Black, new PointF(100, 0));

测试不同参数下测量文本区域的结果。
MeasureString

MultiplyTransform矩阵变换

原型:

public void MultiplyTransform (System.Drawing.Drawing2D.Matrix matrix);//默认是MatrixOrder.Prepend
public void MultiplyTransform (System.Drawing.Drawing2D.Matrix matrix, System.Drawing.Drawing2D.MatrixOrder order);

作用:将世界变换矩阵与该矩形相乘。

var rect = new Rectangle(0, 0, 200, 100);
var pt1 = new Point(0, 0);
var pt2 = new Point(200, 100);
// Create transform matrix.
using (Matrix transformMatrix = new Matrix())
{//平移(200,100)transformMatrix.Translate(200.0F, 100.0F);//世界坐标顺时旋转30度e.Graphics.RotateTransform(30.0F);e.Graphics.DrawLine(Pens.Red, pt1, pt2);e.Graphics.DrawEllipse(new Pen(Color.Blue, 3), rect);//先平移,再旋转e.Graphics.MultiplyTransform(transformMatrix);//默认是 MatrixOrder.Prepend在e.Graphics.DrawLine(Pens.Blue, pt1, pt2);// Draw rotated, translated ellipse.e.Graphics.DrawEllipse(new Pen(Color.Blue, 3), rect);e.Graphics.ResetTransform();//世界坐标顺时旋转30度e.Graphics.RotateTransform(30.0F);//先旋转,再平移e.Graphics.MultiplyTransform(transformMatrix, MatrixOrder.Append);e.Graphics.DrawLine(Pens.Red, pt1, pt2);e.Graphics.DrawEllipse(new Pen(Color.Red, 3), rect);
}

分别测试应用矩阵顺序不同,导致的结果不同。
MultiplyTransform

这篇关于【学习笔记】Windows GDI绘图(十一)Graphics详解(下)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1031679

相关文章

HarmonyOS学习(七)——UI(五)常用布局总结

自适应布局 1.1、线性布局(LinearLayout) 通过线性容器Row和Column实现线性布局。Column容器内的子组件按照垂直方向排列,Row组件中的子组件按照水平方向排列。 属性说明space通过space参数设置主轴上子组件的间距,达到各子组件在排列上的等间距效果alignItems设置子组件在交叉轴上的对齐方式,且在各类尺寸屏幕上表现一致,其中交叉轴为垂直时,取值为Vert

Ilya-AI分享的他在OpenAI学习到的15个提示工程技巧

Ilya(不是本人,claude AI)在社交媒体上分享了他在OpenAI学习到的15个Prompt撰写技巧。 以下是详细的内容: 提示精确化:在编写提示时,力求表达清晰准确。清楚地阐述任务需求和概念定义至关重要。例:不用"分析文本",而用"判断这段话的情感倾向:积极、消极还是中性"。 快速迭代:善于快速连续调整提示。熟练的提示工程师能够灵活地进行多轮优化。例:从"总结文章"到"用

Spring Security基于数据库验证流程详解

Spring Security 校验流程图 相关解释说明(认真看哦) AbstractAuthenticationProcessingFilter 抽象类 /*** 调用 #requiresAuthentication(HttpServletRequest, HttpServletResponse) 决定是否需要进行验证操作。* 如果需要验证,则会调用 #attemptAuthentica

AI绘图怎么变现?想做点副业的小白必看!

在科技飞速发展的今天,AI绘图作为一种新兴技术,不仅改变了艺术创作的方式,也为创作者提供了多种变现途径。本文将详细探讨几种常见的AI绘图变现方式,帮助创作者更好地利用这一技术实现经济收益。 更多实操教程和AI绘画工具,可以扫描下方,免费获取 定制服务:个性化的创意商机 个性化定制 AI绘图技术能够根据用户需求生成个性化的头像、壁纸、插画等作品。例如,姓氏头像在电商平台上非常受欢迎,

【前端学习】AntV G6-08 深入图形与图形分组、自定义节点、节点动画(下)

【课程链接】 AntV G6:深入图形与图形分组、自定义节点、节点动画(下)_哔哩哔哩_bilibili 本章十吾老师讲解了一个复杂的自定义节点中,应该怎样去计算和绘制图形,如何给一个图形制作不间断的动画,以及在鼠标事件之后产生动画。(有点难,需要好好理解) <!DOCTYPE html><html><head><meta charset="UTF-8"><title>06

学习hash总结

2014/1/29/   最近刚开始学hash,名字很陌生,但是hash的思想却很熟悉,以前早就做过此类的题,但是不知道这就是hash思想而已,说白了hash就是一个映射,往往灵活利用数组的下标来实现算法,hash的作用:1、判重;2、统计次数;

OpenHarmony鸿蒙开发( Beta5.0)无感配网详解

1、简介 无感配网是指在设备联网过程中无需输入热点相关账号信息,即可快速实现设备配网,是一种兼顾高效性、可靠性和安全性的配网方式。 2、配网原理 2.1 通信原理 手机和智能设备之间的信息传递,利用特有的NAN协议实现。利用手机和智能设备之间的WiFi 感知订阅、发布能力,实现了数字管家应用和设备之间的发现。在完成设备间的认证和响应后,即可发送相关配网数据。同时还支持与常规Sof

零基础学习Redis(10) -- zset类型命令使用

zset是有序集合,内部除了存储元素外,还会存储一个score,存储在zset中的元素会按照score的大小升序排列,不同元素的score可以重复,score相同的元素会按照元素的字典序排列。 1. zset常用命令 1.1 zadd  zadd key [NX | XX] [GT | LT]   [CH] [INCR] score member [score member ...]

科研绘图系列:R语言扩展物种堆积图(Extended Stacked Barplot)

介绍 R语言的扩展物种堆积图是一种数据可视化工具,它不仅展示了物种的堆积结果,还整合了不同样本分组之间的差异性分析结果。这种图形表示方法能够直观地比较不同物种在各个分组中的显著性差异,为研究者提供了一种有效的数据解读方式。 加载R包 knitr::opts_chunk$set(warning = F, message = F)library(tidyverse)library(phyl

【机器学习】高斯过程的基本概念和应用领域以及在python中的实例

引言 高斯过程(Gaussian Process,简称GP)是一种概率模型,用于描述一组随机变量的联合概率分布,其中任何一个有限维度的子集都具有高斯分布 文章目录 引言一、高斯过程1.1 基本定义1.1.1 随机过程1.1.2 高斯分布 1.2 高斯过程的特性1.2.1 联合高斯性1.2.2 均值函数1.2.3 协方差函数(或核函数) 1.3 核函数1.4 高斯过程回归(Gauss