内容有效性
- 简介
- 1。透明度(alpha通道)
- 2。argb颜色表示
- 三。终端中的对象呈现方案
3.1。背景图3.2。前景图3.3.重画前景图 - 4。混合颜色结果颜色
4.1。颜色处理方法枚举颜色格式 - 5。透明度效果
5.1。创建“错觉.mq5”脚本 - 总结
简介
在MetaTrader 5中绘图很简单,您只需要知道一些细节。一个细节是终端屏幕的设计。准确地说,我们对图形在屏幕上的输出方式感兴趣。例如,图表可以显示在前景或背景中。屏幕上的颜色输出取决于显示的图表。某些图表对象可能在重叠或相交区域中更改颜色。
在直接使用ccanvas类绘制之前,我们先分析一下与颜色相关的定义。例如,让我们了解alpha通道的含义。
在我看来,透明度是使图像看起来生动的最重要的技术。例如,通过使用平滑的颜色过渡和阴影,透明度可以使图像看起来更有吸引力。阴影增加图形对象的尺寸,并在视觉上软化对象的边缘。
1。透明度(alpha通道)
我们生活在一个三维的世界里,从三维的角度来看待周围的一切。我们习惯于看到和感受三维空间。在三维世界中,我们可以理解哪个物体离我们更近。
有些物体可能是半透明的。例如,将装满半透明液体的干净玻璃置于蓝色背景中。透过杯子里的液体可以看到蓝色的背景。背景的可见性取决于液体的透明度。
数字。1空间维度的一般知识
在本例中,透明度不是虚拟的或虚幻的。在这个例子中,透明度是显而易见的。
当图像显示在计算机显示器上时,这是另一回事——像素矩阵是二维的。例如,图像由高度和宽度矩阵显示,但没有三维深度元素。然而,不可能将一个像素置于另一个像素之上,就像不可能将黄色背景像素置于半透明玻璃像素之下一样。屏幕上的任何三维图像和真实物体都是虚幻的,它们是通过颜色和阴影来实现的。
让我们来看一个可以分为两层的图像示例:底部的蓝色背景和顶部的不透明液体。这就是它在屏幕上的样子:
图2。不透明玻璃
最终结果图表上的玻璃完全不透明。为了提高透明度,我们需要使用argb颜色来表示图像上的所有颜色。
2。argb颜色表示
我没有忘记玻璃的透明度。第二部分将详细讨论这个问题。
argb颜色由四个字节的uint表示,代表alpha通道,红色、绿色和蓝色。也就是说,为了向RGB格式添加透明度,还添加了一个字节alpha channel value来表示透明度。
图3。精氨酸
alpha通道值的百分比从0(前景像素的颜色不改变背景颜色的显示)到255(背景像素的颜色完全取代前景像素的颜色)透明度计算如下:
换句话说,alpha通道值越小,透明度越高。如果我们知道目标透明度,α值可以计算如下:
函数color to argb(color,alpha)用于将颜色转换为argb格式。
三。绘制对象的方法
为了更好地理解颜色是如何处理的。让我们研究以下两种设置图形对象的方案:背景和前景。
3.1。背景地图
此选项可以通过右键单击图表,然后从下拉菜单中选择“属性”并转到“常用”选项卡来完成。
图4。背景地图
由终端中的四层组成的图形窗口。可以在两个图层上绘制(背景和前景):
数字。5。图表窗口样式
在前景和背景中,根据创建时间,一个图形对象和另一个图形对象相互重叠。
也就是说,最早创建的对象在底部,即“背景”,最后创建的对象在顶部,即“前景”。后面的对象出现在上层。
数字。6。对象的位置取决于创建时间
并非所有对象都可以完全重叠,而无需重新绘制与其他图形重叠的区域。
下表总结了图形对象的特征,并解释了重绘对象的重叠区域。
身份证件 | 对象 | 描述 | 与底层对象重叠 |
---|---|---|---|
 ;对象 |  ;垂直线 | &不重绘 | |
 ;对象线 |  ;水平线 | 不重漆 | |
&对象趋势 | nbsp; | &趋势线 | 不重漆 |
 ;obj_趋势角度 | nbsp; | &带角度的趋势线 | 不重漆 |
 ;obj_周期 | nbsp; |  ;周期线 | 不重漆 |
 ;对象箭头线 | nbsp; |  ;箭头线 | 不重漆 |
 ;obj_频道 | nbsp; | &等距通道 | 不重漆 |
 ;obj_stdevchannel | nbsp; | &标准偏差通道 | &不重绘 |
&obj_回归 | nbsp; | &线性回归通道 | 不重漆 |
&目标干草叉 | nbsp; | &安德鲁分叉 | 不重漆 |
 ;obj ou甘宁线 | nbsp; | &加恩线 | 不重漆 |
&奥布加恩凡 | nbsp; | &江恩·范 | 不重漆 |
&奥布加尼德 | nbsp; |  ;Gann网格 | 不重漆 |
 ;obj_fibo | nbsp; | &斐波那契退出 | 不重漆 |
&obj_纤维 | nbsp;nbsp; | &斐波那契时间间隔 | 不重漆 |
 ;obj_fibofan | nbsp; |  ;斐波那契扇形 | 不重漆 |
 ;obj_纤维板 | &斐波那契弧 | 不重漆 | |
 ;Obj_Fibochannel公司 | nbsp; | &斐波那契信道 | 不重漆 |
&对象扩展 | nbsp; | &斐波那契扩展 | 不重漆 |
 ;对象Elliotwave5 | nbsp; | &艾略特波-5 | 不重漆 |
 ;obj椭圆波3 | nbsp; | &艾略特波-3 | 不重漆 |
 ;obj_矩形 | nbsp; | &矩形。 | 如果未填充,则不需要重新绘制;如果填充,则 ,则重新绘制。 |
 ;obj_三角形 | nbsp; |  ;三角形 | 如果未填充,则不需要重新绘制;如果填充,则 ,则重新绘制。 |
 ;obj_椭圆 | nbsp; | 椭圆 | 如果未填充,则不需要重新绘制;如果填充,则 ,则重新绘制。 |
 ;obj_箭头_拇指朝上 | nbsp; | &向上竖起 | 不重漆 |
 ;obj_箭头_拇指_向下 | nbsp; | &拇指向下 | 不重漆 |
 ;对象箭头向上 | nbsp; |  ;上箭头 | 不重漆 |
 ;对象箭头向下 | nbsp; | &向下排列 | 不重漆 |
 ;obj_箭头_停止 | nbsp; | 停止。 | 不重漆 |
 ;对象箭头检查 | nbsp; |  ;复选标记 | 不重漆 |
 ;obj_箭头_左_价格 | nbsp; |  ;左价格标签 | 不重漆 |
 ;obj_箭头_右_价格 | nbsp; | &正确的价格标签 | 不重漆 |
 ;obj_arrow_购买 | nbsp; | &买入价 | 不重漆 |
 ;obj_arrow_出售 | nbsp; | &销售标志 | 不重漆 |
 ;对象箭头 | nbsp; |  ;箭头对象 | 不重漆 |
 ;对象文本 | nbsp; | & nbsp; text object | 不重漆 |
 ;对象标签 | nbsp; |  ;文本标签对象 | 不重漆 |
 ;obj_按钮 | nbsp; |  ;按钮对象 | 不重漆 |
&对象图 | nbsp; |  ;图表对象 | 不重漆 |
 ;obj_位图 | nbsp; | &位图对象 | 不重漆 |
 ;obj_位图_标签 | nbsp; | &位图标签对象 | 不重漆 |
 ;对象编辑 | nbsp; | &标记对象 | 不重漆 |
 ;obj_事件 | nbsp; | &与经济数据日历事件相对应的事件对象 | 不重漆 |
 ;obj_矩形_标签 | nbsp; | &用于创建和设计自定义图形对象的矩形标签对象 | &不重绘 |
表1图形对象的重叠和透明度
让我们看一下obj_rectangle(rectangle)类型的三个对象,并讨论重新绘制对象重叠区域(文件xor)的算法。MQ5)。
脚本(文件xor.mq5)设置白色背景色(0xffffff),并绘制用蓝色(0x0000 ff)和红色(0xff0000)矩形填充的矩形no1和no2。
图7。重绘。背景地图
我们得到两个重叠区域和颜色变化:
- 区域1-最终的颜色(0x000000000)是完全透明的,所以这里我们看到的是不变的背景和图像。
- 区域2-最终颜色(0x00ff00)。
当图形对象(如矩形)重叠时,将使用逐位或算法重新绘制它们。
图6这两个区域的重绘示例如下所示。
文字表示法 | 塑性表示 | 二进制表示 | 小心 |
---|---|---|---|
C’0,0, 255’ | 0x000 | 0000 0000 0000 0000 1111 1111 | 蓝色 |
异或 | |||
C’0,0225’ | 0x000 | 0000 0000 0000 0000 1111 1111 | 蓝色 |
= | |||
C′0,0,0’ | 0x00万 | 0000 0000 0000 0000 0000 0000 0000 0000万 | 透明透明 |
异或 | |||
C’255、255、255′ | 0xfffffff | 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 | 白色(背景) |
= | |||
C’255、255、255′ | 0xfffffff | 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 | 白色 |
表2。蓝色+蓝色+白色位或
文字表示法 | 塑性表示 | 二进制表示 | 小心 |
---|---|---|---|
C’0,0, 255’ | 0x000 | 0000 0000 0000 0000 1111 1111 | 蓝色 |
异或 | |||
C’255,0, 0’ | 0xFF000 | 1111 1111 0000 0000 0000万 | 红色的 |
= | |||
“255,0255” | 0xFF900F | 1111 1111 0000 1111 1111 1111 1111 1111 | |
异或 | |||
C’255、255、255′ | 0xfffffff | 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 | 白色(背景) |
= | |||
‘0255,0’ | 0x00 FF00 | 0000 0000 1111 1111 10000 0000 0000万 |
表3。蓝色+红色+白色
的位或
3.2。前景图
当“图表前景”参数处于启用状态时,图表窗口的图层组织方式与背景图表不同:
0
图8。图表窗口方案。顶部图
当图表的“前景”参数为“开”时,“前景”和“背景”两个绘图层会聚为一个公共层。该层位于K线和网格线下方。
3.3。重新绘制“顶层地图”
如图所示。7,重叠对象的重绘算法(文件xor。MQ5)。
脚本(文件xor.mq5)设置白色背景色(0xffffff),并绘制用蓝色(0x0000 ff)和红色(0xff0000)矩形填充的1号和2号矩形。
1
图9。重绘。前景图
如果比较图7和图8,我们会发现重叠区域的重绘结果是相同的。
4。混色
如上所述,屏幕上的透明度效果是错觉。颜色操作。To simulate Figure 2, we just need to know how to display a color transparently on the screen. 需要计算该像素的最终颜色。
假设要在白色背景上绘制alpha通道128红色(“黑白”颜色模板的图形背景)。在argb格式中,红色为0x80ff0000。要计算最终颜色,我们需要计算每个通道的颜色(红色、绿色、蓝色)。
下面是一个计算alpha通道效果颜色的公式。标准化后:
2
在这里:
- 结果是颜色通道的强度。如果值大于255,则返回255。
- background是背景颜色通道值。
- 前景是重叠图像的颜色通道值。
- alpha是标准化的alpha值。
根据公式1.3,计算出效果颜色。
阿尔法通道 | 阿尔法通道,标准化 | R | G | 乙 | 小心 |
---|---|---|---|---|---|
二百五十五 | 二百五十五 | 二百五十五 | 白色 | ||
One hundred and twenty-eight | 0,5 | 二百五十五 | 零 | 零 | 红色阿尔法128 |
255*(1-0.5)+255*0.5=255 | 255*(1-0.5)+0*0.5=127 | 255*(1-0.5)+0*0.5=127 |
表4。按公式1.3
计算
屏幕上的最终颜色如下:
3
数字。10。效果色
4.1。颜色处理方法枚举颜色格式
创建画布时,可以指定三种处理颜色的方法之一(枚举颜色格式):
身份证件 | 描述 |
---|---|
颜色格式 | 忽略alpha元素 |
颜色格式 argb 原始 | 颜色组件不由终端处理(应由用户指定) |
颜色格式参数正常化 | 颜色形成由终端处理 |
表5。用于创建画布的颜色处理方法
颜色_格式_a rgb_规格化考虑了正确的RGB组件重叠,并提供了更漂亮的图形。使用alpha通道颜色时,颜色按公式1.3计算。
颜色_格式_a rgb_raw不控制RGB颜色组件的重叠,因此颜色_格式_a rgb_normalize是比颜色_格式_a rgb_raw更快的处理方法。
下面是使用颜色_格式_argb_raw方法计算alpha通道的颜色效果颜色的公式:
4
在这里:
- 结果是颜色通道的强度。如果值大于255,则返回255。
- background是背景颜色通道值。
- 前景是重叠图像的颜色通道值。
- alpha是标准化的alpha值。
5。透明度效果
现在我们可以开始实现透明度。
让我们画一些填充的矩形(脚本“xor”。MQ5“)。为了揭示颜色处理方法的差异,在图表顶部创建了三个不重叠的水平画布。
第一种是用颜色_格式_xrgb_noalpha处理,第二种是用颜色_格式_argb_raw处理,第三种是用颜色_格式_argb_正常化处理。然后我们逐渐将透明度从255(不透明)改为0(完全透明)。把剧本叫做“幻象”。MQ5”。
这段视频展示了剧本“错觉”的表现。MQ5“作品:
5
数字。11。剧本的假象。MQ5作品
5.1。创造“错觉”。MQ5“脚本”
新的或修改过的代码突出显示。
空白脚本模板:
//+------------------------------------------------------------------+ //| Illusion.mq5 | //| Copyright © 2015, Vladimir Karputov | //| https://wmua.ru/slesar/ | //+------------------------------------------------------------------+ #property copyright "Copyright © 2015, Vladimir Karputov" #property link "https://wmua.ru/slesar/" #property version "1.0" //+------------------------------------------------------------------+ //| 脚本程序start函数 | //+------------------------------------------------------------------+ void OnStart() { //--- }
在脚本的开头添加脚本描述、输入参数,并包含用于绘制的画布类。
#property version "1.0" #property description "The illusion of transparency" //--- 加载脚本时显示输入参数窗口 #property script_show_inputs #include <Canvas/Canvas.mqh>
此脚本需要一些参数:图表的高度和宽度、画布的高度和宽度以及绘制画布坐标时的辅助变量:
#include <Canvas/Canvas.mqh> //+------------------------------------------------------------------+ //| inputs | //+------------------------------------------------------------------+ input color colr=clrRed; input color clr_Circle=clrBlue; //--- 图表高度和宽度变量。 int ChartWidth=-1; int ChartHeight=-1; //--- uchar alpha=0; //控制色彩透明度的alpha通道值 int can_width,can_height; //画布的高度和宽度变量。 int can_x1,can_y1,can_x2,can_y2,can_y3,can_x3; //坐标
我们使用标准函数接收图表的宽度和高度:
//+------------------------------------------------------------------+ //| 脚本程序start函数 | //+------------------------------------------------------------------+ void OnStart() { //--- } //+------------------------------------------------------------------+ //| Chart property width | //+------------------------------------------------------------------+ int ChartWidthInPixels(const long chart_ID=0) { //--- 定义获取属性的变量 long result=-1; //--- 重置报错信息 ResetLastError(); //--- 接收属性变量 if(!ChartGetInteger(chart_ID,CHART_WIDTH_IN_PIXELS,0,result)) { //--- 在智能交易日志中显示报错信息 Print(__FUNCTION__+", Error Code = ",GetLastError()); } //--- 返回图表属性值 return((int)result); } //+------------------------------------------------------------------+ //| Chart property height | //+------------------------------------------------------------------+ int ChartHeightInPixelsGet(const long chart_ID=0,const int sub_window=0) { //--- 定义获取属性的变量 long result=-1; //--- 重置报错信息 ResetLastError(); //--- 接收属性变量 if(!ChartGetInteger(chart_ID,CHART_HEIGHT_IN_PIXELS,sub_window,result)) { //--- 在智能交易日志中显示报错信息 Print(__FUNCTION__+", Error Code = ",GetLastError()); } //--- 返回图表属性值 return((int)result); }
直接转到OnStart()。
为了说明图12所示的图形画布层和画布坐标辅助变量:
6
数字。12。图形坐标
让我们找到图表的高度和宽度,并计算画布坐标的辅助变量。
void OnStart() { //--- 图表高度和宽度 ChartWidth=ChartWidthInPixels(); ChartHeight=ChartHeightInPixelsGet()-50; //--- can_width=ChartWidth/3; can_height=ChartHeight; can_x1=0; can_y1=0; can_x2=can_width; can_y2=0; can_x3=can_width*2; can_y3=0; }
在计算了画布的宽度和高度以及坐标辅助变量之后,我们就可以开始绘制了。
接下来,让我们将onStart()函数的void类型更改为int类型,并在第一个画布上绘制填充矩形、画布颜色处理方法的名称文本和填充圆:
int OnStart() { //--- 图表高度和宽度 ChartWidth=ChartWidthInPixels(); ChartHeight=ChartHeightInPixelsGet()-50; //--- can_width=ChartWidth/3; can_height=ChartHeight; can_x1=0; can_y1=0; can_x2=can_width; can_y2=0; can_x3=can_width*2; can_y3=0; //--- 创建画布COLOR_FORMAT_XRGB_NOALPHA CCanvas canvas_XRGB_NOALPHA,canvas_ARGB_RAW,canvas_XARGB_NORMALIZE; if(!canvas_XRGB_NOALPHA.CreateBitmapLabel("canvas_XRGB_NOALPHA",can_x1,can_y1,can_width-1,can_height,COLOR_FORMAT_XRGB_NOALPHA)) { Print("Error creating canvas: ",GetLastError()); return(-1); } canvas_XRGB_NOALPHA.Erase(ColorToARGB(colr,alpha)); canvas_XRGB_NOALPHA.TextOut((can_width)/2,can_height/2,"canvas_XRGB_NOALPHA",ColorToARGB(clrBlue,255),TA_CENTER|TA_VCENTER); canvas_XRGB_NOALPHA.FillCircle((can_width)/2,can_height/2+50,25,ColorToARGB(clr_Circle,255)); canvas_XRGB_NOALPHA.Update(); return(0); }
更多详细信息,请参见Post Text代码部分。
canvas_XRGB_NOALPHA.CreateBitmapLabel("canvas_XRGB_NOALPHA",can_x1,can_y1,can_width-1,can_height,COLOR_FORMAT_XRGB_NOALPHA)
canvas_xrgb_noalpha.createBitMapLabel-为图表对象创建图形资源。
画布的第一种颜色处理方法是忽略color_format_xrgb_noalpha-alpha元素。
canvas_XRGB_NOALPHA.Erase(ColorToARGB(colr,alpha));
用阿尔法透明元素填充整个画布的argb颜色。
画布的填充忽略alpha通道,因为颜色格式用于处理颜色。
canvas_XRGB_NOALPHA.TextOut((can_width)/2,can_height/2,"canvas_XRGB_NOALPHA",ColorToARGB(clrBlue,255),TA_CENTER|TA_VCENTER);
文本输出-画布的图像处理类型。文本的颜色为argb格式,alpha通道值为255,这意味着文本的颜色是完全不透明的。
将显示相对于矩形的文本级别(Ta_Center)和中心垂直(Ta_vCenter)。
canvas_XRGB_NOALPHA.FillCircle((can_width)/2,can_height/2+50,25,ColorToARGB(clr_Circle,255));
绘制实心圆。我们将用填充画布(canvas_xrgb_noalpha.erase)(colortoargb(colr,alpha))的颜色绘制它。
用于显示在画布上绘制的形状(或区域/点)完全覆盖底层图像。也就是说,这里没有重绘,因为最后一个图形完全覆盖了底部区域。
canvas_XRGB_NOALPHA.Update();
我们需要刷新屏幕以便在屏幕上显示所有绘制的对象。
其他两张画布的绘制类似:颜色为“颜色格式”的画布“原始显示模式”和“颜色格式”的画布“正常化显示模式:
canvas_XRGB_NOALPHA.Update(); //--- 创建画布 COLOR_FORMAT_ARGB_RAW if(!canvas_ARGB_RAW.CreateBitmapLabel("canvas_ARGB_RAW",can_x2,can_y2,can_width-1,can_height,COLOR_FORMAT_ARGB_RAW)) { Print("Error creating canvas: ",GetLastError()); return(-1); } canvas_ARGB_RAW.Erase(ColorToARGB(colr,alpha)); //clrNONE,0)); canvas_ARGB_RAW.TextOut((can_width)/2,can_height/2,"canvas_ARGB_RAW",ColorToARGB(clrBlue,255),TA_CENTER|TA_VCENTER); canvas_ARGB_RAW.FillCircle((can_width)/2,can_height/2+50,25,ColorToARGB(clr_Circle,255)); canvas_ARGB_RAW.Update(); //--- 创建画布 COLOR_FORMAT_ARGB_NORMALIZE if(!canvas_XARGB_NORMALIZE.CreateBitmapLabel("canvas_XARGB_NORMALIZE",can_x3,can_y3,can_width-1,can_height,COLOR_FORMAT_ARGB_NORMALIZE)) { Print("Error creating canvas: ",GetLastError()); return(-1); } canvas_XARGB_NORMALIZE.Erase(ColorToARGB(colr,alpha)); canvas_XARGB_NORMALIZE.TextOut((can_width)/2,can_height/2,"canvas_XARGB_NORMALIZE",ColorToARGB(clrBlue,255),TA_CENTER|TA_VCENTER); canvas_XARGB_NORMALIZE.FillCircle((can_width)/2,can_height/2+50,25,ColorToARGB(clr_Circle,255)); canvas_XARGB_NORMALIZE.Update(); return(0); }
绘制画布和图形对象。
现在,让我们添加一个循环来更改整个画布的透明度:
canvas_XARGB_NORMALIZE.FillCircle((can_width)/2,can_height/2+50,25,ColorToARGB(clr_Circle,255)); canvas_XARGB_NORMALIZE.Update(); //--- 透明度从255到0 uchar transparent; for(transparent=255;transparent>0;transparent--) { canvas_XRGB_NOALPHA.TransparentLevelSet(transparent); canvas_XRGB_NOALPHA.Update(); canvas_ARGB_RAW.TransparentLevelSet(transparent); canvas_ARGB_RAW.Update(); canvas_XARGB_NORMALIZE.TransparentLevelSet(transparent); canvas_XARGB_NORMALIZE.Update(); Sleep(50); } canvas_XRGB_NOALPHA.TransparentLevelSet(transparent); canvas_XRGB_NOALPHA.Update(); canvas_ARGB_RAW.TransparentLevelSet(transparent); canvas_ARGB_RAW.Update(); canvas_XARGB_NORMALIZE.TransparentLevelSet(transparent); canvas_XARGB_NORMALIZE.Update(); Sleep(6000); return(0); }
使用此代码行更改所有画布的透明度:
.TransparentLevelSet(transparent)
在绘图结束时,我们需要清理,例如删除图形资源。
因为我们已经为图表对象创建了图形资源(使用方法createBitMapLabel),所以让我们在删除图表对象(位图标签)时使用destroy()方法删除它们:
canvas_XARGB_NORMALIZE.Update(); Sleep(6000); //--- 完成 canvas_XRGB_NOALPHA.Destroy(); canvas_ARGB_RAW.Destroy(); canvas_XARGB_NORMALIZE.Destroy(); return(0); }
平滑更改图像透明度的脚本可以正常运行。
如果在白色背景下运行此脚本,然后在黑色背景下运行,则可以更好地发现颜色格式与坐标格式的正常化模式之间的区别。
总结
本文介绍了色彩处理的基本概念。学习了如何在图表窗口中绘制图形。本文还讨论了标准类库中CCANVAS类的基本方法和argb格式中颜色的透明性。
这只是基础。在MetaTrader 5终端中,仍然有许多创建各种图形效果的可能性。本文讨论透明度:部分透明度实际上使图形对象的边缘看起来更具吸引力。由于显示器的二维特性,图表的透明度实际上是像素处理的错觉。
本文由MetaQuotes Software Corp.翻译自俄语原文
,网址为https://www.mql5.com/ru/articles/1341。
MyFxtop迈投(www.myfxtop.com)-靠谱的外汇跟单社区,免费跟随高手做交易!
免责声明:本文系转载自网络,如有侵犯,请联系我们立即删除,另:本文仅代表作者个人观点,与迈投财经(www.myfxtop.cn)无关。其原创性以及文中陈述文字和内容未经本站证实,对本文以及其中全部或者部分内容、文字的真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
著作权归作者所有。
商业转载请联系作者获得授权,非商业转载请注明出处。