动态资源创建:ResourceCreate
#resource 指令在编译阶段就将资源嵌入程序,因此可以称为静态资源。然而,在程序执行阶段经常需要生成资源(创建全新资源或修改现有资源)。为此,MQL5 提供了 ResourceCreate 函数。借助该函数创建的资源称为动态资源。
该函数有两种形式:第一种允许从文件中加载图片和声音,第二种用于根据内存中准备好的像素数组创建位图图像。
bool ResourceCreate(const string resource, const string filepath)
该函数从位于 filepath 的文件中加载名为 resource 的资源。如果路径以反斜杠 '\' 开头(在常量字符串中应是两个:"\\path\\name.ext"),那么将在该路径下相对于终端数据目录下的 MQL5 文件夹搜索文件(例如,"\\Files \\CustomSounds\\Hello.wav" 指的是 MQL5/Files/CustomSounds/Hello.wav)。如果没有反斜杠,则从我们调用函数的可执行文件所在的文件夹开始搜索资源。
路径可以指向硬连接到第三方或当前 MQL 程序中的静态资源。例如,某个脚本可以根据 BmpOwner.mq5 指标(在关于 资源变量的一节中讨论)中的图片创建资源。
ResourceCreate("::MyImage", "\\Indicators\\MQL5Book\\p7\\BmpOwner.ex5::search1.bmp"); |
resource 参数中的资源名称可以包含首部的双冒号(但这并不是必需的,因为如果没有双冒号,名称中将自动添加 "::" 前缀)。这确保了在 ResourceCreate 调用中声明资源和后续访问资源(例如,在设置 OBJPROP_BMPFILE 属性时)时统一使用一行。
当然,如果我们只是想在图表上将第三方图像资源加载到我们的对象中,那么上述创建动态资源的语句就是多余的,因为直接将字符串 "\\Indicators\\MQL5Book\\p7\\BmpOwner.ex5:" 赋值给 OBJPROP_BMPFILE 属性 search1.bmp 就足够了。但是,如果需要编辑图像,动态资源是必不可少的。接下来,我们将在 读取和修改资源数据一节中展示一个示例。
其他 MQL 程序可以通过动态资源的全名(包括创建资源的程序的路径和名称)公开获取动态资源。例如,如果之前的 ResourceCreate 调用是由脚本 MQL5/Scripts/MyExample.ex5 生成的,那么另一个 MQL 程序就可以使用全链接 "\\Scripts\\MyExample.ex5::MyImage" 访问相同的资源,而同一文件夹中的任何其他脚本都可以访问简写 "MyExample.ex5::MyImage"(这里的相对路径只是退化)。上文给出了完整路径(从 MQL5 根目录文件夹)和相对路径的编写规则。
ResourceCreate 函数执行后会返回成功 (true) 或错误 (false) 的布尔指标。与往常一样,错误代码可以在 _LastError 变量中找到。具体来说,你可能会收到以下错误:
- ERR_RESOURCE_NAME_DUPLICATED (4015) 动态资源和静态资源的名称不匹配
- ERR_RESOURCE_NOT_FOUND (4016) 未找到 filepath 参数中的指定资源/文件
- ERR_RESOURCE_UNSUPPOTED_TYPE (4017) 不支持的资源类型或大小超过 2 GB
- ERR_RESOURCE_NAME_IS_TOO_LONG (4018) 资源名称超过 63 个字符
所有这些不仅适用于函数的第一种形式,也适用于第二种形式。
bool ResourceCreate(const string resource, const uint &data[], uint img_width, uint img_height, uint data_xoffset, uint data_yoffset, uint data_width, ENUM_COLOR_FORMAT color_format)
resource 参数仍表示新资源的名称,图像内容由其余参数给出。
data 数组可以是一维数组 (data[]) 或二维数组 (data[][]):传递栅格的点(像素)。参数 img_width 和 img_height 设置所显示图像的尺寸(以像素为单位)。这些尺寸可能小于 data 数组中图像的物理尺寸,因此当只输出原始图像的一部分时,就能达到取景的效果。data_xoffset 和 data_yoffset 参数决定了“帧”左上角的坐标。
data_width 参数表示原始图像的全宽(在 data 数组中)。值为 0 意味着该宽度与 img_width 相同。只有在 data 参数中指定一维数组时,data_width 参数才有意义,因为二维数组的两个维度都是已知的(在这种情况下,data_width 参数将被忽略,并被假定等于 data[][] 数组的第二个维度)。
在最常见的情况下,如果要完整显示图像(“按原样”),请使用以下语法:
ResourceCreate(name, data, width, height, 0, 0, 0, ...); |
例如,如果程序有一个描述为一个二维 bitmap 数组的静态资源:
#resource "static.bmp" as bitmap data[][] |
那么在此基础上创建动态资源的方法如下:
ResourceCreate("dynamic", data, ArrayRange(data, 1), ArrayRange(data, 0), 0, 0, 0, ...); |
在静态资源的基础上创建动态资源不仅是为了直接编辑,还可以在显示资源时控制颜色的处理方式。可以使用函数的最后一个参数来选择这种模式:color_format。它使用 ENUM_COLOR_FORMAT 枚举。
标识符 |
说明 |
---|---|
COLOR_FORMAT_XRGB_NOALPHA |
忽略 alpha 通道分量(透明度) |
COLOR_FORMAT_ARGB_RAW |
终端不处理颜色分量 |
COLOR_FORMAT_ARGB_NORMALIZE |
终端会处理颜色分量(参见下文) |
在 COLOR_FORMAT_XRGB_NOALPHA 模式下,图像显示时不带效果:每个点以纯色显示(这是最快的绘制方式)。其他两种模式在显示像素时会考虑每个像素高字节的透明度,但效果不同。对于 COLOR_FORMAT_ARGB_NORMALIZE,终端在调用 ResourceCreate 时准备光栅时,会对每个点的颜色分量进行以下转换:
R = R * A / 255
|
#resource 指令中的静态图像资源借助 COLOR_FORMAT_ARGB_NORMALIZE 进行连接。
在动态资源中,数组大小受 INT_MAX 字节值(2147483647,2 Gb)的限制,这大大超出了编译器在处理静态指令 #resource 时施加的限制:文件大小不能超过 128 Mb。
如果调用第二个版本的函数来创建名称相同的资源,但更改了其他参数(像素数组的内容、宽度、高度或偏移量),则不会重新创建新资源,而只是更新现有资源。只有拥有资源的程序(最初创建资源的程序)才能以这种方式修改资源。
如果在不同图表上运行的不同程序副本中创建动态资源时,每个副本中都需要自己的资源,则应在资源名称中添加 ChartID。
为了演示动态创建各种配色方案的图像,我们建议拆解脚本 ARGBbitmap.mq5。
图像 "argb.bmp" 被静态附加到该脚本中。
#resource "argb.bmp" as bitmap Data[][] |
用户通过 ColorFormat 参数选择颜色格式化方法。
input ENUM_COLOR_FORMAT ColorFormat = COLOR_FORMAT_XRGB_NOALPHA; |
显示图像的对象名称和动态资源名称由变量 BitmapObject 和 ResName 描述。
const string BitmapObject = "BitmapObject";
|
下面介绍该脚本的主要功能。
void OnStart()
|
该脚本在指定的颜色模式下创建一个新资源,并将其分配给 OBJ_BITMAP_LABEL 类型对象的 OBJPROP_BMPFILE 属性。接下来,脚本等待用户明确停止脚本或按 Esc,然后(通过调用 ObjectDelete)删除对象,并使用 ResourceFree 函数删除资源。请注意,删除对象不会自动删除资源。这就是为什么我们需要 ResourceFree 函数,我们将在 下一节中讨论。
如果我们不调用 ResourceFree,那么即使在 MQL 程序终止后,动态资源仍会保留在终端的内存中,直到终端关闭为止。这使得可以将它们用作存储库或 MQL 程序之间交换信息的一种方式。
使用 ResourceCreate 的第二种形式创建的动态资源不必携带图像。如果我们不将其用于渲染,data 数组可以包含任意数据。在这种情况下,设置 COLOR_FORMAT_XRGB_NOALPHA 色彩格式非常重要。我们将在某个时候展示这样一个例子。
与此同时,我们检查一下 ARGBbitmap.mq5 脚本是如何工作的。
上述图片 "argb.bmp" 包含有关透明度的信息:左上角具有完全透明的背景,透明度沿对角线向右下角逐渐消失。
以下图片显示了在三种不同模式下运行脚本的结果。
颜色格式 COLOR_FORMAT_XRGB_NOALPHA 下的图像输出
颜色格式 COLOR_FORMAT_ARGB_RAW 下的图像输出
颜色格式 COLOR_FORMAT_ARGB_NORMALIZE 下的图像输出