TC下graphics.h中getimage/putimage使用到的数据格式

这次的图形学作业是做分形图 不过描点绘图的速度太慢了 于是就想要写到内存中然后一次都绘制到屏幕上

查看了一下getimage和putimage这2个函数 分别是用来截取屏幕图像到内存和绘制内存数据到屏幕的

那么我只要先画到内存中 然后再用putimge去绘制就行了

但是网上找了很多资料 都没把存储的数据结构表达的很清楚 所以我也绕了不少弯子 最后看了一个显示BMP图像到屏幕的程序 算是搞明白了存储格式了

存储的数据格式如下:

宽度 2字节

高度 2字节

图像数据 n字节 这个后面详细分析

保留部分 2字节

这里的宽度其实是实际的宽度-1 高度也是实际的宽度-1 也就是说 比如你截取的是0,0-7,7 这样一个8*8的区域 那么宽度这里保存的就是7 高度这里保存的也是7
这里需要注意一下 高度和宽度都是小端对齐的 也就是低位的部分在低位的部分 高位的部分在高位的部分 也就是说 一个8*8的图像 头部4字节应该是这样的:0x07 0x00 0x07 0x00

保留部分是2字节 我也不知道为什么会有这个部分 不过用imagesize去获取大小的话 返回的数据就是宽度2字节+高度2字节+图像数据n字节+保留部分2字节 实际测试了一下 这2个字节无论是放0x00还是放别的什么好像都没什么问题 我在处理上都给他们0x00就是了

接下来是重点了 图像数据部分
图像数据部分他是按照行逐行编排的 也就是先第一行的数据 再第二行的数据 再第三行的数据这样以此类推
同一行中是按照先位面再按照列编排的 这个地方需要详细说一下
什么是位面呢? 我们的屏幕假如是16色的 那么就是0-15这16种颜色 总共用4位二进制可以表示 假如颜色是11 也就是二进制的1011 那么他的第3位面是1 第2位面是0 第1位面是1 第0位面是1 就是按照这个顺序编排出位面的
他是按照位面优先的 这个位面中放的是这个位面所有的列 也就是说 数据形式大致是如下的
行0的位面3 行0的位面2 行0的位面1 行0的位面0 行1的位面3 行1的位面2 行1的位面1 行1的位面0(顺序: 内存低->高)
同一行的同一位面中保存的是这行的这个位面所有的列 而且是按照列号小的在高字节 列号低的在低字节存放的
举例说明的话比较能看懂

putpixel(0,0,15);
putpixel(1,0,0);
putpixel(2,0,7);
putpixel(3,0,0);
我在同一行上打印了4个点 然后使用getimage(0,0,3,0,theimage1);来截取0,0-3,0 也就是第0行中的第0到3列
那么整个图像数据就是:
0x03,0x00,0x00,0x00,0x80,0xa0,0xa0,0xa0,0x00,0x00
总共10个字节
前面4个字节代表的是宽度0x0003和高度0x0000 这里前面说过了 小端对齐 而且是实际的宽度-1和高度-1 大概是为了运算方便吧
后面开始的数据是0x80,0xa0,0xa0,0xa0,0x00,0x00 这里最后的2字节是保留的 我们无视 只看0x80,0xa0,0xa0,0xa0
0x80就是10000000 也就是这行第0列的15的最高位 第1第2第3列的最高位都是0 所以得到的是1000 也就是8 之所以是0x80 是因为不足一个字节的后面自动补0填满这个字节
0xa0就是10100000 这里的2个1 分别对应了第0列15的第次高位和第2列的7的次高位  第1第3列的次高位都是0 所以也就得到了1010 就是a 之所以是0xa0 和之前的原因一样

以上就是大致的图像数据格式了 总之就是一行一行的存放(从低行到高行分别存储到内存的低到高 也就是小端对齐的) 每行中是一个一个位面(从高位面到低位面分别存储到内存的低到高 也就是大端对齐的) 每个位面中是一个一个列(从低列到高列分别存储到内存的低到高 但是在同一字节中列号大的是这个字节的低位 列号小的是在这个字节的高位 ) 如果列不是8的倍数 那么自动在后面补0
这里对于同一位面中的列有点难说清楚 举个例子 比如我们现在有9列 那么在一个位面中保存的数据在内存中的表现如下
低位字节:第0列 第1列 第2列 第3列 第4列 第5列 第6列 第7列 (顺序:这个字节的高位->低位)
高位字节:第8列 0 0 0 0 0 0 0(顺序:这个字节的高位->低位)
最后7个0是因为不足一个字节的填充 我们可以发现 在这个位面中 保存这9列需要2字节 第0-7列在低位字节 第8列在高位字节 但是第0列却在这个低位字节中的最高位
如果你没看懂 那么假如这个位面中第0,1,8列是1 其他列都是0 那么数据是0xC0,0x80 我们知道这里的0xC0是低位字节 保存了0-7列  0x80是高位字节  保存了第8列 但是在0xC0中 实际的数据是11000000 也就是说第0和第1列在这个字节的高位 在0X80中 实际的数据是10000000 也就是说第8列在这个字节的最高位

以上就是整个数据的格式了 根据这个数据格式 我编写了自己的内存画点函数

#define BufferImgWidth 100 /* 缓冲图像的宽度 */

#define BufferImgHeight 100 /* 缓冲图像的高度 */



#if BufferImgWidth%8==0 /* 宽度是8的倍数 */

#define BitPerLine BufferImgWidth /* 那么每行的宽度位数就是这个宽度 单位是二进制位 */

#define BufferImgSize 2+(BitPerLine)/8*4*BufferImgHeight+4 /*计算相应的字节数*/

#else

#define BitPerLine (8+8*(BufferImgWidth/8)) /* 不是8的倍数 那么就要补0填充 所以实际的字节数就要+1了 这里是二进制位 计算时候注意*/

#define BufferImgSize 2+(BitPerLine)/8*4*BufferImgHeight+4 /*计算相应的字节数*/

#endif



unsigned char theimage1[BufferImgSize];/* 缓冲的图像数据就是这个了 */

/* 这个是用于颜色数中取出每一个位面用的 其实这里的bitPos%8是多余的 因为传进去的bitPos范围是0-3 属于我代码的复制粘贴偷懒的历史遗留问题 无所谓啦 */

unsigned char getbitbybitpos(unsigned char c,long bitPos)

{

return ((c & (1<<(char)(bitPos%8))) != 0);

}

/* 这个函数是用于对于缓冲图像的某一位置0或者1的 这里的7-bitPos%8就是之前我说的那个位面中列的高位低位问题了 我在这里直接进行了这样的处理 也就是说这里的bitPos代表的意思是从缓冲区底部到bitPos这一位置 抛开那些头疼的字节吧 我们只用二进制位来定位 */

void setbitbycountpos(unsigned char c[],long bitPos,unsigned char value)

{

if(value)

c[bitPos/8] = (c[bitPos/8] | (1<<(char)(7-bitPos%8)));

else

c[bitPos/8] = (c[bitPos/8] & ~(1<<(char)(7-bitPos%8)));

}

/* 这个就是我们真正要用到的内存画点函数了 */
void imageputpixel(unsigned char image[],long x,long y,unsigned char color)

{

int i;



for(i=0;i<4;i++)/* 分别置位4个位面 */

setbitbycountpos(image,4*8+y*4*BitPerLine+i*BitPerLine+x,getbitbybitpos(color,3-i));/* 这里的3-i的原因就是因为同一行的高位面在前低位面在后的缘故 */



}

/* 下面这些请写在图像初始化部分 用来填写宽度和高度 当然保留字其实不去写也无所谓的 */

theimage1[0]=(BufferImgWidth-1)&0x00ff;

theimage1[1]=((BufferImgWidth-1)>>8)&0x00ff;

theimage1[2]=(BufferImgHeight-1)&0x00ff;

theimage1[3]=((BufferImgHeight-1)>>8)&0x00ff;



theimage1[BufferImgSize-2]=0x00;

theimage1[BufferImgSize-1]=0x00;



原文地址:https://www.cnblogs.com/happycat1988/p/2301282.html