zoukankan      html  css  js  c++  java
  • 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;



  • 相关阅读:
    Cesium实现键盘控制镜头效果
    怎么判断一个服务器的服务器性能
    2T以上的盘怎么分区, 利用parted创建 linuxTB硬盘GPT分区
    解压和压缩的简单用法
    关于windows修改远程登录端口的问题
    tomcat启动非常慢;连接oracle数据库失败,jdbc错误日志提示connection reset;测试主机间网络互通及数据库端口都正常
    docker的安装和基础使用
    Centos7 时区的设置
    Day24 中间件 自定义分页 ModelForm 序列化 缓存 信号
    Day22 博客园的构建
  • 原文地址:https://www.cnblogs.com/happycat1988/p/2301282.html
Copyright © 2011-2022 走看看