原理

JPEG图像的存储压缩结构

参考链接:https://www.zhihu.com/question/22116845/answer/22998727
来源:知乎

JPEG文件的格式是分为一个一个的段来存储的(但并不是全部都是段),段的多少和长度并不是一定的。只要包含了足够的信息,该JPEG文件就能够被打开,呈现给人们。

JPEG文件的每个段都一定包含两部分:

① 段的标识,它由两个字节构成:第一个字节是十六进制0xFF,第二个字节对于不同的段,这个值是不同的。

② 紧接着的两个字节存放的是这个段的长度(除了前面的两个字节0xFF和0xXX,X表示不确定。他们是不算到段的长度中的。这个长度的表示方法是按照高位在前,低位在后的,与Intel的表示方法不同。比方说一个段的长度是0x12AB,那么它会按照0x12,0xAB的顺序存储。但是如果按照Intel的方式:高位在后,低位在前的方式会存储成0xAB,0x12,而这样的存储方法对于JPEG是不对的。

APP0段中主要存储的是图片的识别信息(字符串”JFIF\0”)、一些分辨率的信息以及缩略图的信息。在我的实际测试中,发现并不是所有的JPEG文件都有APP0段的,有的仅是有APP2之类的其他段,但是每个文件中肯定是包含APPX的段(X可以取得的值可以查阅相关文档)。

DQT段的内容是量化表的信息。众所周知,一个颜色可以分为RGB(红、绿、兰)三个分量,这三色光组成了我们可以见到的所有色彩。但是,在JPEG文件中,RGB色彩格式需要先转化为YUV的格式。Y分量代表了亮度信息,UV分量代表了色差信息。相比之下,人眼对于Y分量更为敏感。量化表的作用就是对于一些不需要的量进行去除,这也是JPEG有损压缩损失数据的关键。上面的输出可以看到两个量化表,一个给Y分量,另一个给UV分量。

SOF0段的内容是图像的大小信息,每个像素的位数信息,以及YUV每个分量分别得的采样信息(这部分如果读者想要进一步学习,请参考相应书籍和文档)。JPEG文件图像的编码是一个方块一个方块进行的,每块的大小为8x8大小(如果图像不是整数个方块的大小那么就对图像补齐为整数个大小)。简略地说采样信息,就是如何按组记录YUV的信息,即若干个Y方块,若干个U方块,若干个V方块经过量化的数据再次经过编码后组成一组记录,保存在SOS段结束后。

DHT段的内容是一个重头戏,如果没有它,JPEG压缩效率就不会那么高了。它内部定义的是一个Huffman表,不同的DHT段定义不同的Huffman表,有的是直流量的表,有的是交流量的表。

所以我从一张BMP图像中读取多组数据,例如图像高度,宽度,灰度等。将JPEG的段在代码中封装为类-class,类中定义数据组,然后从BMP图片中读取数据,不同的数据存在不同的类中的数据组中。

bmp文件

参考链接:https://zhuanlan.zhihu.com/p/260320604

BMP(全称Bitmap)是Windows操作系统中的标准图像文件格式,可以分成两类:设备相关位图(DDB)和设备无关位图(DIB),使用非常广。它采用位映射存储格式,除了图像深度可选以外,不采用其他任何压缩,因此,BMP文件所占用的空间很大。BMP文件的图像深度可选 1bit、4bit、8bit及24bit。BMP文件存储数据时,图像的扫描方式是按从左到右从下到上的顺序。由于BMP文件格式是Windows环境中交换与图有关的数据的一种标准,因此在Windows环境中运行的图形图像软件都支持BMP图像格式。在Windows系统平台上和Android手机上,直接使用系统默认的图片浏览器即可打开。

BMP文件总共由四个部分构成:

(1)BMP文件头(bmp file header):提供文件的格式、大小等信息

(2)位图信息头(bitmap information):提供图像数据的尺寸、位平面数、压缩方式、颜色索引等信息

(3)调色板(color palette):可选,如使用索引来表示图像,调色板就是索引与其对应的颜色的映射表,在使用 256位彩色、16位彩色等情况下用到

(4)位图数据(bitmap data):就是图像的像素数据

1、BMP文件头部分

固定占用14个字节,包括文件类型表示、文件大小、像素数据偏移等信息

2、位图信息头

固定占用40个字节,包含了图像的基本新,例如:像素的宽度、高度、色彩格式位数、是否有压缩(绝大部分情况下无压缩)等。

3、调色板信息

这一项是可选项,适用于索引方式伪彩色的图像数据。调色板其实是一张映射表,标识颜色索引号与其代表的颜色的对应关系。总共有256个索引,每个索引对应一个RGBA四字节的色彩值,而后续位图数据只需要保存每个像素点的索引,根据索引找到对应的RGBA数据值。根据索引列表大小,该部分信息总计占用 256*4=1024个字节。

4、位图数据

这部分存放的就是详细的每个像素的RGB或者RGBA数据。存放顺序从左到右、从下到上的顺序存放。 这里有两点需要注意一下:

(1)像素RGB值存放时,先存放图像最下面一行数据,然后再存放下面倒数第二行数据,所以存放顺序是倒的,这个跟正常浏览顺序不一样。

(2)每一行像素数据需要保证4字节对齐,不对齐的需要补充空字节,这个是BMP文件格式本身要求的。对于RGBA 32位色彩格式来说没有任何问题,但是对于Gray或者RGB格式的数据 ,有时一行像素需要补充一些空字节。例如:对于宽高为 322*240 像素的RGB数据,正常计算一行像素数据需要 322 * 3= 966字节,但是966不是四字节对齐,所以在存储时,每行的像素数据要保存为 968字节,最后2个字节保留。

bmp读写操作代码

//
// Bmp file structure
//
#define XBMP_FILEHDR_LEN        14
typedef struct _tag_XBmpFileHeader
{uint16_t      bfType;uint32_t      bfSize;uint16_t      bfReserved1;uint16_t      bfReserved2;uint32_t      bfOffBits;
}XBMPFILE_HEADER, *LPXBMPFILE_HEADER;#define XBMP_INFOHDR_LEN        40
typedef struct _tag_XBMPINFO_HEADER
{uint32_t      biSize;int32_t        biWidth;int32_t        biHeight;uint16_t      biPlanes;uint16_t      biBitCount;uint32_t      biCompression;uint32_t      biSizeImage;int32_t        biXPelsPerMeter;int32_t        biYPelsPerMeter;uint32_t      biClrUsed;uint32_t      biClrImportant;
} XBMPINFO_HEADER, *LPXBMPINFO_HEADER;#define XBMP_RGBQUAD_LEN        4
typedef struct _tag_XBmp_RGBQUAD
{uint8_t        rgbBlue; uint8_t        rgbGreen;uint8_t        rgbRed;uint8_t        rgbReserved;
} XBMP_RGBQUAD, *LPXBMP_XBMP_RGBQUAD;int32_t XImage::LoadFromBmp(const char* bmp_file_path)
{if (bmp_file_path == nullptr){return XERR_INVALID_PARAM;}FILE* file_handler = fopen(bmp_file_path, "rb");if (file_handler == nullptr){XOS_ERROR(TAG_IMGENG, "<XImage.LoadFromBmp> fail to fopen(), file=%s", bmp_file_path);return XERR_FILE_OPEN;}//// 判断位图文件头结构BITMAPFILEHEADER//XBMPFILE_HEADER  sFileHdr = { 0 };uint8_t szBuffer[255] = { 0 };fread(szBuffer, 1, XBMP_FILEHDR_LEN, file_handler);sFileHdr.bfType = ((uint32_t)szBuffer[0] | (uint32_t)szBuffer[1] << 8);if (0x4D42 != sFileHdr.bfType){XOS_ERROR(TAG_IMGENG, "<XImage.LoadFromBmp> not BM flag, file=%s", bmp_file_path);fclose(file_handler);return XERR_UNSUPPORTED;}//// 读取位图信息头结构变量,读取位图信息头进内存, 存放在变量head中  //XBMPINFO_HEADER  sInfoHdr = { 0 };XBMP_RGBQUAD*  pColorTab = XNULL;memset(szBuffer, 0, 255);fread(szBuffer, 1, XBMP_INFOHDR_LEN, file_handler);sInfoHdr.biSize    = ((uint32_t)szBuffer[0]) | ((uint32_t)szBuffer[1] << 8) | ((uint32_t)szBuffer[2] << 16) | ((uint32_t)szBuffer[3] << 24);sInfoHdr.biWidth  = ((uint32_t)szBuffer[4]) | ((uint32_t)szBuffer[5] << 8) | ((uint32_t)szBuffer[6] << 16) | ((uint32_t)szBuffer[7] << 24);sInfoHdr.biHeight  = ((uint32_t)szBuffer[8]) | ((uint32_t)szBuffer[9] << 8) | ((uint32_t)szBuffer[10] << 16) | ((uint32_t)szBuffer[11] << 24);sInfoHdr.biPlanes  = ((uint32_t)szBuffer[12]) | ((uint32_t)szBuffer[13] << 8);sInfoHdr.biBitCount = ((uint32_t)szBuffer[14]) | ((uint32_t)szBuffer[15] << 8);sInfoHdr.biCompression  = ((uint32_t)szBuffer[16]) | ((uint32_t)szBuffer[17] << 8) | ((uint32_t)szBuffer[18] << 16) | ((uint32_t)szBuffer[19] << 24);sInfoHdr.biSizeImage  = ((uint32_t)szBuffer[20]) | ((uint32_t)szBuffer[21] << 8) | ((uint32_t)szBuffer[22] << 16) | ((uint32_t)szBuffer[23] << 24);sInfoHdr.biXPelsPerMeter= ((uint32_t)szBuffer[24]) | ((uint32_t)szBuffer[25] << 8) | ((uint32_t)szBuffer[26] << 16) | ((uint32_t)szBuffer[27] << 24);sInfoHdr.biYPelsPerMeter= ((uint32_t)szBuffer[28]) | ((uint32_t)szBuffer[29] << 8) | ((uint32_t)szBuffer[30] << 16) | ((uint32_t)szBuffer[31] << 24);sInfoHdr.biClrUsed    = ((uint32_t)szBuffer[32]) | ((uint32_t)szBuffer[33] << 8) | ((uint32_t)szBuffer[34] << 16) | ((uint32_t)szBuffer[35] << 24);sInfoHdr.biClrImportant  = ((uint32_t)szBuffer[36]) | ((uint32_t)szBuffer[37] << 8) | ((uint32_t)szBuffer[38] << 16) | ((uint32_t)szBuffer[39] << 24);////获取图像宽、高、每像素所占位数等信息 //int32_t bmp_width  = sInfoHdr.biWidth;int32_t bmp_height = sInfoHdr.biHeight;PXL_FORMAT bmp_pxl_format = PXL_FORMAT_NONE;if (8 == sInfoHdr.biBitCount){bmp_pxl_format = PXL_FORMAT_8BIT_GRAY;}else if (24 == sInfoHdr.biBitCount){bmp_pxl_format = PXL_FORMAT_24BIT_BGR;}else if (32 == sInfoHdr.biBitCount){bmp_pxl_format = PXL_FORMAT_32BIT_BGRA;}else{XOS_ERROR(TAG_IMGENG, "<XImage.LoadFromBmp> unknown pixel format, biBitCount=%d, file=%s",sInfoHdr.biBitCount, bmp_file_path);fclose(file_handler);return XERR_UNSUPPORTED;}if (8 == sInfoHdr.biBitCount)  // 灰度图像有颜色表,且颜色表表项为256色{XOS_ERROR(TAG_IMGENG, "<XImage.LoadFromBmp> not support color 8bit, file=%s", bmp_file_path);fclose(file_handler);return XERR_UNSUPPORTED;  // 目前不支持}// 分配内存空间Allocate(bmp_pxl_format, bmp_width, bmp_height);// 逐行读取像素数据, 注意: .bmp文件中像素数据时先存放最后一行,然后逐步到第一行, 是反向的uint8_t* pixel_line = (uint8_t*)(image_data_ + (height_ - 1) * line_bytes_);for (int32_t i = 0; i < height_; i++){fread(pixel_line, 1, line_bytes_, file_handler);pixel_line -= line_bytes_;}fclose(file_handler);return XOK;
}int32_t XImage::SaveToBmp(const char* save_bmp_file)
{FILE* file_handler = fopen(save_bmp_file, "wb");if (file_handler == nullptr){XOS_ERROR(TAG_IMGENG, "<XImage.SaveToBmp> fail to fopen(), file=%s", save_bmp_file);return XERR_FILE_OPEN;}// YUV图像数据直接保存原始数据if (pxl_format_ & PXL_FORMAT_TYPE_YUV){fwrite(image_data_, 1, image_bytes_, file_handler);fclose(file_handler);return XOK;}// 写入文件头信息int32_t  bit_count  = pixel_bytes_ * 8;uint16_t temp_16bit = 0x4D42;uint32_t temp_32bit = static_cast<uint32_t>(54 + line_bytes_ * height_);if (bit_count == 8)temp_32bit += XBMP_RGBQUAD_LEN * 256;else if (bit_count == 16)temp_32bit += 16;fwrite(&temp_16bit, 1, 2, file_handler);fwrite(&temp_32bit, 1, 4, file_handler);// 写入bitmap信息temp_16bit = 0;temp_32bit = 54;if (bit_count == 8)temp_32bit += XBMP_RGBQUAD_LEN * 256;else if (bit_count == 16)temp_32bit += 16;fwrite(&temp_16bit, 1, 2, file_handler);fwrite(&temp_16bit, 1, 2, file_handler);fwrite(&temp_32bit, 1, 4, file_handler);if (8 == bit_count){XBMPINFO_HEADER bi = { 0 };bi.biSize = 40;bi.biWidth = width_;bi.biHeight = height_;bi.biBitCount = (uint16_t)bit_count;bi.biPlanes = 1;fwrite(&bi, 1, XBMP_INFOHDR_LEN, file_handler);XBMP_RGBQUAD rgb[256];for (int i = 0; i < 256; i++){rgb[i].rgbBlue = (XBYTE)i;rgb[i].rgbGreen = (XBYTE)i;rgb[i].rgbRed = (XBYTE)i;rgb[i].rgbReserved = 0;}fwrite(rgb, 1, XBMP_RGBQUAD_LEN * 256, file_handler);}else{uint32_t    biSize = 40;int32_t      biWidth = width_;int32_t      biHeight = height_;uint16_t    biPlanes = 1;uint16_t    biBitCount = bit_count;uint32_t    biCompression = (bit_count == 16) ? 3 : 0;uint32_t    biSizeImage = 0;int32_t      biXPelsPerMeter = 0;int32_t      biYPelsPerMeter = 0;uint32_t    biClrUsed = 0;uint32_t    biClrImportant = 0;fwrite(&biSize, 1, 4, file_handler);fwrite(&biWidth, 1, 4, file_handler);fwrite(&biHeight, 1, 4, file_handler);fwrite(&biPlanes, 1, 2, file_handler);fwrite(&biBitCount, 1, 2, file_handler);fwrite(&biCompression, 1, 4, file_handler);fwrite(&biSizeImage, 1, 4, file_handler);fwrite(&biXPelsPerMeter, 1, 4, file_handler);fwrite(&biYPelsPerMeter, 1, 4, file_handler);fwrite(&biClrUsed, 1, 4, file_handler);fwrite(&biClrImportant, 1, 4, file_handler);if (bit_count == 16){uint32_t mask[16] = { 0 };mask[0] = 0xF800;mask[1] = 0x7E0;mask[2] = 0x1F;mask[3] = 0;fwrite(mask, 1, 16, file_handler);}}uint8_t* pixel_line = image_data_ + (height_ - 1) * line_bytes_;for (int32_t i = 0; i < height_; i++){fwrite(pixel_line, 1, line_bytes_, file_handler);pixel_line -= line_bytes_;}fclose(file_handler);return XOK;
}

bmp转jpg参考代码

https://www.jb51.net/article/69779.htm

jpg转bmp代码

jpeg转bmp实现c代码__寒潭雁影的博客-CSDN博客_c语言 jpeg转bmp

数字图像处理-bmp与jpeg格式互相转换相关推荐

  1. FFmpeg开发实战(五):bmp转换为jpeg格式图像

    文章目录 1. bmp结构 2. bgr24转yuv420p 3. yuv420转jpeg 4. 下载 本文介绍了将bmp格式图像转换为jpeg格式图像的方法,附有详细的代码和图像示例. 1. bmp ...

  2. Python实现数字图像处理之5种彩色空间转换(单图+多图+视频)

    本文主要运用用Python代码实现了5种彩色空间之间的转换! 具体而言,包括: 1)RGB → CMY: 2)  CMY → RGB: 3)  RGB → HSI: 4)  HSI → RGB: 5) ...

  3. BMP与PPM格式的转换

    /*真彩色bmp格式与PPM-P6之间的转换*/#include<math.h> #include <iomanip> #include <stdlib.h> #i ...

  4. 数字图像处理大作业-BMP文件的读写

    数字图像处理-BMP文件的读写 一.题目背景 二.灰度BMP的读写 1.读入lena.bmp文件 1.1 编写打印文件头信息与信息头数据的函数 2 通过文件内容得到灰度bmp数据信息 2.1 打印信息 ...

  5. 【数字图像处理】一.MFC详解显示BMP格式图片

    本文主要是讲述<数字图像处理>系列栏目中的第一篇文章.主要详细介绍了BMP图片格式,同时使用C++和MFC显示BMP格式,主要结合自己的<数字图像处理>课程和以前的项目叙述讲解 ...

  6. C++图片格式转换:BMP转JPEG

    C++方式将BMP格式转换为JPEG格式,依赖了一个第三方库,工程下载链接为:点击打开链接 Bmp2Jpeg.h: #pragma onceclass CBmp2Jpeg { public:CBmp2 ...

  7. c#如何wmf图片转换成png图片_C#图片格式转换(支持bmp/gif/jpeg/png/tiff/wmf文件)

    [实例简介] [实例截图] [核心代码] using System; using System.Drawing; using System.Collections; using System.Comp ...

  8. 用CxImage将BMP位图转换成JPEG格式

    用CxImage将BMP位图转换成JPEG格式 1.从http://www.xdp.it/download.htm下载cximage600_full. 2.解压cximage600_full,在解压后 ...

  9. 如何把 AI 格式的文件转换成 BMP或者JPEG?

    简 介: 本文给出了将 AI 格式转换成JPEG的方法,经过测试可以看到,在 ZAMZAR 网站, Convertio网站提供的在线转换都获得的不错测结果.但是寻找 Python 转换 AI 文件的方 ...

最新文章

  1. springMVC4(9)属性编辑器剖析入参类型转换原理
  2. python之开发系列
  3. 裸板烧写 bootloader
  4. Spring Ioc源码分析 之 Bean的加载(4):实例化Bean(createBeanInstance()方法)
  5. 文本分类和提取关键词算法_文本内容之间的关键词提取和相似度计算
  6. Linux网络下载管理工具(lftp, ftp, lftpget, wget)
  7. LIN总线协议详解4(进度表)
  8. 喜马拉雅FM下载的音频转换为正常文件的JAVA实现
  9. 王松波 计算机科学,王松波-华南农业大学华南农业大学动物科学学院
  10. 名义利率、实际利率、名义贴现率
  11. jar -cvfM0 暂使用 jar cvf不好用
  12. correl函数相关系数大小意义_用Correl函数返回相关系数,以确定属性关系
  13. 什么是DHT网络(DHT network)
  14. 《寒蝉鸣泣之时:携带版》游戏截图
  15. 头歌--C++之函数进阶练习题
  16. 2058:【例3.10】简单计算器
  17. 路飞学城Python-Day31
  18. abaqus子程序开发学习笔记
  19. 百度贴吧软文引流怎么写?每个贴吧都有自己的中心主题
  20. 自学SQL网题解(0-5课题解)

热门文章

  1. 3D活体识别使用mobilenet_v2训练模型
  2. 神器IDM | 不限速下载到底有多快?
  3. 在Susy和Toolkits上与Miriam Suzanne进行实时问答
  4. viso画图如何调整尺寸大小及设置打印【viso使用技巧篇】
  5. 用计算机外接燃气流量计检查什么,燃气流量计,你知道其中几种
  6. java程序设计谢先伟课后答案_最新网课答案沟通心理学见面课2020知到APP
  7. 高手实例解析蠕虫病毒的原理
  8. 技术人攻略访谈三十九-HTML5社区田爱娜:女神哪有天生,坚守就是一切
  9. Java代码实现百万级数据XLS文件和XLSX文件的读取(已经过测试, 安心使用)
  10. android版本11下载,android 11正式版下载-android 11正式版系统下载-pk38游戏网