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

文章目录

  • Graphics的方法
    • AddMetafileComment添加注释
    • BeginContainer和EndContainer新建、还原图形容器
      • 不指定指定源与目标矩形
      • 指定源与目标矩形
    • Clear清空并填充指定颜色
    • CopyFromScreen
      • 截图
      • CopyPixelOperation
    • DrawImage绘制图像
    • DrawImage的Graphics+DrawImageAbort回调
    • ExcludeClip排除裁切区域

Graphics的方法

AddMetafileComment添加注释

原型:

public void AddMetafileComment (byte[] data);

作用:向当前图元(Metafile)文件添加注释。只对图元文件有效。

// 创建新的Graphics对象并获取其句柄
Graphics newGraphics = this.CreateGraphics();
IntPtr hdc = newGraphics.GetHdc();// 创建新的图元文件
Metafile metaFile1 = new Metafile("SampMeta.emf", hdc);// 从图元文件创建Graphics对象
Graphics metaGraphics = Graphics.FromImage(metaFile1);// 绘制一个矩形
metaGraphics.DrawRectangle(new Pen(Color.Black, 5), 0, 0, 100, 100);// 添加注释
byte[] metaComment = { (byte)'T', (byte)'e', (byte)'s', (byte)'t' };
metaGraphics.AddMetafileComment(metaComment);metaGraphics.Dispose();metaFile1.Dispose();newGraphics.ReleaseHdc(hdc);newGraphics.Dispose();// 打开一个图元文件
Metafile metaFile2 = new Metafile("SampMeta.emf");// 将图元文件内容绘制到当前Graphics上
e.Graphics.DrawImage(metaFile2, new Point(0, 0));metaFile2.Dispose();

创建一个新的图元件,保存后,打开并绘制。目前没看出有啥作用,在图像文件中嵌入一些信息?可还没找到读取的方法。

BeginContainer和EndContainer新建、还原图形容器

原型:

public System.Drawing.Drawing2D.GraphicsContainer BeginContainer ();
public System.Drawing.Drawing2D.GraphicsContainer BeginContainer (System.Drawing.Rectangle dstrect, System.Drawing.Rectangle srcrect, System.Drawing.GraphicsUnit unit);
public System.Drawing.Drawing2D.GraphicsContainer BeginContainer (System.Drawing.RectangleF dstrect, System.Drawing.RectangleF srcrect, System.Drawing.GraphicsUnit unit);
public void EndContainer (System.Drawing.Drawing2D.GraphicsContainer container);

作用:保存图形容器及其当前状态,再打开并使用新的图形容器。
可定义源矩形与目标矩形来生成新的图形容器,实现坐标变换。
关闭当前图形容器并改得到通过调用BeginContainer()方法保存的状态。

不指定指定源与目标矩形

//将当前状态保存到containerState,并打开一个新的图形容器
GraphicsContainer containerState = e.Graphics.BeginContainer();// 在新图形容器来执行平移
e.Graphics.TranslateTransform(100.0F, 100.0F);// 填充一个红色矩形
e.Graphics.FillRectangle(new SolidBrush(Color.Red), 0, 0, 200, 200);// 还原图形容器状态(还原到未平移前的状态)
e.Graphics.EndContainer(containerState);// Fill untransformed rectangle with green.
e.Graphics.FillRectangle(new SolidBrush(Color.Green), 0, 0, 200, 200);

1、保存原图形容器
2、在新的图形容器内到平移变换
3、绘制一个矩形
4、还原图形容器
5、再绘制一个与前面坐标一致(世界坐标)的矩形
注意结果位置的不同
BeginContainer

指定源与目标矩形

// 定义源矩形和目标矩形,
RectangleF srcRect = new RectangleF(0, 0, 200, 200);
RectangleF destRect = new RectangleF(100, 100, 150, 150);// 保存,并打开一个变换后图形容器
GraphicsContainer containerState = e.Graphics.BeginContainer(destRect, srcRect,GraphicsUnit.Pixel);//定义一个矩形,注意两个图形容器绘制时的区别
var rect = new RectangleF(50, 50, 200, 150);
//在变换后的容器内填充矩形
e.Graphics.FillRectangle(new SolidBrush(Color.FromArgb(127, Color.Red)), rect.X, rect.Y, rect.Width, rect.Height);e.Graphics.EndContainer(containerState);// 在未变换的容器内填充矩形
e.Graphics.FillRectangle(new SolidBrush(Color.FromArgb(127, Color.Green)), rect.X, rect.Y, rect.Width, rect.Height);var wScale = destRect.Width / srcRect.Width;
var hScale = destRect.Height / srcRect.Height;
//在未变换的容器内绘制一个矩形,使其与变换的填充矩形重叠,注意计算方法
e.Graphics.DrawRectangle(Pens.Black, destRect.X + (rect.X - srcRect.X) * wScale,destRect.Y + (rect.Y - srcRect.Y) * hScale,rect.Width * wScale,rect.Height * hScale);

1、定义两个矩形用于新图形容器的目标与源矩形
2、使用上面两个矩形,打开一个新的图形容器
3、填充一个矩形
4、还原图形容器
5、使用世界坐标相同的矩形,在原图形容器里填充一个矩形
6、在原图形里计算一个与变换后图形容器中一样大小的矩形(注意计算方法)
容器缩放

Clear清空并填充指定颜色

原型:

public void Clear (System.Drawing.Color color);

作用:清空整个绘图表面并用指定颜色填充为背景色。

CopyFromScreen

原型:

public void CopyFromScreen (System.Drawing.Point upperLeftSource, System.Drawing.Point upperLeftDestination, System.Drawing.Size blockRegionSize);
public void CopyFromScreen (System.Drawing.Point upperLeftSource, System.Drawing.Point upperLeftDestination, System.Drawing.Size blockRegionSize, System.Drawing.CopyPixelOperation copyPixelOperation);
public void CopyFromScreen (int sourceX, int sourceY, int destinationX, int destinationY, System.Drawing.Size blockRegionSize);

作用:从屏幕复制(截图)

截图

int drawCount = 1;
[System.ComponentModel.Description("Graphics的CopyFromScreen1方法")]
public void Demo10_05(PaintEventArgs e)
{var srcPt = this.Location;e.Graphics.DrawString($"{drawCount}", new Font("宋体", 18), Brushes.Red, new Point(20, 20));//桌面左上角(100,100)位置开始,复制(截图一个200 x 200)的图像,绘制在(50,50)的起点位置e.Graphics.CopyFromScreen(srcPt, new Point(50, 50),new Size(200, 200));drawCount++;
}

截图然后绘制到当前Graphics中,注意,如果开启DoubleBuffer复制的图像是上一次的。如果没有开启,则复制的图像是当前绘制的。

在这里插入图片描述

CopyPixelOperation

确定复制像素操作中的源颜色如何与目标颜色组合以产生最终颜色。

private Image TransparentBmp;[System.ComponentModel.Description("Graphics的CopyFromScreen的CopyPixelOperation方法")]
public void Demo10_06(PaintEventArgs e)
{var srcX = this.Location.X + 40;//var srcY = this.Location.Y + 103;//var values = Enum.GetValues(typeof(CopyPixelOperation)) as CopyPixelOperation[];if (TransparentBmp == null){TransparentBmp = new Bitmap("transparent.png");}var dstSize = new Size(128, (int)(128f * TransparentBmp.Height / TransparentBmp.Width));e.Graphics.DrawImage(TransparentBmp, e.Graphics.ClipBounds);e.Graphics.DrawImage(TransparentBmp, 10, 20, dstSize.Width, dstSize.Height);var colCount = 5;for (int i = 0; i < values.Length; i++){var val = values[i];e.Graphics.DrawString($"{val}", Font, Brushes.Red, new Point(20 + ((i + 1) % colCount) * (dstSize.Width + 20), 5 + ((i + 1) / colCount) * (dstSize.Height + 20)));var dstX = 20 + ((i + 1) % colCount) * (dstSize.Width + 20);var dstY = 20 + ((i + 1) / colCount) * (dstSize.Height + 20);//e.Graphics.DrawImage(TransparentBmp, dstX, dstY , dstSize.Width, dstSize.Height);e.Graphics.CopyFromScreen(srcX, srcY, dstX, dstY, dstSize, val);}
}

绘制一个背景再左上角绘制一个透明图,用CopyFromScreen截取透明图位置,用不的CopyPixelOperation值绘制结果。
CopyPixelOperation

DrawImage绘制图像

原型:

//截取源图绘制到指定点
public void DrawImage (System.Drawing.Image image, float x, float y, System.Drawing.RectangleF srcRect, System.Drawing.GraphicsUnit srcUnit);//截取源图,以指定大小矩形绘制
public void DrawImage (System.Drawing.Image image, System.Drawing.RectangleF destRect, System.Drawing.RectangleF srcRect, System.Drawing.GraphicsUnit srcUnit);//截取源图,绘制到指定位置平行四边形,并应用图像属性
public void DrawImage (System.Drawing.Image image, System.Drawing.PointF[] destPoints, System.Drawing.RectangleF srcRect, System.Drawing.GraphicsUnit srcUnit, System.Drawing.Imaging.ImageAttributes imageAttr);
        private Image LenaBmp;[System.ComponentModel.Description("Graphics的DrawImage方法")]public void Demo10_07(PaintEventArgs e){if (LenaBmp == null){LenaBmp = new Bitmap("lena.jpg");}var dstSize = new Size(256, 256);var space = 20;//缩小后绘制原图e.Graphics.DrawImage(LenaBmp, space, space, dstSize.Width, dstSize.Height);//注意,这里截取的原图是192X192,但绘制的是256*256 退即 192/72*96e.Graphics.DrawImage(LenaBmp, 300, space, new Rectangle(200, 200, 192, 192), GraphicsUnit.Pixel);var srcRect = new RectangleF(50, 50, LenaBmp.Width - 100, LenaBmp.Height - 100);var dstRect = new RectangleF(580, space, 200, 200);//截取部分源图像,绘制到目标矩形上(大小可缩放)e.Graphics.DrawImage(LenaBmp, dstRect,srcRect , GraphicsUnit.Pixel);//目标平行四边形的左上、右上、左下三个顶点var dstPts = new PointF[] { new PointF(20, 350), new PointF(276, 300), new PointF(120, 500)};// Create image attributes and set large gamma.ImageAttributes imageAttr = new ImageAttributes();imageAttr.SetGamma(0.6f);//调整Gamma值//截取原图,绘制成指定平行四边形e.Graphics.DrawImage(LenaBmp, dstPts, srcRect, GraphicsUnit.Pixel, imageAttr);}

1、绘制缩小后的图像
2、截取原图像绘制到指定点(注意绘制的大小与截取图像的大小不一致问题)
3、截取原图后,换指定大小绘制
4、截取原图后,绘制成平行四边形
在这里插入图片描述

DrawImage的Graphics+DrawImageAbort回调

原型:

public void DrawImage (System.Drawing.Image image, System.Drawing.Rectangle destRect, int srcX, int srcY, int srcWidth, int srcHeight, System.Drawing.GraphicsUnit srcUnit, System.Drawing.Imaging.ImageAttributes imageAttrs, System.Drawing.Graphics.DrawImageAbort callback, IntPtr callbackData);

作用:指定绘制目标矩形,源图像矩形,图像属性(可为Null),绘制回调函数,回调参数。
该方法支持中途取消绘制图像(如超出绘制区域,可不绘制)。

//是否要中途取消绘制
private bool canCancel = false;
[System.ComponentModel.Description("Graphics的DrawImage方法DrawImageAbort")]
public void Demo10_08(PaintEventArgs e)
{if (LenaBmp == null){LenaBmp = new Bitmap("lena.jpg");}var sw = Stopwatch.StartNew();canCancel = !canCancel;//如果canCancel为false,则绘制501次,否则,只绘制最后一次for (int index= 500;index>=0;index--){// 定义回调函数Graphics.DrawImageAbort callback = new Graphics.DrawImageAbort(DrawImageCallback);// 创建回调数据结构var callbackData = new CallbackData { Index = index,Cancel = canCancel};IntPtr callbackDataPtr = Marshal.AllocHGlobal(Marshal.SizeOf(callbackData));// 将结构复制到非托管内存Marshal.StructureToPtr(callbackData, callbackDataPtr, false);try{// 绘制图像,使用回调函数和回调参数e.Graphics.DrawImage(LenaBmp, new Rectangle(10, 50, LenaBmp.Width, LenaBmp.Height), 0, 0, LenaBmp.Width, LenaBmp.Height, GraphicsUnit.Pixel, null, callback, callbackDataPtr);}catch { }finally{//gcHandle.Free(); // 释放 GCHandle// 释放非托管内存Marshal.FreeHGlobal(callbackDataPtr);}}sw.Stop();e.Graphics.DrawString($"是否取消:{canCancel},耗时:{sw.ElapsedMilliseconds}ms", Font, Brushes.Red, new PointF(20, 20)); 
}
// 回调函数定义
private bool DrawImageCallback(IntPtr callbackDataPtr)
{var callbackData = Marshal.PtrToStructure(callbackDataPtr, typeof(CallbackData)) as CallbackData;if (callbackData == null) return false;//继续绘制if (callbackData.Index != 0){return callbackData.Cancel;//取消绘制}return false;
}// 定义回调数据结构
[StructLayout(LayoutKind.Sequential)]
public class CallbackData
{public int Index;public bool Cancel=true;
}

模拟中途取消与不取消绘制时的耗时差异。
DrawImageAbort

ExcludeClip排除裁切区域

原型:

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

作用:定义一个区域不属于裁切区域

//创建一个矩形区域
Rectangle excludeRect = new Rectangle(100, 100, 200, 200);// 创建一个裁切排除区域
Region excludeRegion = new Region(excludeRect);// 设置排除区域
e.Graphics.ExcludeClip(excludeRegion);// 填充一个大矩形,以观察排除区域
e.Graphics.FillRectangle(new SolidBrush(Color.Blue), 0, 0, 350, 350);

定义排除区域,再填充一个大矩形,以观察效果。
ExcludeClip

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/22723.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

初识 peerDependencies

目录 初步认识 peerDependencies semver 介绍 # 摘要 # 简介 # 语义化版本控制规范&#xff08;SemVer&#xff09; # 合法语义化版本的巴科斯范式语法 # 为什么要使用语义化的版本控制&#xff1f; # FAQ 示例讲解&#xff1a;vue-router 插件 # 说明 声明 验证 初…

在Windows11系统上搭建SFTP服务器

利用OpenSSH搭建SFTP服务器 下载安装部署OpenSSH创建一个测试账户测试链接为SFTP用户配置根目录下载安装部署OpenSSH 参考链接 部署完启动服务要使用管理员模式。 net start sshd创建一个测试账户 使用PC的微软账户是访问不了SFTP的。 需要使用被微软账户覆盖掉的系统账户和…

微信自定义小程序源码系统 众多组件随心搭 各行各业都适用的小程序 带完整的安装代码包以及搭建教程

系统概述 微信自定义小程序源码系统是一款基于微信官方开发框架进行深度定制的源码系统。该系统整合了众多优质组件&#xff0c;通过可视化的拖拽式操作&#xff0c;让开发者无需编写复杂的代码&#xff0c;即可快速搭建出符合自己需求的小程序。同时&#xff0c;该系统支持多…

iTerm2 携手 OpenAI,带来命令行的自然语言革新

在技术不断进步的今天&#xff0c;命令行工具的智能化已成为提升效率的关键。iTerm2&#xff0c;macOS 系统上广受欢迎的开源终端工具&#xff0c;通过最新版本 v3.5 的发布&#xff0c;实现了与 OpenAI 的集成&#xff0c;引领了这一变革。 iTerm2 简介 iTerm2 是一款功能强…

qcom 平台系统签名流程

security boot 平台的东东&#xff0c;oem 可定制的功能有限&#xff0c;只能参考平台文档&#xff0c;可以在高通的网站上搜索&#xff1a;Secure Boot Enablement&#xff0c;然后找对应平台的文档xxx-Secure Boot Enablement User Guide, step by step 操作即可 开机校验流…

CodeBlocks官方主题颜色更换及方法

文章目录 一、前言二 、用工具导入配置文件2.1 运行 cb_share_config.exe文件2.2 替换文件2.3 设置主题 三、配置主题3.1 步骤13.2 步骤23.3 步骤3 四、设置光标4.1 配置字体4.2 展示 行号 五、设置左边行号区域部分六、设置完后的效果七、下载地址 一、前言 Codeblocks 默认的…

【Python系列】Python装饰器

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…

【数据结构】图论中求最短路径——迪杰斯特拉算法(Dijkstra)、弗洛伊德算法(Floyd)

目录 最短路径 (*)迪杰斯特拉算法&#xff08;Dijkstra&#xff09;迪杰斯特拉算法&#xff08;Dijkstra&#xff09;的算法原理&#xff1a; 弗洛伊德算法&#xff08;Floyd&#xff09;弗洛伊德算法&#xff08;Floyd&#xff09;的算法原理&#xff1a;弗洛伊德算法的&#…

哪种价格行为指标对投资者有用?AnzoCapital昂首资本总结6个特征

各位投资者都知道价格行为指标对于交易极具助益&#xff0c;无论是初学者还是专业交易员都能运用。构建外汇交易系统时&#xff0c;这类指标堪称核心且必不可少的工具。 但不是所有的价格行为指标都对投资者有用的&#xff0c;哪种价格行为指标才是对投资者有用的&#xff0c;都…

CogVLM2多模态开源大模型部署与使用

CogVLM2多模态开源大模型部署与使用 项目简介 CogVLM2 是由清华大学团队发布的新一代开源模型系列。2024年5月24日&#xff0c;发布了Int4版本模型&#xff0c;只需16GB显存即可进行推理。2024年5月20日&#xff0c;发布了基于llama3-8b的CogVLM2&#xff0c;性能与GPT-4V相当…

论文AI率过高?掌握这四种技巧轻松降重

随着人工智能技术的突飞猛进&#xff0c;AI生成内容&#xff08;AIGC&#xff09;已被广泛用于学术论文撰写中&#xff0c;提高效率同时也带来了原创性的挑战。面对日益严格的学术审查&#xff0c;一个突出的问题是&#xff1a;使用AI代写的论文能否通过内容检测&#xff1f;因…

Linux 搭建 ZeroTier 的 Moon 服务器

系统&#xff1a;centos 7.6 轻量云服务器&#xff1a;腾讯云 Moon是什么&#xff0c;为什么需要Moon&#xff1f; ZeroTier通过自己的多个根服务器帮助我们建立虚拟的局域网&#xff0c;让虚拟局域网内的各台设备可以打洞直连。这些根服务器的功能有些类似于通过域名查询找到…

SpringCloud Hystrix服务熔断实例总结

SpringCloud Hystrix断路器-服务熔断与降级和HystrixDashboard SpringCloud Hystrix服务降级实例总结 【1】服务熔断 熔断机制概述 熔断机制是应对雪崩效应的一种微服务链路保护机制。当扇出链路的某个微服务出错不可用或者响应时间太长时&#xff0c;会进行服务的降级&…

WWDC 2024前瞻:苹果如何用AI技术重塑iOS 18和Siri

苹果下周的全球开发者大会有望成为这家 iPhone 制造商历史上的关键时刻。在 WWDC 上&#xff0c;这家库比蒂诺科技巨头将展示如何选择将人工智能技术集成到其设备和软件中&#xff0c;包括通过与 OpenAI 的历史性合作伙伴关系。随着重大事件的临近&#xff0c;有关 iOS 18 及其…

AI大模型时代必须关注的数据库 DuckDB1.0 正式发布

开源数据库DuckDB1.0 经过内部6年的打磨&#xff0c;积累了30万行代码&#xff0c;1.8万star&#xff0c;2024.06.03号正式发布了1.0版本&#xff08;代号 Snow Duck&#xff09;。 我们新一代程序员&#xff0c;没能见证MySQL 1.0、PostgreSQL 1.0、Windows 1.0、Linux 1.0、…

flinksql 回撤流中主键发生变更的影响(group by中的值发生改变)

flinksql 回撤流中,主键发生变更的影响 1 什么是回撤流2 主键变更场景2.2 实践发生3 实践中发现的比较好的的实时数仓架构1 什么是回撤流 这篇文章主要谈论一个场景,简单来说: 首先我们来简单的说一下什么是回撤流,以及回撤流的底层原理,举个例子: 这个说的不是很清晰…

【吊打面试官系列】MySQL 中有哪几种锁?

大家好&#xff0c;我是锋哥。今天分享关于 【MySQL 中有哪几种锁&#xff1f;】面试题&#xff0c;希望对大家有帮助&#xff1b; MySQL 中有哪几种锁&#xff1f; 1、表级锁&#xff1a;开销小&#xff0c;加锁快&#xff1b;不会出现死锁&#xff1b;锁定粒度大&#xff0c;…

TypeScript学习(一):开发环境搭建

官方文档搭建参考 https://learn.microsoft.com/zh-cn/training/modules/typescript-get-started/ 1.下载node.js https://nodejs.org/en/download 2.下载vscode https://code.visualstudio.com/ 3.在线ts的测试工具 https://www.typescriptlang.org/play/ 4.下载typescr…

H5即时通讯群聊源码无限建群创群/H5聊天系统聊天网站源码/H5语音聊天系统

源码介绍 支持自助建群 管理群 修改群资料支持自动登录 登陆成功可自助修改资料后台可查看群组聊天消息记录支持表情 动态表情 图片发布支持消息语音提醒

docker-compose教程

1. docker-compose是什么&#xff1f; 1. 1 简介 compose、machine 和 swarm 是docker 原生提供的三大编排工具。 简称docker三剑客。Compose 项目是 Docker 官方的开源项目&#xff0c;定义和运行多个 Docker 容器的应用&#xff08;Defining and running multi-container Do…