【学习笔记】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*96
            e.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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

NSSCTF中的popchains、level-up、 What is Web、 Interesting_http、 BabyUpload

目录 [NISACTF 2022]popchains [NISACTF 2022]level-up [HNCTF 2022 Week1]What is Web [HNCTF 2022 Week1]Interesting_http [GXYCTF 2019]BabyUpload 今日总结&#xff1a; [NISACTF 2022]popchains 审计可以构造pop链的代码 <php class Road_is_Long{public $…

桑基图Cannot set properties of undefined (setting ‘dataIndex‘)

前端写桑基图的时候碰到以上bug 原因是&#xff1a; 桑基图中的name值有重复的&#xff0c;把重复的name值去掉就好了&#xff0c;或者如果name排查太麻烦&#xff0c;可以用唯一id作为name,增加些字段&#xff0c;展示时用fomatter的方式 参照https://www.cnblogs.com/lempe…

详解FedAvg:联邦学习的开山之作

FedAvg&#xff1a;2017年 开山之作 论文地址&#xff1a;https://proceedings.mlr.press/v54/mcmahan17a/mcmahan17a.pdf 源码地址&#xff1a;https://github.com/shaoxiongji/federated-learning 针对的问题&#xff1a;移动设备中有大量的数据&#xff0c;但显然我们不能收…

GPT-4o仅排第二!北大港大等6所高校联手,发布权威多模态大模型榜单!

多模态大模型视频分析能力榜单出炉&#xff1a; Gemini 1.5 Pro最强&#xff0c;GPT-4o仅排第二&#xff1f; 曾经红极一时的GPT-4V屈居第三。 3.5研究测试&#xff1a;hujiaoai.cn 4研究测试&#xff1a;askmanyai.cn Claude-3研究测试&#xff1a;hiclaude3.com 最近&#…

python代码中参数的默认值

python中的函数&#xff0c;可以给形参指定默认值。 带有默认值的参数&#xff0c;可以在调用的时候不传参。 如上图所示&#xff0c;在给函数设定形参的时候可以给函数形参设定默认值&#xff0c;当然默认参数的形参应该在非默认形参的后面。 如果在调用函数的时候&#xff…

【机器学习】因TensorFlow所适配的numpy版本不适配,用anaconda降低numpy的版本

目录 0 TensorFlow最高支持的numpy版本 1 激活你的环境&#xff08;如果你正在使用特定的环境&#xff09; 2 查找可用的NumPy版本 3 安装特定版本的NumPy 4. 验证安装 5.&#xff08;可选&#xff09;如果你更改了base环境 0 TensorFlow最高支持的numpy版本 要使用 …

测试基础11:测试用例设计方法-等价类划分

课程大纲 1、概述 1.1测试用例设计方法意义 穷举测试&#xff1a;每种输入都测一次。最完备&#xff0c;但不现实。 使用设计方法&#xff0c;用最少的数据&#xff08;成本&#xff09;&#xff0c;实现最大的测试覆盖。 1.2常用设计方法 ①等价类划分 ②边界值分析 ③错误推…

SpringBoot+Vue网上购物商城系统(前后端分离)

技术栈 JavaSpringBootMavenMySQLMyBatisVueShiroElement-UI 系统角色对应功能 用户商家管理员 系统功能截图

【安装笔记-20240608-Linux-免费空间之三维主机免费空间】

安装笔记-系列文章目录 安装笔记-20240608-Linux-免费空间之三维主机免费空间 文章目录 安装笔记-系列文章目录安装笔记-20240608-Linux-免费空间之三维主机免费空间 前言一、软件介绍名称&#xff1a;三维主机免费空间主页官方介绍 二、安装步骤测试版本&#xff1a;openwrt-…

ROS学习记录:栅格地图格式

一、机器人导航所使用的地图数据&#xff0c;就是ROS导航软件包里的map_server节点在话题 /map 中发布的消息数据&#xff0c;消息类型是nav_msgs消息包中的OccupancyGrid&#xff0c;它的中文意思的占据栅格&#xff0c;是一种正方形小格子组成的地图。 二、对障碍物进行俯视&…

基于STM32智能小车

一、前置准备 前置知识&#xff1a;需要学习stm32&#xff0c;建议去b站看江科大的视频&#xff0c;讲的很详细&#xff0c;学完串口那一块就可以制作了&#xff0c;软件用的是Keil5&#xff0c;开发语言C语言&#xff0c;手机连接蓝牙模块软件是蓝牙调试器。 需要准备的器件…

const详解

关键字const用来定义常量&#xff0c;如果一个变量被const修饰&#xff0c;那么它的值就不能再被改变。 但是&#xff0c;可以通过取地址进行修改。 将const 在指针前进行修饰&#xff0c;那么就修饰指针所指向的变量。 但是指针变量可以被修改。 将const 在指针后进行修饰&am…

轻松连接远程服务器SecureCRT for Mac/Windows

SecureCRT是一款功能强大的终端仿真器和文件传输工具&#xff0c;专为网络管理员、开发人员和系统工程师设计。它支持SSH、Telnet、RDP和串口等多种协议&#xff0c;提供安全、高效的远程访问和管理体验。SecureCRT具有多窗口/多标签管理、自定义终端仿真、颜色方案优化等高级功…

30-unittest生成测试报告(HTMLTestRunner插件)

批量执行完测试用例后&#xff0c;为了更好的展示测试报告&#xff0c;最好是生成HTML格式的。本文使用第三方HTMLTestRunner插件生成测试报告。 一、导入HTMLTestRunner模块 这个模块下载不能通过pip安装&#xff0c;只能下载后手动导入&#xff0c;下载地址是&#xff1a;ht…

DOM型xss靶场实验

DOM型xss可以使用js去控制标签中的内容。 我使用的是一个在线的dom型xss平台&#xff0c;靶场链接&#xff1a;Challenges 第一关Ma Spaghet!&#xff1a; Ma Spaghet! 关卡 <h2 id"spaghet"></h2> <script>spaghet.innerHTML (new URL(locatio…

数字校园的优势有哪些

数字化时代下&#xff0c;数字校园已成为教育领域一股显著趋势。数字校园旨在借助信息技术工具对传统校园进行改造&#xff0c;提供全新的教学、管理和服务方式。那么&#xff0c;数字校园究竟具备何种优势&#xff1f;现从三个方面为您详细介绍。 首先&#xff0c;数字校园为教…

【NI国产替代】产线测试:数字万用表(DMM),功率分析仪,支持定制

数字万用表&#xff08;DMM&#xff09; • 6 位数字表显示 • 24 位分辨率 • 5S/s-250KS/s 采样率 • 电源和数字 I/O 均采用隔离抗噪技术 • 电压、电流、电阻、电感、电容的高精度测量 • 二极管/三极管测试 功率分析仪 0.8V-14V 的可调输出电压&#xff0c;最大连…

鸿业的【管立得】设计的地下管线BIM模型如何导入到图新地球

0序&#xff1a; 在城乡建设行业&#xff0c;不论是园区的建设还是整个区划的智慧城市应用&#xff0c;地下管线都是很重要的组成元素。地下管线的直接测绘成果是管点表、管线表&#xff0c;存档及交付的成果多数是CAD文件&#xff0c;在智慧城市、市政工程、三维GIS信息化平台…

linux系统——ping命令

ping命令可以用来判断对远端ip的连通性&#xff0c;可以加域名也可以加公共ip地址 这里发送出56字节&#xff0c;返回64字节

How to: Add and Customize the Ribbon Skin List and Skin Gallery

皮肤列表和皮肤库允许用户选择皮肤。本文介绍如何在功能区中显示“皮肤列表”或“皮肤库”并对其进行自定义。 DevExpress演示中心中的大多数应用程序都允许您选择皮肤。例如&#xff0c;运行XtraGrid演示并导航到皮肤功能区页面以更改当前皮肤。 在功能区UI中显示皮肤列表或…