24位BMP 转 16位BMP-RGB565 代码

由于需要bpp-16 的BMP文件,只是现在Window 10自带的画图程序没法直接转换出来。只好上网找下代码,去转原24-bit 的BMP出来。找了好几个程序,转出来的东西都无法显示,没办法只得自己研究下,搞了一下午,总算把这些代码的窟窿都堵上了,差不多重写了一遍,实测成功!
分享给其他有同样需求的人。

     编译: c++ -o convert_bmp  /mnt/hgfs/WIN_D/share/convert_bmp24to16.cpp

    测试:./convert_bmp  1.bmp 

SrcCode: convert_bmp24to16.cpp

/*
 *  24位深的bmp图片转换为16位深RGB565格式的bmp图片
 *  Original: from network
 *  Modified by Golden.Chen 2019/02/16
 */
#include <iostream>
#include <stdio.h>
#include <string.h>

using namespace std;

typedef unsigned char  uint8;
typedef unsigned short uint16; //32bit system
typedef unsigned int   uint32;//32bit system

#define SRC_BMP_BPP    24   /* bits per pixel */
#define DST_BMP_BPP    16

struct bmp_filehead //size: 14B
{
    uint16 bmtype; //0x424d ='BM'
    uint16 bmtotalsize; //total file size 
    uint16 bmtotalsizeH;
    uint16 bmReserved;//reserve word,fixed to : 0x0000
    uint16 bmReservedH; 
    uint16 bmOffBits;//offset of image data
    uint16 bmOffBitsH;
}bmphead;

struct bmp_infohead //size: 40B
{
    uint32 bmpheadsize;//size of infoheader
    uint32 bmp_width;//image width
    uint32 bmp_height;//image height
    uint16 bmplans;//planes,0 or 1
    uint16 bitcount;//bits per pixel,24
    uint32 compress_type;/* 0 - rgb, 1 - rle8, 2 - rle4, 3 - BITFEILDS */
    uint32 imagesize;//size of image data

    uint32 biXPelsPerMeter;
    uint32 biYPelsPerMeter;
    uint32 biClrUsed;
    uint32 biClrImportant;
}infohead;

int bmp565_write_header(struct bmp_filehead *pfhd,struct bmp_infohead *pinfo,FILE *fp)
{
	int ret;
	uint32 widthsize,head_size,imgdata_offset;
	uint8 rgb_mask[12] = {// RGBQUAD MASK     
        	0x00, 0xF8, 0x00, 0x00, //red mask     
 		0xE0, 0x07, 0x00, 0x00, //green mask    
		0x1F, 0x00, 0x00, 0x00  //blue mask
	}; 
	
	widthsize = (((uint32)pinfo->bmp_width * DST_BMP_BPP + 31) >> 5) << 2;
	head_size = sizeof(struct bmp_filehead) + sizeof(struct bmp_infohead) + sizeof(rgb_mask);

	/* base on src data ,initialize bmp_infoheader*/
	pinfo->bitcount = DST_BMP_BPP;
	pinfo->compress_type = 3 ; //only valid when BPP == 16 or 32
	pinfo->imagesize = pinfo->bmp_height * widthsize;
	pinfo->biXPelsPerMeter = 0;
	pinfo->biYPelsPerMeter = 0;
	pinfo->biClrUsed = 0;
	pinfo->biClrImportant = 0;

	/* base on src data ,initialize bmp_fileheader*/
	pfhd->bmtotalsize  = (head_size + pinfo->imagesize) & 0xFFFF;
	pfhd->bmtotalsizeH = (head_size + pinfo->imagesize) >> 16;
	pfhd->bmOffBits  = head_size & 0xFFFF;
	pfhd->bmOffBitsH = head_size >> 16;

	//write header data to fp
	ret = fwrite(pfhd,  1, sizeof(struct bmp_filehead), fp);
	if(ret != sizeof(struct bmp_filehead)) return -1;

	ret = fwrite(pinfo, 1, sizeof(struct bmp_infohead), fp);
	if(ret != sizeof(struct bmp_infohead)) return -1;

	ret = fwrite(rgb_mask, 1, sizeof(rgb_mask), fp);
	if(ret != sizeof(rgb_mask)) return -1;

	return 0;
}

#define bmp565_write_imgdata(buf,block,count,fp)  \
	fwrite(buf, block, count, fp);

int main(int argc, char *argv[])
{
	FILE *src_fp,*dst_fp;
	char src_file[64] = "";
	char dst_file[64] = "";
	uint8 *imagebuf=NULL,*bmpwidbuf=NULL;
	uint32 src_widsize,dst_widsize;
	uint16 k,q,d;
	int ret=0,n;

	if(argc < 2)
	{
		printf("\nUsage: %s <src file> \n",argv[0]);
		printf("\n       %s <src file>  <output file>\n",argv[0]);
		return -1;
	}

	strcpy(src_file, argv[1]);
	if(argc == 3) {
		strcpy(dst_file, argv[2]);
		cout << "dst file name : " << dst_file << endl;
	} else {
		strncpy(dst_file, src_file, strlen(src_file)-4);
		strcat(dst_file, "_rgb565.bmp");
		cout << "dst file default name : " << dst_file << endl;
	}


	if((src_fp=fopen(src_file,"r")) == NULL) {
		cout<<"Can't Open file: "<< src_file <<endl;
		return -1;
	} 
	if((dst_fp=fopen(dst_file,"wb")) == NULL){
		fclose(src_fp);
		cout<<"Fail to Open dst file: "<< dst_file <<endl;
		return -1;
	}

	fseek(src_fp, 0, 0);//fseek(src_fp, offset, fromwhere);
	ret=fread(&bmphead,sizeof(uint8),sizeof(bmphead),src_fp);
	if(ret != sizeof(bmphead)) {
		cout<<"read bmp header failed!"<<endl;
		goto out_err;
	}

	ret=fread(&infohead,sizeof(uint8),sizeof(infohead),src_fp);
	if(ret != sizeof(infohead)) {
		cout<<"read bmp info header failed!"<<endl;
		goto out_err;
	}

	if(infohead.bitcount != SRC_BMP_BPP) {
		printf("Error: unsupport bpp%d, only support 24-bit bmp!",infohead.bitcount);
		goto out_err;
	}

	printf("filesize: %ld, dataoffset: %ld, imagesize: %d\nimage Width: %d, Height: %d\n", \
		(long)(bmphead.bmtotalsize | (bmphead.bmtotalsizeH<<16)),  \
		(long)(bmphead.bmOffBits | (bmphead.bmOffBitsH<<16)),  \
		infohead.imagesize, infohead.bmp_width,infohead.bmp_height);

	/* seek to offset indicated by file header */
	fseek(src_fp, (long)(bmphead.bmOffBits|(bmphead.bmOffBitsH<<16)), SEEK_SET);

	/* Please note : BMP width size is 4-bytes aliagn in fact */
	src_widsize = ((infohead.bmp_width * infohead.bitcount + 31)>>5)<<2;
	if((bmpwidbuf=(uint8 *)malloc(src_widsize)) == NULL) {
		cout << "Fail to malloc bmpwidbuf!"<<endl;
		goto out_err;
	}
	dst_widsize = ((infohead.bmp_width * DST_BMP_BPP + 31)>>5)<<2;
	if((imagebuf=(uint8 *)malloc(dst_widsize * infohead.bmp_height)) == NULL) {
		cout << "Fail to malloc imagebuf!"<<endl;
		goto out_err;
	}

	for(k=0,n=0;k<infohead.bmp_height;k++) {
		ret = fread(bmpwidbuf,sizeof(uint8),src_widsize,src_fp);
		if(ret != src_widsize) {
			cout<<"read bmp data failed !" <<endl;
			goto out_err;
		}
		for(q=0;q<infohead.bmp_width;q++) {
		    d =  ((uint16)(bmpwidbuf[3*q + 2]>>3)<<11)//R G B
			+((uint16)(bmpwidbuf[3*q + 1]>>2)<<5)
			+ (uint16)(bmpwidbuf[3*q + 0]>>3);
		    imagebuf[n++] = d & 0xff;
		    imagebuf[n++] = d >> 8;
		}
		while(n%dst_widsize != 0) imagebuf[n++] = 0x00;
	}

	fclose(src_fp);
	free(bmpwidbuf);

	cout<<"write bmp 565 start !"<<endl;
	fseek(dst_fp, 0, SEEK_SET);
	ret = bmp565_write_header(&bmphead, &infohead, dst_fp);
	if(!ret) 
		ret = bmp565_write_imgdata(imagebuf, dst_widsize,infohead.bmp_height, dst_fp);
	if(ret != infohead.bmp_height)
		cout<<"write bmp 565 fail!"<<endl;
	else
		cout<<"write bmp 565 success!"<<endl;

	fclose(dst_fp);
	free(imagebuf);
	return 0;
	
out_err:
	if(imagebuf) free(imagebuf);
	if(bmpwidbuf) free(bmpwidbuf);
	fclose(src_fp);
	fclose(dst_fp);
	return -1;
}

 

  • 2
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 要实现24BMP8BMP,需要进行以下步骤: 首先,读取24BMP文件的头部信息,包括文件大小、宽度、高度和颜色数等信息。可以使用相关的bmp库或者自定义函数来读取头部信息。 接下来,创建一个新的8BMP文件,并设置其头部信息。新文件的宽度和高度与原文件相同,但是颜色数为8。 然后,需要对每个像素点进行颜色换。由于8BMP只能表示256种颜色,而24BMP可以表示更多的颜色,因此需要将24颜色值映射到8颜色值。这可以通过查表的方式实现。可以创建一个颜色映射表,包含256个颜色值,将原24颜色对应地映射到8颜色。 接下来,遍历所有像素点,将24颜色值换为对应的8颜色值。可以使用像素点的RGB值在颜色映射表中查找对应的索引,得到8颜色值,并将其写入新的8BMP文件。 最后,将新的8BMP文件保存到指定的路径中。 需要注意的是,在颜色换过程中可能会出现颜色丢失的情况。因为8BMP只能表示256种颜色,而24BMP可以表示更多的颜色,所以在换过程中,可能会出现某些颜色无法准确映射的情况。可以考虑使用一些颜色量化算法,如误差扩散等,来尽量减少颜色丢失的程度。 ### 回答2: 将24BMP换为8BMP可以简单地理解为将每个像素点的RGB换为相应的8灰度值。下面是一种可能的实现方法: 1. 读取24BMP文件的头部信息,包括图像的宽度、高度和像素深度等。 2. 创建一个新的8BMP文件,并设置相应的头部信息,如宽度、高度和像素深度为8。 3. 遍历24BMP文件中的每个像素点。 4. 对于每个像素点,获取其RGB值,即红色、绿色和蓝色的分量。 5. 将RGB换为灰度值,可以使用以下公式:Gray = (0.299 * R) + (0.587 * G) + (0.114 * B),其中R、G和B分别表示红、绿和蓝的分量值。 6. 将灰度值存储到新创建的8BMP文件对应的像素点置。 7. 重复步骤3-6,直到遍历完所有的像素点。 8. 将换后的8BMP文件保存到磁盘上。 这样,就完成了将24BMP文件转换成8BMP文件的过程。通过将RGB换为灰度值,可以将原本的24色彩表示缩减为256级灰度表示,实现了从24BMP到8BMP换。 ### 回答3: 实现24BMP8BMP的过程中,主要需要做以下几个步骤: 1. 首先读取24BMP文件的头文件信息,包括图像的宽度、高度、颜色深度等信息。 2. 创建一个8BMP文件的头文件,并将相应的信息填写进去,包括图像的宽度、高度、颜色深度等。 3. 创建一个256色的调色板,用来储存颜色索引值。这里需要注意,由于8BMP最大只能表示256种颜色,所以需要对原始24BMP中的所有颜色进行量化处理,将其映射到256色调色板中。 4. 逐个像素地将24BMP图像中的RGB值映射到对应的索引值,并写入到8BMP文件中,形成新的图像。 5. 最后保存修改后的8BMP文件。 在实现的过程中,我们可以使用编程语言如C或Python来进行操作。通过读取和写入文件的操作,以及相应的数值处理和运算等操作,可以实现24BMP8BMP的功能。 总之,实现24BMP8BMP需要读取原始BMP的图像信息,创建8BMP文件头部和调色板,对原始颜色进行量化处理和映射,最后将映射后的颜色值写入新的8BMP文件中。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值