Skip to content

Instantly share code, notes, and snippets.

@kamawanu
Created August 26, 2016 01:15
Show Gist options
  • Save kamawanu/bd7692e0e4a6d78a579b1cb00b647f55 to your computer and use it in GitHub Desktop.
Save kamawanu/bd7692e0e4a6d78a579b1cb00b647f55 to your computer and use it in GitHub Desktop.
/************************************************/
// 2012.07.12
// Author: pentux
/************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define PRINT_ERR(str) { fprintf(stdout, str); }
// ヘッダのサイズ
#define FILE_HEADER_SIZE 14
#define WIN_HEADER_SIZE 40
#define OS2_HEADER_SIZE 12
// 1画素あたりのバイト数とピクセル数
#define PXL_BYTE 4
#define BIT_COUNT (PXL_BYTE*8)
// 画面サイズの定義
#define QVGA_X 320
#define QVGA_Y 480
#define WVGA800_X 480
#define WVGA800_Y 800
// 画像のサイズ
typedef enum { QVGA, WVGA800 } IMG_SIZE;
// BMP の種類
typedef enum { WIN, OS2 } BMP_TYPE;
// 型変換
typedef unsigned char byte;
typedef unsigned int uint;
// 内部関数群
byte *read_byte_data(char *path, uint *size);
uint write_byte_data(char *path, byte *data, uint size);
BMP_TYPE select_bmp_type(char *type);
IMG_SIZE select_img_size(char *size);
byte *add_bmp_header(uint *bmp_data_size, byte *data, uint size, BMP_TYPE bmp_type, IMG_SIZE img_size);
byte *create_header(uint *header_data_size, uint data_size, BMP_TYPE bmp_type, IMG_SIZE img_size);
uint get_info_header_size(BMP_TYPE bmp_type);
byte *create_info_header(BMP_TYPE bmp_type, IMG_SIZE img_size);
uint get_img_size_x(IMG_SIZE img_size);
uint get_img_size_y(IMG_SIZE img_size);
byte *inverse_top_bottom(byte *data, uint data_size, uint width);
byte *convert_fb_data(byte *data, uint data_size);
void convert16to32(byte dst[], byte src[]);
/**
* Main
*/
int main(int argc, char *argv[]){
if(argc != 5){
printf("Usage: add_bmp_header [dst_path] [src_path] [bmp_type] [bmp_size]\n"
"\tbmp_type : WIN or OS2\n"
"\tbmp_size : WVGA800, QVGA\n");
return 1;
}
char *dst_path = argv[1];
char *src_path = argv[2];
BMP_TYPE bmp_type = select_bmp_type(argv[3]);
IMG_SIZE img_size = select_img_size(argv[4]);
uint data_size = 0;
byte *data = read_byte_data(src_path, &data_size);
byte *tmp_data = NULL;
// Convert frame buffer data.
tmp_data = convert_fb_data(data, data_size);
if(tmp_data == NULL){
PRINT_ERR("Error of converting fb data.\n");
if(data != NULL){
free(data);
}
return 1;
}
free(data);
data = tmp_data;
// Inverse bmp data
tmp_data = inverse_top_bottom(data, data_size, get_img_size_x(img_size));
if(tmp_data == NULL){
PRINT_ERR("Error of inversing original bmp data.\n");
if(data != NULL){
free(data);
}
return 1;
}
free(data);
data = tmp_data;
// Add header
uint bmp_data_size = 0;
byte *bmp_data = add_bmp_header(&bmp_data_size, data, data_size, bmp_type, img_size);
write_byte_data(dst_path, bmp_data, bmp_data_size);
free(data);
free(bmp_data);
return 0;
}
byte *convert_fb_data(byte *data, uint data_size){
byte *converted = (byte *)calloc(sizeof(byte), data_size);
uint i = 0;
for(i = 0; i < data_size/2; i+=2){
convert16to32(converted+i*2, data+i);
}
return converted;
}
/**
* Convert RGB565 into RGB888
* dst:4byte, src:2byte
*/
void convert16to32(byte dst[], byte src[]){
uint tmp = src[0] + (src[1] << 8);
byte b = (tmp & 0x001F) >> 0;
byte g = (tmp & 0x07E0) >> 5;
byte r = (tmp & 0xF800) >> 11;
dst[0] = b * 255/32;
dst[1] = g * 255/64;
dst[2] = r * 255/32;
dst[3] = 0;
}
/**
* Inverse order data between top and bottom.
*/
byte *inverse_top_bottom(byte *data, uint data_size, uint width){
byte *inversed = (byte *)malloc(sizeof(byte) * data_size);
uint i = 0;
uint height = data_size / width / PXL_BYTE;
for(i = 0; i < height; i++){
uint j = 0;
for(j = 0; j < width*PXL_BYTE; j++){
inversed[(height-1-i)*width*PXL_BYTE + j] = data[i*width*PXL_BYTE + j];
}
}
return inversed;
}
/**
* Create BMP header info.
*/
byte *create_header(uint *header_size, uint data_size, BMP_TYPE bmp_type, IMG_SIZE img_size){
(*header_size) = FILE_HEADER_SIZE + get_info_header_size(bmp_type);
uint all_size = data_size + (*header_size);
byte mask = 0xFF;
// file header
byte file_header[FILE_HEADER_SIZE] = {0};
// File Type
file_header[0] = 'B';
file_header[1] = 'M';
// File Size
file_header[2] = all_size & mask;
file_header[3] = (all_size >> (sizeof(byte)*1*8)) & mask;
file_header[4] = (all_size >> (sizeof(byte)*2*8)) & mask;
file_header[5] = (all_size >> (sizeof(byte)*3*8)) & mask;
// Reserved
file_header[6] = 0;
file_header[7] = 0;
file_header[8] = 0;
file_header[9] = 0;
// Offset from TopData to ImageData
file_header[10] = (*header_size) & mask;
file_header[11] = ((*header_size) >> (sizeof(byte)*1*8)) & mask;
file_header[12] = ((*header_size) >> (sizeof(byte)*2*8)) & mask;
file_header[13] = ((*header_size) >> (sizeof(byte)*3*8)) & mask;
// info header
byte *info_header = create_info_header(bmp_type, img_size);
// Concat file_hader and info_header
byte *header_data = (byte *)malloc(sizeof(byte) * all_size);
memcpy(header_data, file_header, sizeof(byte) * FILE_HEADER_SIZE);
memmove(header_data+sizeof(byte)*FILE_HEADER_SIZE, info_header, sizeof(byte)*get_info_header_size(bmp_type));
return header_data;
}
uint get_img_size_x(IMG_SIZE img_size){
switch(img_size){
case QVGA: return QVGA_X;
case WVGA800: return WVGA800_X;
default: return -1;
}
}
uint get_img_size_y(IMG_SIZE img_size){
switch(img_size){
case QVGA: return QVGA_Y;
case WVGA800: return WVGA800_Y;
default: return -1;
}
}
byte *create_info_header(BMP_TYPE bmp_type, IMG_SIZE img_size){
byte mask = 0xFF;
byte *info_header = NULL;
info_header = (byte *)malloc(sizeof(byte)*get_info_header_size(bmp_type));
uint x = get_img_size_x(img_size);
uint y = get_img_size_y(img_size);
switch(bmp_type){
case OS2:
// Size
info_header[0] = OS2_HEADER_SIZE;
info_header[1] = 0;
info_header[2] = 0;
info_header[3] = 0;
// Width
info_header[4] = x & mask;
info_header[5] = (x >> (sizeof(byte)*1*8)) & mask;
// Height
info_header[6] = y & mask;
info_header[7] = (y >> (sizeof(byte)*1*8)) & mask;
// Planes
info_header[8] = 1;
info_header[9] = 0;
// BitCount
info_header[10] = BIT_COUNT;
info_header[11] = 0;
break;
case WIN:
// Size
info_header[0] = WIN_HEADER_SIZE;
info_header[1] = 0;
info_header[2] = 0;
info_header[3] = 0;
// Width
info_header[4] = x & mask;
info_header[5] = (x >> (sizeof(byte)*1*8)) & mask;
info_header[6] = (x >> (sizeof(byte)*2*8)) & mask;
info_header[7] = (x >> (sizeof(byte)*3*8)) & mask;
// Height
info_header[8] = y & mask;
info_header[9] = (y >> (sizeof(byte)*1*8)) & mask;
info_header[10] = (y >> (sizeof(byte)*2*8)) & mask;
info_header[11] = (y >> (sizeof(byte)*3*8)) & mask;
// Planes
info_header[12] = 1;
info_header[13] = 0;
// BitCount
info_header[14] = BIT_COUNT;
info_header[15] = 0;
// Compression
info_header[16] = 0;
info_header[17] = 0;
info_header[18] = 0;
info_header[19] = 0;
// Size of Image part
info_header[20] = 0;
info_header[21] = 0;
info_header[22] = 0;
info_header[23] = 0;
// Pixel per Meter X
info_header[24] = 0;
info_header[25] = 0;
info_header[26] = 0;
info_header[27] = 0;
// Pixel per Meter Y
info_header[28] = 0;
info_header[29] = 0;
info_header[30] = 0;
info_header[31] = 0;
// Used palet num
info_header[32] = 0;
info_header[33] = 0;
info_header[34] = 0;
info_header[35] = 0;
// Important palet index
info_header[36] = 0;
info_header[37] = 0;
info_header[38] = 0;
info_header[39] = 0;
break;
}
return info_header;
}
uint get_info_header_size(BMP_TYPE type){
switch(type){
case WIN: return WIN_HEADER_SIZE;
case OS2: return OS2_HEADER_SIZE;
default: return WIN_HEADER_SIZE;
}
}
/**
* Create BMP header and add on head of bmp binary data.
* args :
* return:
*/
byte *add_bmp_header(uint *bmp_data_size, byte *data, uint data_size, BMP_TYPE bmp_type, IMG_SIZE img_size){
if(data == NULL){
PRINT_ERR("Error. No original byte data in add_bmp_header().\n");
return NULL;
}
// create header data
uint header_size = 0;
byte *header_data = create_header(&header_size, data_size, bmp_type, img_size);
// concat header_data and read binary data
(*bmp_data_size) = header_size + data_size;
byte *bmp_data = (byte *)calloc(sizeof(byte), (*bmp_data_size));
memcpy(bmp_data, header_data, sizeof(byte)*header_size);
memmove(bmp_data+sizeof(byte)*header_size, data, sizeof(byte)*data_size);
return bmp_data;
}
BMP_TYPE select_bmp_type(char *type){
if(!strcmp(type, "WIN")){
return WIN;
}else if(!strcmp(type, "OS2")){
return OS2;
}
return WIN;
}
IMG_SIZE select_img_size(char *size){
if(!strcmp(size, "QVGA")){
return QVGA;
}else if(!strcmp(size, "WVGA800")){
return WVGA800;
}
return WVGA800;
}
/**
* Read byte data from binary file.
*/
byte *read_byte_data(char *path, uint *size){
if(path == NULL){
PRINT_ERR("Read file path error.\n");
return NULL;
}
FILE *fp = NULL;
if((fp = fopen(path, "rb")) == NULL){
PRINT_ERR("Reading file open error.\n");
return NULL;
}
(*size) = 0;
byte d = 0;
byte *data = NULL;
byte *tmp_data = NULL;
while(fread(&d, sizeof(byte), 1, fp) == 1){
(*size) += 1;
tmp_data = (byte *)realloc(data, sizeof(byte)*(*size));
if(tmp_data == NULL){
PRINT_ERR("Realloc Error.\n");
if(data != NULL)
free(data);
return NULL;
}
data = tmp_data;
data[*size-1] = d;
}
fclose(fp);
return data;
}
/**
* Write byte data into binary file.
* args : target_file_path, write_data, write_data_size
* return: wrote data size
*/
uint write_byte_data(char *path, byte *data, uint size){
if(path == NULL){
PRINT_ERR("Write file path error.\n");
return -1;
}
FILE *fp = NULL;
if((fp = fopen(path, "wb")) == NULL){
PRINT_ERR("Write file open error.\n");
return -1;
}
uint i = 0;
for(i = 0; i < size; i++)
fwrite(data+i, sizeof(byte), 1, fp);
fclose(fp);
return i;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment