前言
本文旨在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。替换的思路是:
注意:如果最后一次读取到的字符数目不是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。