关于bmp、jpg格式图片的解码

这篇具有很好参考价值的文章主要介绍了关于bmp、jpg格式图片的解码。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档

文章目录

目录

文章目录

前言

一、为什么要解码?

二、bmp图片

1.bmp图片信息

2.获取图片信息

三、jpg图片 

总结


前言

        在学习C语言、文件IO、数据结构之后做了一个6818的开发板项目,自觉想要记录一下,本该将整个项目整理好发布的,由于当时着急提交查验,代码并未优化,继而现在将在做项目的时候遇到的自认为较关键的图片格式解码整理一下。


一、为什么要解码?

        想要将图片写入或者映射到开发板设备上,就必须知道图片的像素信息,但图片的信息是一整个合集,各种信息都集中在里面,包括图片的文件类型、图片大小、像素等等信息,而我们只需要像素信息,将之写入/映射到设备,这就需要解码。

二、bmp图片

1.bmp图片信息

  bmp图片信息前面14个字节文件信息 Bitmap File Header,包含文件类型、文件大小等信息,接下来40个字节位图信息Bitmap Information Header,这部分包含位图的宽高、位图数据大小等很多信息,接下来才是像素信息,而我们读取的就是这部分,想要读取这部分信息就要:

                                        Bitmap File Header
                位置      大小(byte)                 描述
00 0 2 头文件字段
02 2 4 整个.bmp文件大小
06 6 2 预留字段,通常为0
08 8 2
0A 10 4 图片信息的开始位置
                                Bitmap Information Header
                 位置 尺寸 描述
0E 14 4 DIB  header的大小通常为40byte即0x28
12 18 4 图像宽度
16 22 4 图像高度
1A 26 2 色彩平面的数量必须为1
1C 28 2 每像素用多少bit来表示
1E 30 4 采用何种压缩方式,通常不压缩,即BI_RGB,对应值为0
22 34 4

图片大小(原始位图数据的大小)

对于不压缩的图片,通常表示为0

26 38 4

横向分辨率(像素/米)

2A 42 4 纵向分辨率(像素/米)
2E 46 4

调色板中颜色数量

通常为0(不表示没有颜色)

32 50 4

重要颜色的数量(通常被忽略)

通常为0(表示每种颜色都重要)

2.获取图片信息

(1)获取图片的宽度和高度

   以下是图片文件信息结构体

// 前14个字节
struct bitmap_header
{
	int16_t type;
	int32_t size; // 图像文件大小
	int16_t reserved1;
	int16_t reserved2;
	int32_t offbits; // bmp图像数据偏移量
}__attribute__((packed));

// 14-54个字节
struct bitmap_info
{
	int32_t size;   // 本结构大小	
	int32_t width;  // 图像宽
	int32_t height; // 图像高
	int16_t planes;

	int16_t bit_count; // 色深
	int32_t compression;
	int32_t size_img; // bmp数据大小,必须是4的整数倍
	int32_t X_pel;
	int32_t Y_pel;
	int32_t clrused;
	int32_t clrImportant;
}__attribute__((packed));

故而要获取图片大小为:

    int fd = open("dd.bmp", O_RDONLY);

	// 读取BMP格式头,获取图片信息
	struct bitmap_header header;
	struct bitmap_info info;
	

    // 读取文件信息到结构体
	read(fd, &header, sizeof(header));
	read(fd, &info, sizeof(info));

    // 输出图片相关信息
    printf("图片大小: %d\n", header.size);
    printf("图片尺寸: %d×%d\n", info.width, info.height);

(2)获取图片的像素信息

    // 打开bmp图片
    int fd_pic = open(addr_bmp, O_RDONLY);
    if (fd_pic < 0)
    {
        perror("open bmp faile");
        return -1;
    }

    // 图片偏移54位
    lseek(fd_pic, 54, SEEK_SET);

    // 获取图片像素信息
    char rgb[480 * 800 * 3] = {0};

    read(fd_pic, rgb, sizeof(rgb));
 

三、jpg图片 

关于jpg(jpeg)图片的解码是使用第三方库来实现的,因此编译时要带上库

jpeg第三方库下载Directory Listing of /files (ijg.org)

解码过程如下:

#include <stdio.h>
#include "jpeglib.h"
#include <setjmp.h>
#include <string.h>
struct my_error_mgr
{
  struct jpeg_error_mgr pub; /* "public" fields */
  jmp_buf setjmp_buffer;     /* for return to caller */
};

typedef struct my_error_mgr *my_error_ptr;

METHODDEF(void)
my_error_exit(j_common_ptr cinfo)
{

  my_error_ptr myerr = (my_error_ptr)cinfo->err;

  (*cinfo->err->output_message)(cinfo);

  longjmp(myerr->setjmp_buffer, 1);
}
//解码jpge
int read_JPEG_file(void *lcd_addr, char *filename)
{

  // 定义一个jpeg解码对象
  struct jpeg_decompress_struct cinfo;

  // 定义一个jpeg错误对象
  struct my_error_mgr jerr;
  FILE *infile;      /* 源文件 */
  JSAMPARRAY buffer; /* 输出行缓存 */
  int row_stride;    /* 输出行大小 */

  
  // 打开需要解码的jpeg文件
  if ((infile = fopen(filename, "rb")) == NULL)
  {
    fprintf(stderr, "can't open %s\n", filename);
    return 0;
  }

  /* Step 1: 初始化解码对象*/
  /* 设置jpeg出错处理函数*/
  cinfo.err = jpeg_std_error(&jerr.pub);
  jerr.pub.error_exit = my_error_exit;
  if (setjmp(jerr.setjmp_buffer))
  {
    jpeg_destroy_decompress(&cinfo);
    fclose(infile);
    return 0;
  }

  /*初始化解码对象函数*/
  jpeg_create_decompress(&cinfo);

  /* Step 2: 关联文件与解码对象 */
  jpeg_stdio_src(&cinfo, infile);

  /* Step 3: 读取jpeg文件头*/
  (void)jpeg_read_header(&cinfo, TRUE);

  /* Step 5: 开始解码 */
  (void)jpeg_start_decompress(&cinfo);

  // 保存图像的宽度与高度
  int width = cinfo.output_width;
  int height = cinfo.output_height;

  row_stride = cinfo.output_width * cinfo.output_components;

  /* 分配一行的RGB数据空间 */
  buffer = (*cinfo.mem->alloc_sarray)((j_common_ptr)&cinfo, JPOOL_IMAGE, row_stride, 1);

  // buffer 输出行缓存,是一个二维数组

  // 把解码后的数据输出到argb数组中
  char argb[width * height * 4];
  int y = 0;
  // cinfo.output_scanline 解码的当前行  cinfo.output_height 图像的总行数
  while (cinfo.output_scanline < cinfo.output_height)
  {

    (void)jpeg_read_scanlines(&cinfo, buffer, 1);

    char *p = buffer[0]; // 指向解码后的RGB 数据
    for (int x = 0; x < width; x++)
    {
      argb[y * width * 4 + 2 + x * 4] = buffer[0][0 + x * 3]; // R
      argb[y * width * 4 + 1 + x * 4] = buffer[0][1 + x * 3]; // G
      argb[y * width * 4 + 0 + x * 4] = buffer[0][2 + x * 3]; // B
      argb[y * width * 4 + 3 + x * 4] = 0;
    }
    y++;
  }

  // 把LCD 转换为二维数组
  int(*lcd)[800] = lcd_addr;

  // 把argb 转换为二维数组
  int(*color)[width] = (void *)argb;

  for (int y = 0; y < height; y++)
  {
    for (int x = 0; x < width; x++)
    {
      if (y < 480 && x < 800) // 限制显示范围
      {
        lcd[y][x] = color[y][x]; // 把小图的对应像素点放入屏幕的对应位置
      }
    }
  }

  /* Step 7: 结束解码 */
  (void)jpeg_finish_decompress(&cinfo);
  // 销毁解码对象
  jpeg_destroy_decompress(&cinfo);
  // 关闭文件
  fclose(infile);

  return 1;
}

void *inin_lcd()
{
    // 1.打开LCD 设备
    int lcd = open("/dev/fb0", O_RDWR);
    if (lcd == -1)
    {
        perror("打开 /dev/fb0 失败");
        exit(0);
    }

    // 定义LCD 设备信息结构体
    struct fb_var_screeninfo varinfo;
    // FBIOGET_VSCREENINFO 获取屏幕参数命令,成功后会把屏幕的所有信息放入varinfo结构体中
    if (ioctl(lcd, FBIOGET_VSCREENINFO, &varinfo) != 0)
    {
        perror("获取LCD设备可变属性信息失败");
        return 0;
    }

    // 根据获取的参数映射 映射的length 多少个字节?? varinfo.xres*varinfo.yres*varinfo.bits_per_pixel/4
    // 32/8 = 4
    void *lcd_p = mmap(NULL, varinfo.xres * varinfo.yres * varinfo.bits_per_pixel / 8, PROT_READ | PROT_WRITE,
                       MAP_SHARED, lcd, 0);

    close(lcd);

    // 返回映射地址
    return lcd_p;
}

int main()
{
    //初始化lcd设备
    void *lcd = inin_lcd();

    read_JPEG_file(lcd, adr_jpg);

    return;
}

编译时注意,以下仅供参考

arm-linux-gcc main.c -o main -I /home/gec/jpeglib/include  -L /home/gec/jpeglib/lib -ljpeg
参数解析:
-I/home/gec/jpeglib/include #指定头文件所在路径
-L/home/gec/jpeglib/lib #指定库文件所在路径
-ljpeg #指定库的名称

总结

以上就是关于这两种图片格式的解压总结,如有不足请指教,本人初学嵌入式,写文章一是为了总结回顾,二是为了方便日后翻阅查看。文章来源地址https://www.toymoban.com/news/detail-734688.html

到了这里,关于关于bmp、jpg格式图片的解码的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 让dedecms织梦后台支持上传bmp格式的图片的教程

    在后台-系统-附件设置,里面添加了bmp,上传bmp格式图片系统还是会提示你\\\"文件类型不正确!\\\",那么有什么好的解决方法呢,请看下文。 1、后台-系统-附件设置,添加bmp 2、includedialogselect_images_post.php 找到 改成 3、includehelpersupload.helper.php 找到 改成 4、includedialogselect_images.

    2024年02月02日
    浏览(37)
  • Word 文档中的图片另存为 .jpg 格式图片

    ​​​ [1] Yongqiang Cheng, https://yongqiang.blog.csdn.net/

    2024年02月21日
    浏览(39)
  • Python实现: JPG与PNG格式图片间互转

    【注意】转换完成后,转换图会与原图在同一个文件夹,只需按大小进行排列就可以将转换后的图片筛选出来

    2024年02月06日
    浏览(65)
  • 【Python编程】将格式为ppm和pgm的图片批量转换为png或jpg格式的图片

    如果文件夹中有异常图片,则可以使用以下代码从而跳过这些异常图片而不影响转换代码的运行。例如本人在解压时中断而导致的图片异常问题,图片示例如下:

    2024年02月11日
    浏览(58)
  • ps导出bmp|jpg马赛克

    ps导入图片-滤镜-像素化-马赛克 图像-模式-索引颜色-确定合并 文件-存储为-导出bmp格式 备注: 封面来源于免费素材网2.8 million+ Stunning Free Images to Use Anywhere - Pixabay - Pixabay ai马赛克网站PixelMe : Convert your photo into pixelart. (pixel-me.tokyo))

    2024年02月12日
    浏览(45)
  • 怎么在电脑上把jpg改成png?批量图片格式转换器分享推荐

    美工在处理图片时,经常使用png格式图片,所以就会有用到格式转换器(https://www.yasuotu.com/geshi),尤其是在需要处理批量图片的时候,今天介绍的这款批量图片格式转换器,可以在线操作,打开浏览器就能完成png格式转换,非常方便,一起来看一下吧。 使用浏览器搜索【压

    2023年04月24日
    浏览(52)
  • STC51单片机解码433M程序说明

    最近需要用到433M的单片机解码,上网搜了一下。大部分的程序都是基于定时器定时检测。感觉逻辑不够严谨。对于新手理解起来也比较困难。 查看EV1527手册 我是用的240K电阻。得到了每个数据宽度是1.29MS,每个数据宽度为16个LCK,每个LCK宽度大约为80us, 可以算出同步位的高

    2024年02月11日
    浏览(41)
  • 【stm32单片机基础】红外NEC协议解码

    红外通信协议是一种基于红外线的传输技术,广泛使用的家电遥控器几乎都是采用的红外线传输技术,由于红外线为不可见光,对环境影响很小,红外线遥控不会影响其他家用电器,也不会影响临近的无线电设备。红外遥控的编码方式目前广泛使用的是: PWM(脉冲宽度调制)的

    2024年02月01日
    浏览(37)
  • 使用Python代码实现视频(如.MP4)与图片(如.jpg)文件格式的相互转换

    1.使用Python代码将视频文件(.MP4格式)转换为图片(.jpg格式) 对视频进行抽帧操作,将视频逐帧转换为图片(.jpg格式的图片的文件) 此处采取的方法是:对视频.MP4文件 每隔10帧截取一张.jpg格式的图片 需要使用的Python方法cv2在opencv-python库中,下载安装方式; 实现上述功能的

    2024年02月03日
    浏览(56)
  • esp32单片机在arduino环境下,串口接收解码

    提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 前言 一、pandas是什么? 二、使用步骤 1.引入库 2.读入数据 总结 当主控芯片发送一串数据,但此数据为一串字符串,需要将此字符串翻译成整型数组,以形成指令,控制串口屏。 例如:esp32单

    2024年02月09日
    浏览(43)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包