• 图像操作API
    • Image对象
    • 图片比较操作
    • 示例
    • 控件与模型图片比较
    • 虚拟控件上的图片操作

    图像操作API

    图像操作API用于在执行中操作API,及自动化结果的验证,主要通过Image对象。此外虚拟控件也有相应的方法,根据图片实现判断。

    Image对象

    Image对象用于获得图片的属性信息,及针对图片的比较操作。

    Image对象定义如下:

    1. class Image {
    2. width: number;
    3. height: number;
    4. clip(rect: {x: number, y: number, width: number, height: number}): Image;
    5. drawImage(image: Image, x: number, y: number): Image;
    6. getData(option?: {encoding: 'base64' | null}): Promise<Buffer | string>;
    7. static fromData(bufferOrString: Buffer | string): Promise<Image>;
    8. static fromFile(filePath: string): Promise<Image>;
    9. static imageEqual(image1: Buffer | string | Image,
    10. image2: Buffer | string | Image,
    11. options?: CompareOptions,
    12. compareInfo?: ImageCompareInfo): Promise<boolean>;
    13. static imageCompare(image1: Buffer | string | Image,
    14. image2: Buffer | string | Image,
    15. options?: CompareOptions): Promise<ImageCompareResult>
    16. }

    获得一个Image对象的实例可以得到图片的属性,或将图片用于后继处理。

    可以从Buffer、base64的字符串,或者一个文件路径生成Image实例,例如:

    1. const { Image } = require('leanpro.visual');
    2. const fs = require('fs');
    3. (async function() {
    4. let buf1 = fs.readFileSync('c:/temp/image1.png');
    5. let image1 = await Image.fromData(buf1);
    6. console.log(image1.width, image1.height);
    7. let image2 = await Image.fromFile('c:/temp/image2.png');
    8. console.log(image2.width, image2.height);
    9. })()

    上面例子分别从Buffer和文件中读取图片数据并打印宽度和高度。

    注意:无法直接通过new Image()创建对象,需要通过fromData或者fromFile生成Image实例。另外Image对象现只支持PNG格式的图片。

    实例成员:

    • clip 用于剪切图片,返回另一个图片。传入矩形框,按照矩形框剪切图片,如果传入数据不合法导致剪切的图片宽度或高度为0,返回为null;
    • drawImage 用于将两幅绘制图片绘制到一幅图片上。返回为新绘制的图片。

    例如:

    1. this.screen1 = await model.getButton("Five").takeScreenshot();
    2. this.screen2 = await model.getButton("Six").takeScreenshot();
    3. let image1 = await Image.fromData(this.screen1);
    4. let image2 = await Image.fromData(this.screen2);
    5. image1 = image1.clip({ x: 10, y: 10, width: image1.width - 20, height: image1.height - 20 })
    6. image2 = image2.clip({ x: 10, y: 10, width: image2.width - 20, height: image2.height - 20 })
    7. let combinedImage = image1.drawImage(image2, image1.width + 5, 0);

    上面代码将两个按钮截屏剪切掉10像素的周围边缘,然后绘制到一张图片上,中间间隔5个像素。

    如果你想让两幅图片上下排列,你可以使用类似下面的代码:

    1. let combinedImage = image1.drawImage(image2, 0, image1.height + 5);

    您还可以使用为负值的x,y,以便第二个图像在第一个图像的另一侧绘制,例如,以下语句将在左侧绘制image2,在右侧绘制image1:

    1. let combinedImage = image1.drawImage(image2, -(image1.width + 5), 0);
    • getData返回图片的内容数据,可用于保存至文件,或添加到报表中。注意它返回的是Promise,所以在async函数中需要加await。

    图片比较操作

    在自动化过程中,为了验证结果的正确性,可以通过验证结果图片和期望图片的差异来判断执行结果是否正确。

    图片判断主要有两种方式:

    • 比较图片差异,返回布尔值。
    • 将两幅图对应像素相减,产生结果图片,将差异点用色彩标出来,结果图片显示在报表中,可以由人工判断是否正确。

    Image对象的imageEqual和imageCompare分别针对上面两种对比方式。

    由于操作系统、分辨率、颜色设置都可能影响图片的显示,同样的控件在不同的环境设置下可能显示不同,所以在比较截屏图片时,一般会设置比较容忍度。在容忍度阈值内认为两幅图片是相同的。容忍度有如下的分类:

    • 颜色容忍度:针对两幅图片的两个对应像素点,如果它们的RGB颜色按照特定的距离算法在一定的范围内认为是相同的。
    • 像素容忍度:针对两幅图整体而言,如果不同的像素点数量在一定的范围内,则认为两幅图是相同的。像素容忍度还可以根据百分比来设定,即不同的点占图片所有像素的百分比。

    • imageEqual

    imageEqual用来比较两幅图片的差异,返回布尔值的Promise,如果是true表示相同,false表示不同。如果您只想知道两个图像是否不同,请使用此API。 如果您想知道获取显示差异所在位置的结果图像,请使用另一个API imageCompare

    它的函数签名:

    1. imageEqual(image1: Buffer | string | Image,
    2. image2: Buffer | string | Image,
    3. options?: CompareOptions,
    4. compareInfo?: ImageCompareInfo): Promise<boolean>;
    • image1、image2可以是Buffer、base64的字符串,或者一个Image实例。
    • options用来指定图片比较的参数,它有如下的参数设置:
    1. interface CompareOptions {
    2. colorTolerance?: number, //default to 0.1
    3. pixelNumberTolerance?: number, //no default value
    4. pixelPercentTolerance?: number, //default 1, means 1%
    5. ignoreExtraPart?: boolean //default to false
    6. }

    其中:

    1. - **colorTolerance**:颜色容忍度,缺省为0.1。一般不用修改。
    2. - **pixelNumberTolerance**:像素数量容忍度,没有缺省值。
    3. - **pixelPercentTolerance**:像素百分比容忍度,缺省为1,即1%。例如,两幅图片分别有10000像素,如果允许少于150个像素不同的情况下认为图片相同,则设置为1.5
    4. - **ignoreExtraPart**:是否忽略非重叠部分,缺省为false。两幅比较图片可以是不同尺寸,比较时左上角对齐,超出部分会当成是不同的点。如果设成true,则会忽略超出部分。

    当pixelNumberTolerance和pixelPercentTolerance有一个超出了设定值(或缺省值)比较就会返回false。如果只需要使用其中一个设定,可以将另一个设定设为比较大的值。例如只需要pixelNumberTolerance,并忽略pixelPercentTolerance,可以把pixelPercentTolerance设成100。

    • 除了返回值表示是否相同外,有时需要知道详细的信息,例如像素尺寸,有多少点不同,不同的点的百分比等,这时可以通过传出compareInfo对象获得相关信息。

    compareInfo的类型:

    1. interface ImageCompareInfo {
    2. image1: {
    3. width: number,
    4. height: number
    5. },
    6. image2: {
    7. width: number,
    8. height: number
    9. }
    10. diffPixels: number,
    11. diffPercentage: number
    12. }

    使用时,如果compareInfo传入一个空的对象,调用imageEqual后compareInfo会填充如上结构的数据。

    下面是调用样例:

    1. (async function() {
    2. try {
    3. let pngSource = await Image.fromFile(__dirname + '/../source.png');
    4. let pngTargt = await Image.fromFile(__dirname + '/../target.png');
    5. let compareInfo = {};
    6. let isEqual = await Image.imageEqual(pngSource, pngTargt,
    7. {pixelNumberTolerance: 300, ignoreExtraPart: true}, compareInfo);
    8. console.log('isEqual', isEqual, JSON.stringify(compareInfo, null, 2));
    9. } catch(err) {
    10. console.log(err)
    11. }
    12. })()

    执行时它传入两个图片,比较是否相同,同时会忽略没有重叠部分。如果不同的像素点超过300个,则返回false,同时它返回了compareInfo的详细数据。打印的内容如下:

    1. isEqual false {
    2. "image1": {
    3. "width": 375,
    4. "height": 266
    5. },
    6. "image2": {
    7. "width": 402,
    8. "height": 224
    9. },
    10. "diffPixels": 3502,
    11. "diffPercentage": 3.3100814760203408
    12. }

    • imageCompare

    impageCompare,比较两者图片,返回详细信息的数据,特别是两幅图片差异部分的图片。如果您想获得显示差异所在位置的结果图像,请使用此API。

    它有如下的签名:

    1. imageCompare(image1: Buffer | string | Image,
    2. image2: Buffer | string | Image,
    3. options?: CompareOptions): Promise<ImageCompareResult>
    • image1、image2可以是Buffer、base64的string,或者一个Image实例。
    • options 的设置与imageEqual的options设置相同。此外,如果ignoreExtraPart是false,对生成的差分图片有影响。如果ignoreExtraPart为false,图片非重叠部分会设置为红色,否则非重叠不设置颜色。返回值是名为ImpageCompareResult的结构:
    1. interface ImageCompareResult {
    2. equal: boolean,
    3. info: ImageCompareInfo,
    4. diffImage: Image
    5. }

    其中:

    • equal表示是否根据容忍度设置认为图片相同。
    • info的结构与imageEqual的compareInfo结构相同,包括像素尺寸,有多少点不同,不同的点的百分比等。
    • diffImage是返回的差分图片的Image对象,相同的像素点以缺省白色表示,不同的点显示为红色。图像中原有的图案会以浅色显示在目标图片中,方便定位差异部分所在的位置。

    这两个图片比较API中,imageEqual是imageCompare的封装,为了更直观的返回两个图片是否相等的判断结果。如果只想知道是否相等就用imageEqual,如果除了是否相等外,还想知道更详细的就用imageCompare。

    示例

    下面是比较两个图片并生成差分图片的样例:

    1. (async function() {
    2. try {
    3. let pngSource = await Image.fromFile(__dirname + '/../image1.png');
    4. let pngTargt = await Image.fromFile(__dirname + '/../image2.png');
    5. let result = await Image.imageCompare(pngSource, pngTargt, {pixelNumberTolerance: 300});
    6. let diffImage = result.diffImage;
    7. console.log('resultMeta', JSON.stringify(result.info, null, 2));
    8. let imageData = await diffImage.getData();
    9. fs.writeFileSync(__dirname + '/../diff.png', imageData)
    10. } catch(err) {
    11. console.log(err)
    12. }
    13. })()

    该样例打印出差异信息,并把结果图片保存成文件"diff.png"。

    假如我们有下面两幅图片:

    image1 (375 266)image2 (402 224)
    图像操作API - 图1图像操作API - 图2

    根据参数的不同,可以生成下面的差分图片:

    ignoreExtraPart = trueignoreExtraPart = false
    图像操作API - 图3图像操作API - 图4

    左边是ignoreExtraPart = true的情况,超出部分也标记为红色,右边是ignoreExtraPart = false,忽略了超出部分。

    控件与模型图片比较

    Windows自动化中一个常见的场景是,将运行时控件的截屏与模型中的保存的测试对象截屏相比较。这可以通过调用测试对象的modelImage方法获得测试对象的截屏png图片,以base64字符串数据返回。如果模型中该对象没有对应的截屏图片,则返回null。

    下面的样例从对象模型中获取按钮对象,同时拿到控件截屏和模型中的截屏,并做对比,将对比信息打印出来,同时将差分图片保存到目录中。

    1. const { Image } = require('leanpro.visual');
    2. const { TestModel } = require('leanpro.win');
    3. const fs = require('fs');
    4. const model = TestModel.loadModel(__dirname + "\\test.tmodel");
    5. (async function () {
    6. let five = model.getButton("Five");
    7. let controlImage = await five.takeScreenshot();
    8. let modelImage = await five.modelImage();
    9. let result = await Image.imageCompare(modelImage, controlImage);
    10. fs.writeFileSync(__dirname + '/diff.png', await result.diffImage.getData());
    11. //print the diff information
    12. console.log(result.info)
    13. })();

    虚拟控件上的图片操作

    虚拟控件的图片相关操作有:

    • findSnapshot
    • matchSnapshot

    请参见虚拟控件API获得相关帮助。