粤嵌GEC6818实现图片显示

简介: 粤嵌GEC6818实现图片显示

要求

练习: 完成一张图片在板子上的显示

要求: 任意路径的图片

任意大小的图片

在板子上的任意位置显示

思路

  void show_bmp (char * pathname ,  int x,int y)
  {
    第一步:打开图片 ,读取宽度 高度 色深 
    
    第二步: 确定总字节数  然后malloc对应大小的内来保存这些颜色。unsigned char * p = malloc(total_bytes);
    
    //第三步: 打开帧缓冲设备  映射    init(); end();
    
    第四步: 把颜色的值写进去 要一个字节一个字节地写入 为什么呢?   
          因为32位和24位地A是不一样的。
          unsigned char a,r,g,b ;
          我们把前面保存的像素数组的对应内容 一个一个字节地给我的argb 。
          24位的像素数组只有RGB    a直接给0 
          32位的像素数组有a  需要给一个字节给a 
    
          每写完四个字节  写完一个argb 。 这四个字节是不是就是组成一个color ? 
          这个时候是不是就该调用我们draw_point函数。
    
    
              注意: 每行跳过癞子。
          
    第五步: 关闭图片 //关闭帧缓冲 解除映射
  }

代码

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <sys/mman.h>
#include <math.h>
#include <stdlib.h>
int * p = NULL ;

void draw_point(int x,int y,int color)
{
  if(x>=0 && x<800 && y>=0 && y<480 )
  {
    *(p+800*y+x) = color ;
  }
}
/*
函数功能:在屏幕的任意一个位置  显示任意一张  任意大小的bmp图片 
函数参数: 
    @pathname : 要显示的图片 的路径名 
    @x : 在屏幕X轴值为x的地方开始显示
    @y :  在屏幕Y轴值为y的地方开始显示
*/
void show_bmp (char * pathname ,int x ,int y)
{
  int fd = open(pathname,O_RDONLY);
  if(fd == -1)
  {
    perror("open error\n");
    return ;
  }
  int fd1 = open("/dev/fb0",O_RDWR);
  if(fd1 == -1)
  {
    perror("open error\n");
    return ;
  }
  printf("open success\n");
  
  p = mmap(NULL,800*480*4,PROT_READ | PROT_WRITE,MAP_SHARED ,fd1,0);
  if(p == NULL )
  {
    perror("mmap error\n");
    return ;
  }
  int width,height;
  short depth;
  unsigned char buf[4] ;
  //读取宽度
  lseek(fd,0x12,SEEK_SET);
  read(fd,buf,4);
  width = buf[3]<<24 | buf[2]<< 16 | buf[1] << 8 | buf[0];
  //读取高度
  read(fd,buf,4);
  height  = buf[3]<<24 | buf[2]<< 16 | buf[1] << 8 | buf[0];
  //读取色深
  lseek(fd,0x1c,SEEK_SET);
  read(fd,buf,2);
  depth = buf[1] << 8  | buf[0];
  //打印信息
  printf("width = %d  height = %d  depth = %d \n",width,height,depth);

  //像素数组 
  int line_valid_bytes = abs(width) * depth / 8 ; //一行本有的有效字节
  int laizi=0;//填充字节
  if( (line_valid_bytes % 4) !=0   )
  {
    laizi =  4 - line_valid_bytes%4;
  }
  int line_bytes = line_valid_bytes  +  laizi ;//一行所有的字节数
  
  int total_bytes = line_bytes * abs(height) ; //整个像素数组的大小
  
  unsigned char * p1  = malloc(total_bytes);
  
  lseek(fd,54,SEEK_SET);
  read(fd,p1,total_bytes);
  
  //调用draw_point 函数 。
  unsigned char a ,r ,g, b ;
  int i = 0;//用来做指针运动的
  int x0=0,y0=0; //用来循环计数
  int color ;
  for(y0=0;y0<abs(height);y0++)//画满每一列
  {
    for(x0=0;x0<abs(width);x0++)//画满每一行
    {
      //现在开始一个字节一个字节写入颜色
      // i++  先用后加     
      // ++i  先加后用
      b = p1[i++];
      g = p1[i++];
      r = p1[i++];
      if(depth == 32)
      {
        a=p1[i++];
      }
      if(depth == 24)
      {
        a = 0;
      }
      color = a << 24 | r << 16 | g << 8 | b ;
      draw_point(width>0?x+x0:abs(width)+x-1-x0,
          height>0? y+height-1-y0 : y+y0,color);
      
      
    }
    i = i +laizi ;//每一行后面的癞子数 跳过去。
      
  }
  free(p1);
  close(fd1);
  munmap(p,800*480*4);
  close(fd);
  
}
int main()
{
  show_bmp("1.bmp",-100 ,-100);
  //show_bmp("3.bmp",0,0);
  return 0;
}

具体步骤

1、读取文件设置缓冲区

int fd = open(pathname,O_RDONLY);
  if(fd == -1)
  {
    perror("open error\n");
    return ;
  }
  int fd1 = open("/dev/fb0",O_RDWR);
  if(fd1 == -1)
  {
    perror("open error\n");
    return ;
  }
  printf("open success\n");

2、测量待显示图片的宽度、高度、色深

p = mmap(NULL,800*480*4,PROT_READ | PROT_WRITE,MAP_SHARED ,fd1,0);
  if(p == NULL )
  {
    perror("mmap error\n");
    return ;
  }
  int width,height;
  short depth;
  unsigned char buf[4] ;
  //读取宽度
  lseek(fd,0x12,SEEK_SET);
  read(fd,buf,4);
  width = buf[3]<<24 | buf[2]<< 16 | buf[1] << 8 | buf[0];
  //读取高度
  read(fd,buf,4);
  height  = buf[3]<<24 | buf[2]<< 16 | buf[1] << 8 | buf[0];
  //读取色深
  lseek(fd,0x1c,SEEK_SET);
  read(fd,buf,2);
  depth = buf[1] << 8  | buf[0];
  //打印信息
  printf("width = %d  height = %d  depth = %d \n",width,height,depth);

BMP图片的显示 :

bmp:bit map picture 位图

bmp文件格式的图片, 没有经过任何压缩技术生成的图片。

无压缩:保存了图片的每一个像素点的rgb颜色分量的值。

我们按照bmp图片文件的固定的内容格式将他的数据读出来,进行一些简单的操作。我们就可以完成这个图片的显示。

BMP图片文件格式

见图:

头两个字节 BM 我们是自己用BMP图片 所以就不用判定。

  宽度: 一行有多少个像素点:
      偏移量:0x12 
      大小: 4个字节
      可正可负 
      正负只表示一行像素点的存储方式
      为正说明行像素点是从左到右排列
      为负说明行像素点是从右往左排列
  高度: 一列有多少个像素点
      偏移量:0X16
      大小 : 4个字节
      可正可负 
      正负只表示一列像素点的存储方式
      为正说明行像素点是从下到上排列
      为负说明行像素点是从上往下排列
  色深: 每个像素所占的位数 bit  
      怎么求每个像素的大小?字节
        色深/8
       24 
       32  
      偏移量:0x1c
      大小: 2个字节

小端模式和大端模式

小端模式: 存储器(内存)的低地址 存放 寄存器(数据)的低地址字节

大端模式: 存储器(内存)的低地址 存放 寄存器(数据)的高地址字节

两者的区别就是 高字节位、低字节位存放次序不同;小端先存低,大端先存高,大端模式用于比较高端的场景,处理速度快。

  获取图片的宽度 高度 色深信息。
  思路: 
    int width,height;
    short depth;
    unsigned char buf[4];
    
   第一步: 打开图片  open("./1.bmp")
   第二步: lseek 偏移对应偏移量大小
        read   读取对应数据大小的内容
        。。。。。
   第三步: 关闭图片

buf[4]

buf[0]  buf[1]  buf[2]  buf[3]  

我们真正想要的正确的数据是多少

buf[3]  buf[2]  buf[1]  buf[0] 



buf[0]  buf[1]  buf[2]  buf[3]  ---> buf[3]  buf[2]  buf[1]  buf[0] 

buf[3] << 24        buf[3]    _______    ________    _________  

buf[2] << 16       _________   buf[2]  __________  ___________

buf[1] << 8       __________  _______   buf[1]   ____________

buf[0]             _________  _________  ________     buf[0]


width = buf[3] << 24 | buf[2] << 16 | buf[1] << 8  | buf[0] 

将图像字节写入一个数组

//像素数组 
  int line_valid_bytes = abs(width) * depth / 8 ; //一行本有的有效字节
  int laizi=0;//填充字节
  if( (line_valid_bytes % 4) !=0   )
  {
    laizi =  4 - line_valid_bytes%4;
  }
  int line_bytes = line_valid_bytes  +  laizi ;//一行所有的字节数
  
  int total_bytes = line_bytes * abs(height) ; //整个像素数组的大小
  
  unsigned char * p1  = malloc(total_bytes);
  

像素数组: 保存了图片像素点的所有argb颜色分量的值

  偏移量: 54
  大小:  ???
  
  大小需要根据宽度和高度和色深来求 。
  格式规定图片每行的字节数为4字节的倍数
  大小: 图片的宽度的绝对值   *  图片的高度的绝对值  *  色深/ 8
  if(depth == 32)
  {
    (图片的宽度的绝对值  *  32/ 8) % 4 一定为0 ;
  }
  
  if(depth == 24 )
  {
    (图片的宽度的绝对值  *  24 / 8)  % 4  不一定为 0 ;
  }

  是不是我们24位的图片就需要填充若干个字节 来满足每行大小为4字节倍数要求
  这些填充的字节数 我们叫癞子。
  
  那我们怎么求出每行的填充的字节数呢?癞子?
  
  int laizi;
  if (    ( 宽度*色深/8 ) %4  !=0    )
  {
    laizi = 4 -  宽度*色深/8 ) %4 ;
  }


  我真正意义上一行的字节数 是多少?   line_bytes = ( 宽度*色深/8 ) %4   +  laizi ;
  总共的字节数呢?     total_bytes = line_bytes * height 
  
  unsigned char * p = malloc(total_bytes);

将图像字节写入屏幕

void draw_point(int x,int y,int color)
{
  if(x>=0 && x<800 && y>=0 && y<480 )
  {
    *(p+800*y+x) = color ;
  }
}
lseek(fd,54,SEEK_SET);
  read(fd,p1,total_bytes);
  
  //调用draw_point 函数 。
  unsigned char a ,r ,g, b ;
  int i = 0;//用来做指针运动的
  int x0=0,y0=0; //用来循环计数
  int color ;
  for(y0=0;y0<abs(height);y0++)//画满每一列
  {
    for(x0=0;x0<abs(width);x0++)//画满每一行
    {
      //现在开始一个字节一个字节写入颜色
      // i++  先用后加     
      // ++i  先加后用
      b = p1[i++];
      g = p1[i++];
      r = p1[i++];
      if(depth == 32)
      {
        a=p1[i++];
      }
      if(depth == 24)
      {
        a = 0;
      }
      color = a << 24 | r << 16 | g << 8 | b ;
      draw_point(width>0?x+x0:abs(width)+x-1-x0,
          height>0? y+height-1-y0 : y+y0,color);
      
      
    }
    i = i +laizi ;//每一行后面的癞子数 跳过去。
      
  }

注意事项

  • bmp图片需要传在GEC818上
  • 如果要显示两张图片改变两张图片的起始位置即可
  • width>0?x+x0:abs(width)+x-1-x0

当width>0,也就是从左到右时,横坐标位置为x+x0

当width<0,也就是从右到左时,横坐标位置为abs(width)+x-1-x0`



模块化思想: 
  
  。。。
  只有一个唯一的main函数‘
  一个或者多个功能函数 
  main.c
  lcd.c   lcd.h
  bmp.c   bmp.h
  led.c   led.h
  beef.c   beef.h
  .....
  
  
  
  .h怎么写? 
  例:led.h
  
  #ifndef  __LED_H__
  #define  __LED_H__
  
  
  // 变量的定义 
  // 函数的声明
  
  //。。。
  
  #endif
  
  
  
  功能函数: 封装一个函数 
  /*
    功能函数:对一个坐标点为(x,y)的像素点上色。
    参数: 
      @x : 像素点的X轴坐标值
      @y :像素点的Y轴坐标值
      @color : 要画的颜色
  */
  void draw_point (  int x, int y, int color )
  {
    if(x>=0 && x<800 && y>=0 && y<480)
    *(p + 800*y +x ) = 0x00ff0000 ;//p定义成全局变量
  }
   
  
  
  
  
BMP图片的显示 : 

  bmp:bit map picture 位图
  bmp文件格式的图片, 没有经过任何压缩技术生成的图片。
  无压缩:保存了图片的每一个像素点的rgb颜色分量的值。
  我们按照bmp图片文件的固定的内容格式将他的数据读出来,进行一些简单的操作。我们就可以完成这个图片的显示。
  
  
  BMP图片文件格式 
    见图:
    
    头两个字节  BM 我们是自己用BMP图片 所以就不用判定。
    
    
    宽度: 一行有多少个像素点: 
    
        偏移量:0x12 
        大小: 4个字节 
        
        可正可负 
        正负只表示一行像素点的存储方式
        为正说明行像素点是从左到右排列
        为负说明行像素点是从右往左排列
        
    高度: 一列有多少个像素点
      
        偏移量:0X16
        大小 : 4个字节
    
        可正可负 
        正负只表示一列像素点的存储方式
        为正说明行像素点是从下到上排列
        为负说明行像素点是从上往下排列
    
    
    色深: 每个像素所占的位数 bit  
        怎么求每个像素的大小?字节
          色深/8
         
         24 
         32  
         
        偏移量:0x1c
        大小: 2个字节
    
    
  小端模式和大端模式 
  小端模式: 存储器(内存)的低地址  存放 寄存器(数据)的低地址字节
  大端模式: 存储器(内存)的低地址  存放 寄存器(数据)的高地址字节
    
    练习: 获取图片的宽度 高度 色深信息。
    
    思路: 
      int width,height;
      short depth;
      unsigned char buf[4];
      
     第一步: 打开图片  open("./1.bmp")
     第二步: lseek 偏移对应偏移量大小
          read   读取对应数据大小的内容
          。。。。。
          
          
          
          
    
     第三步: 关闭图片
    
    
      
  buf[4] 
  
  buf[0]  buf[1]  buf[2]  buf[3]  
  
  我们真正想要的正确的数据是多少
  
  buf[3]  buf[2]  buf[1]  buf[0] 



  buf[0]  buf[1]  buf[2]  buf[3]  ---> buf[3]  buf[2]  buf[1]  buf[0] 
  
  buf[3] << 24        buf[3]    _______    ________    _________  
  
  buf[2] << 16       _________   buf[2]  __________  ___________
  
  buf[1] << 8       __________  _______   buf[1]   ____________
  
  buf[0]             _________  _________  ________     buf[0]
  
  
  width = buf[3] << 24 | buf[2] << 16 | buf[1] << 8  | buf[0] 
  
  同样的方法求高度 色深...
  
  见code  : 
  
  
  像素数组: 保存了图片像素点的所有argb颜色分量的值
  
    偏移量: 54
    大小:  ???
    
    大小需要根据宽度和高度和色深来求 。
    
    大小: 图片的宽度的绝对值   *  图片的高度的绝对值  *  色深/ 8
    if(depth == 32)
    {
      (图片的宽度的绝对值  *  32/ 8) % 4 一定为0 ;
    }
    
    if(depth == 24 )
    {
      (图片的宽度的绝对值  *  24 / 8)  % 4  不一定为 0 ;
    }
  
    是不是我们24位的图片就需要填充若干个字节 来满足每行大小为4字节倍数要求
    这些填充的字节数 我们叫癞子。
    
    那我们怎么求出每行的填充的字节数呢?癞子?
    
    int laizi;
    if (    ( 宽度*色深/8 ) %4  !=0    )
    {
      laizi = 4 -  宽度*色深/8 ) %4 ;
    }
  
  
    我真正意义上一行的字节数 是多少?   line_bytes = ( 宽度*色深/8 ) %4   +  laizi ;
    总共的字节数呢?     total_bytes = line_bytes * height 
    
    unsigned char * p = malloc(total_bytes);
  
  
  练习: 完成一张图片在板子上的显示
      要求: 任意路径的图片 
          任意大小的图片
          在板子上的任意位置显示 
          
    void show_bmp (char * pathname ,  int x,int y)
    {
      第一步:打开图片 ,读取宽度 高度 色深 
      
      第二步: 确定总字节数  然后malloc对应大小的内来保存这些颜色。unsigned char * p = malloc(total_bytes);
      
      //第三步: 打开帧缓冲设备  映射    init(); end();
      
      第四步: 把颜色的值写进去 要一个字节一个字节地写入 为什么呢?   
            因为32位和24位地A是不一样的。
            unsigned char a,r,g,b ;
            我们把前面保存的像素数组的对应内容 一个一个字节地给我的argb 。
            24位的像素数组只有RGB    a直接给0 
            32位的像素数组有a  需要给一个字节给a 
      
            每写完四个字节  写完一个argb 。 这四个字节是不是就是组成一个color ? 
            这个时候是不是就该调用我们draw_point函数。
      
      
                注意: 每行跳过癞子。
            
      第五步: 关闭图片 //关闭帧缓冲 解除映射
      
      
    }
  

效果图

相关文章
|
6月前
鼠标经过图片图片放大效果
鼠标经过图片图片放大效果
48 0
|
4月前
|
前端开发
css实用技巧——异步加载图片时,在图片完成加载前,鼠标悬浮到占位图片上时显示图片的alt信息
css实用技巧——异步加载图片时,在图片完成加载前,鼠标悬浮到占位图片上时显示图片的alt信息
27 0
|
6月前
|
机器学习/深度学习 人工智能
bigjpg图片放大
bigjpg图片放大
64 0
平铺文理+拉伸按钮图片
平铺文理+拉伸按钮图片
79 0
显示图片
显示图片
95 0
|
JavaScript BI 数据库
|
C#
【C#/WPF】图片的切割/切图/裁剪图片
原文:【C#/WPF】图片的切割/切图/裁剪图片 前台准备两个Image控件。上面是显示原图,下面显示切割后的效果。 对应的后台代码: public par...
2174 0