Created
August 5, 2015 17:22
-
-
Save wf9a5m75/2119dc8536d189a0bd7e to your computer and use it in GitHub Desktop.
Android Screen Capture
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/************************************************/ | |
// 2012.07.12 | |
// Author: pentux | |
// http://android-dev-log.ldblog.jp/archives/11346611.html | |
/************************************************/ | |
#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