安卓ADB工具系列——快速截屏并直接保存在windows上

前言
本文旨在windows操作系统下,利用ADB工具,直接将截图存放到电脑磁盘中,降低手机负担,提高截图效率。

ADB截图命令在下面这篇文章中有介绍

http://blog.csdn.net/wirelessqa/article/details/29187339

截图命令分为两种,第一种是先截图保存到安卓手机的SD卡中,然后再上传到电脑上,最后再删除SD卡中的截图。第二种是直接将截图保存到电脑上。

由于第一种方法需要对手机进行写-读-写操作,对电脑进行写操作,而第二种方法只需要对电脑写操作,大大减少了对手机的操作,对需要频繁截屏的场景十分奏效。

ADB直接截图并保存到电脑的命令是

adb shell screencap -p >screenshot.png

上述指令将截图数据重定向到当前文件夹下名为screenshot的png文件。然而,在windows操作系统下,回车符是\r\n,在Linux操作系统下,回车符是\n。安卓系统是基于Linux内核开发而来的,所以在安卓系统中回车符也是\n,这样就会出现一个问题,在安卓系统中截图得到的二进制数据流中,如果出现\n,Windows会将\n解析成\r\n,所以截图命令得到的png文件不能正常打开。要使得在Windows系统中能对截图得到的png文件进行操作,需要将png文件中数据部分的\r\n转换成\n,这样就能够得到正确的文件。

png文件结构在下面这篇文章中有介绍

http://blog.csdn.net/bisword/article/details/2777121

对于一个png文件来说,其文件头由固定8个字节来描述的,其十六进制数为:89 50 4E 47 0D 0A 1A 0A,其中0D代表\r,0A代表\n。上面说过Windows会将\n转化成\r\n,为了验证上面的介绍,这里使用Notepad++,利用HEX-Editor插件以十六进制显示重定向后的文件screenshot.png,其结果如下图所示。

文件头的十六进制

可以看出,png的文件头中的0A在Windows中确实被解析成了0D0A,我们接下来需要做的便是将所有的0D0A替换成0A。假设原文件是a.png,需要得到的正确文件是b.png。替换的思路是:

  1. 创建一个大小为N字节的缓冲区1和大小为N个字节的缓冲区2,缓冲区1用于缓存读取的文件数据流,缓冲区2用于缓存写入的文件数据流。
  2. 从文件a.png读取N个字符并存入缓冲区1,从缓冲区的第0个位置开始到第N-2个位置,逐个判断当前字符和下一个字符是否是\r\n,如果不是,则将当前字符存入缓冲区2中,否则不进行任何操作。完成后将缓冲区2中的数据写入到b.png中。由于缓冲区1中第N-1个字符后面没有有效的字符,不能进行判断,所将第N-1个字符存放到临时变量1中留到下一步中判断。
  3. 再从文件读取N个字符并存入缓冲区1,先判断临时变量1和缓冲区1的第0个字符是否是\r\n,如果不是,则将临时变量1追加写入到b.png中,否则不进行任何操作。然后和步骤2类似,从缓冲区1的第0个字符开始到第N-2个字符,逐个判断当前字符和下一个字符是\r\n,如果不是则将当前字符存入缓冲区2中,否则不进行任何操作。完成后将缓冲区2中的数据写入到b.png中。
  4. 循环执行步骤2,直到读取到文件结尾EOF。
  5. 由于最后一步中缓冲区中最后一个字符没有用到,所以将上一步中的最后一个字符追加写入到b.png中。
  6. 关闭文件a.png和文件b.png。

注意:如果最后一次读取到的字符数目不是N,则以实际读取到的字符数目M为准,从第0个字符到第M-2个字符开始遍历。

上述算法的C语言实现如下,其中变量srcPngPath和destPngPath分别代表原文件和待写入的目的文件的路径。

int convertPng(const char* srcPngPath, const char* destPngPath)
{
    //原文件和目的文件指针
    FILE *fp1, *fp2;
    int i, count;
    //实际读取的字符数目
    int num;
    //png文件头的等效表示
    long long head = 0x0a1a0a0d474e5089;
    //读取和写入文件缓冲区,临时变量
    char text[1024], text2[1024], tmpchar;

    if (!(fp1 = fopen(srcPngPath, "rb")))
    {
        return -1;//原文件打开失败
    }
    fp2 = fopen(destPngPath, "wb");

    fread(text, sizeof(char), 1024, fp1);
    count = 0;
    for (i = 0; i < 1023; i++)
    {
        if (!(text[i] == '\r' && text[i + 1] == '\n'))
            text2[count++] = text[i];
    }
    fwrite(text2, sizeof(char), count, fp2);
    tmpchar = text[1023];

    while (num = fread(text, sizeof(char), 1024, fp1))
    {
        count = 0;
        if (!(tmpchar == '\r' && text[0] == '\n'))
            fputc(tmpchar, fp2);

        for (i = 0; i < num - 1; i++)
        {
            if (!(text[i] == '\r' && text[i + 1] == '\n'))
                text2[count++] = text[i];
        }
        fwrite(text2, sizeof(char), count, fp2);
        tmpchar = text[num - 1];
    }
    fputc(text[num - 1], fp2);

    fclose(fp1);
    fclose(fp2);

    return 0;
}

在我的2.8GHz主频的电脑上转换一个大小为12.1KB的png文件耗时约为1ms。

你可能感兴趣的:(安卓)