#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
struct header1 {
unsigned short type;
size_t size;
unsigned short r1;
unsigned short r2;
size_t off;
} __attribute__((packed));
struct header2 {
size_t size;
long width;
long height;
unsigned short planes;
unsigned short bit_count;
unsigned long compression;
size_t img_size;
long x_pels_per_meter;
long y_pels_per_meter;
unsigned long color_used;
unsigned long color_important;
} __attribute__((packed));
typedef struct {
unsigned char r;
unsigned char g;
unsigned char b;
}data24;
typedef struct {
short r;
short g;
short b;
}ERROR;
struct data16 {
unsigned short r:5;
unsigned short g:6;
unsigned short b:5;
};
void plus_truncate_uchar(unsigned char *a,char b)
{
// printf("xxx=%d\n",*a);
if(int(*a)+b>0xff)*a=0xff;
else if(int(*a)+b<0)*a=0;
else *a+=b;
//printf("yyy=%d\n",*a);
}
int main(int argc, char *argv[])
{
int fd_in, fd_out;
struct header1 in_header1;
struct header2 in_header2;
unsigned char in_buff[3] = {0};
struct data16 out_buff;
size_t i,j, n;
ERROR error;
const unsigned long red_mask = 0xF800ul;
const unsigned long green_mask = 0x07E0ul;
const unsigned long blue_mask = 0x001Ful;
short bmpwidth;
short bmpheight;
data24 **bmpBuf;
if (argc != 3) {
fprintf(stderr, "Wrong usage!\n"
"Tyr %s <Source BMP file> <Destenation BMP file>\n", argv[0]);
return -1;
}
fd_in = open(argv[1], O_RDONLY);
fd_out = open(argv[2], O_WRONLY | O_TRUNC | O_CREAT,
S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
if (fd_in == -1 || fd_out == -1) {
perror("Open file failed");
}
read(fd_in, &in_header1, sizeof(in_header1));
if (in_header1.type != 0x4d42) {
fprintf(stderr, "%s isn't BMP file\n", argv[1]);
goto end;
}
n = (in_header1.size - 54) / 3;
in_header1.size = n * 2 + 54 + 12;
in_header1.off += 12;
read(fd_in, &in_header2, sizeof(in_header2));
if (in_header2.bit_count != 24) {
fprintf(stderr, "The BMP file %s isn't 24 bit.\n", argv[1]);
goto end;
}
in_header2.bit_count = 16;
in_header2.compression = 3ul;
in_header2.img_size = in_header2.img_size / 3 * 2;
write(fd_out, &in_header1, sizeof(in_header1));
write(fd_out, &in_header2, sizeof(in_header2));
write(fd_out, &red_mask, sizeof(red_mask));
write(fd_out, &green_mask, sizeof(green_mask));
write(fd_out, &blue_mask, sizeof(blue_mask));
n /= 100;
i = 0;
bmpwidth=in_header2.width;
bmpheight=in_header2.height;
bmpBuf = new data24 *[bmpheight];
bmpBuf[0] = new data24 [bmpwidth*bmpheight];
for (short i = 0; i<bmpheight; i++) bmpBuf[i]=bmpBuf[0] + bmpwidth*i;
printf("bmpwidth=%d bmpheight=%d \n",bmpwidth,bmpheight);
for(i=0;i<bmpheight;i++)
for(j=0;j<bmpwidth;j++){
//printf("%d %d \n",i,j);
read(fd_in, in_buff, sizeof(in_buff));
bmpBuf[i][j].r=in_buff[0];
bmpBuf[i][j].g=in_buff[1];
bmpBuf[i][j].b=in_buff[2];
}
printf("\ndither ing ...\n");
//////////////////////////////////////////////////////////////////////
for(i=0;i<bmpheight;i++)
for(j=0;j<bmpwidth;j++){
error.r=bmpBuf[i][j].r & 0x07;
////////////////////////////
if(error.r>=4){
if((int)bmpBuf[i][j].r + 0x08>0xff)bmpBuf[i][j].r=0xff;
else bmpBuf[i][j].r += 0x08;
error.r-=0x08;
}
////////////////////////////
error.g=bmpBuf[i][j].g & 0x03;
if(error.g>=2){
if((int)bmpBuf[i][j].g + 0x04>0xff)bmpBuf[i][j].g=0xff;
else bmpBuf[i][j].g += 0x04;
error.g-=0x04;
}
////////////////////////////
error.b=bmpBuf[i][j].b & 0x07;
if(error.b>=4){
if((int)bmpBuf[i][j].b + 0x08>0xff)bmpBuf[i][j].b=0xff;
else bmpBuf[i][j].b += 0x08;
error.b-=0x08;
}
//if(j<10)printf("%d %d %d |%d %d %d \n",bmpBuf[i][j].r,bmpBuf[i][j].g,bmpBuf[i][j].b,error.r,error.g,error.b);
////////////////////////////
if(j+1<bmpwidth)plus_truncate_uchar(&bmpBuf[i][j+1].r,(error.r*7)>>4);
if(i+1<bmpheight){
if (j-1 >0)plus_truncate_uchar(&bmpBuf[i+1][j-1].r,(error.r*3)>>4);
plus_truncate_uchar(&bmpBuf[i+1][j].r,(error.r*5)>>4);
if (j+1 <bmpwidth)plus_truncate_uchar(&bmpBuf[i+1][j+1].r,(error.r*1)>>4);
}
////////////////////////////
if(j+1<bmpwidth)plus_truncate_uchar(&bmpBuf[i][j+1].g,(error.g*7)>>4);
if(i+1<bmpheight){
if (j-1 >0)plus_truncate_uchar(&bmpBuf[i+1][j-1].g,(error.g*3)>>4);
plus_truncate_uchar(&bmpBuf[i+1][j].g,(error.g*5)>>4);
if (j+1 <bmpwidth)plus_truncate_uchar(&bmpBuf[i+1][j+1].g,(error.g*1)>>4);
}
////////////////////////////
if(j+1<bmpwidth)plus_truncate_uchar(&bmpBuf[i][j+1].b,(error.b*7)>>4);
if(i+1<bmpheight){
if (j-1 >0)plus_truncate_uchar(&bmpBuf[i+1][j-1].b,(error.b*3)>>4);
plus_truncate_uchar(&bmpBuf[i+1][j].b,(error.b*5)>>4);
if (j+1 <bmpwidth)plus_truncate_uchar(&bmpBuf[i+1][j+1].b,(error.b*1)>>4);
}
////////////////////////////
}
printf("\nwrite to bmp ...\n");
/////////////////////////////////////////////////////////////////////
for(i=0;i<bmpheight;i++)
for(j=0;j<bmpwidth;j++){
out_buff.r = bmpBuf[i][j].r >> 3;
out_buff.g = bmpBuf[i][j].g >> 2;
out_buff.b = bmpBuf[i][j].b >> 3;
write(fd_out, &out_buff, sizeof(out_buff));
if ((i*bmpheight+j) % n == 0) {
printf("\r %d%%", (i*bmpheight+j) / n);
fflush(stdout);
}
}
printf("\r 100%%\n");
printf("24 bit BMP %s to 16 bit (5-6-5) BMP %s ok!\n", argv[1], argv[2]);
end:
delete[] bmpBuf[0];
delete[] bmpBuf;
close(fd_out);
close(fd_in);
return 0;
}