From 091d5fb9befc53ee0550dbfc4e08240fe40071e0 Mon Sep 17 00:00:00 2001 From: Jiyong Min Date: Fri, 2 Jun 2017 12:23:22 +0900 Subject: [PATCH] Add to support saving encoded bmp to buffer Image-Util can not save encoded bmp to buffer Change-Id: I130266b2841bb062ad7f18c9166e01dc67366c06 Signed-off-by: Jiyong Min --- src/bmpfile.c | 223 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/bmpfile.h | 1 + 2 files changed, 224 insertions(+) mode change 100644 => 100755 src/bmpfile.c mode change 100644 => 100755 src/bmpfile.h diff --git a/src/bmpfile.c b/src/bmpfile.c old mode 100644 new mode 100755 index 4fb18f4..da264cf --- a/src/bmpfile.c +++ b/src/bmpfile.c @@ -708,3 +708,226 @@ bmp_save(bmpfile_t *bmp, const char *filename) return TRUE; } + +#define BMP_SAFE_FREE(x) { if (x != NULL) { free(x); x = NULL; } } +#define bmp_retm_if(expr, val) do { \ + if (expr) { \ + BMP_SAFE_FREE(val); \ + return; \ + } \ + } while (0) + +#define bmp_retvm_if(expr, val, retv) do { \ + if (expr) { \ + BMP_SAFE_FREE(val); \ + return retv; \ + } \ + } while (0) + +static uint16_t +bmp_write_to_buffer(void *src, unsigned char **dst, size_t *size, size_t *offset, size_t len) +{ + if (src == NULL || len <= 0) + return -1; + + *size += len; + if ((*offset + len) > *size) + return -1; + + if (*dst == NULL) + *dst = (unsigned char *)calloc(1, *size); + else + *dst = (unsigned char *)realloc(*dst, *size); + + if (*dst == NULL) + return -1; + + memcpy(*dst + *offset, src, len); + *offset += len; + + return len; +} + +static void +bmp_write_header2(bmpfile_t *bmp, unsigned char **ptr, size_t *size) +{ + uint16_t ret; + size_t offset = *size; + bmp_header_t header = bmp->header; + + if (_is_big_endian()) bmp_header_swap_endianess(&header); + + ret = bmp_write_to_buffer(header.magic, ptr, size, &offset, sizeof(header.magic)); + bmp_retm_if(ret < 0, *ptr); + ret = bmp_write_to_buffer(&(header.filesz), ptr, size, &offset, sizeof(uint32_t)); + bmp_retm_if(ret < 0, *ptr); + ret = bmp_write_to_buffer(&(header.creator1), ptr, size, &offset, sizeof(uint16_t)); + bmp_retm_if(ret < 0, *ptr); + ret = bmp_write_to_buffer(&(header.creator2), ptr, size, &offset, sizeof(uint16_t)); + bmp_retm_if(ret < 0, *ptr); + ret = bmp_write_to_buffer(&(header.offset), ptr, size, &offset, sizeof(uint32_t)); + bmp_retm_if(ret < 0, *ptr); +} + +static void +bmp_write_dib2(bmpfile_t *bmp, unsigned char **ptr, size_t *size) +{ + uint16_t ret; + size_t offset = *size; + bmp_dib_v3_header_t dib = bmp->dib; + + if (*ptr == NULL) + return; + + if (_is_big_endian()) bmp_dib_v3_header_swap_endianess(&dib); + + ret = bmp_write_to_buffer(&(dib), ptr, size, &offset, sizeof(bmp_dib_v3_header_t)); + bmp_retm_if(ret < 0, *ptr); +} + +static void +bmp_write_palette2(bmpfile_t *bmp, unsigned char **ptr, size_t *size) +{ + uint16_t ret; + size_t offset = *size; + + if (*ptr == NULL) + return; + + if (bmp->dib.depth == 1 || bmp->dib.depth == 4 || bmp->dib.depth == 8) { + int i; + for (i = 0; i < bmp->dib.ncolors; ++i) { + ret = bmp_write_to_buffer(&(bmp->colors[i]), ptr, size, &offset, sizeof(rgb_pixel_t)); + bmp_retm_if(ret < 0, *ptr); + } + } + else if (bmp->dib.depth == 16) { /* the bit masks, not palette */ + uint16_t red_mask = 63488; /* bits 1-5 */ + uint16_t green_mask = 2016; /* bits 6-11 */ + uint16_t blue_mask = 31; /* bits 12-16 */ + uint16_t zero_word = 0; + + if (_is_big_endian()) { + red_mask = UINT16_SWAP_LE_BE_CONSTANT(red_mask); + green_mask = UINT16_SWAP_LE_BE_CONSTANT(green_mask); + blue_mask = UINT16_SWAP_LE_BE_CONSTANT(blue_mask); + } + + ret = bmp_write_to_buffer(&red_mask, ptr, size, &offset, sizeof(uint16_t)); + bmp_retm_if(ret < 0, *ptr); + ret = bmp_write_to_buffer(&zero_word, ptr, size, &offset, sizeof(uint16_t)); + bmp_retm_if(ret < 0, *ptr); + + ret = bmp_write_to_buffer(&green_mask, ptr, size, &offset, sizeof(uint16_t)); + bmp_retm_if(ret < 0, *ptr); + ret = bmp_write_to_buffer(&zero_word, ptr, size, &offset, sizeof(uint16_t)); + bmp_retm_if(ret < 0, *ptr); + + ret = bmp_write_to_buffer(&blue_mask, ptr, size, &offset, sizeof(uint16_t)); + bmp_retm_if(ret < 0, *ptr); + ret = bmp_write_to_buffer(&zero_word, ptr, size, &offset, sizeof(uint16_t)); + bmp_retm_if(ret < 0, *ptr); + } +} + + +bool +bmp_save2(bmpfile_t *bmp, void **buffer, size_t *size) +{ + int row; + unsigned char *buf; + unsigned char *ptr = NULL; + size_t osize = 0, offset = 0; + uint16_t ret; + + /* Write bmp to buffer */ + bmp_write_header2(bmp, &ptr, &osize); + bmp_write_dib2(bmp, &ptr, &osize); + bmp_write_palette2(bmp, &ptr, &osize); + + if (ptr == NULL) { + *size = 0; + return FALSE; + } + offset = osize; + + if (bmp->dib.depth == 16) { + uint32_t data_bytes = bmp->dib.width * 2; + uint32_t padding_bytes = 4 - data_bytes % 4; + + for (row = bmp->dib.height - 1; row >= 0; --row) { + int i; + unsigned char zero_byte = 0; + uint32_t write_number = 0; + + for (i = 0; write_number < data_bytes; ++i, write_number += 2) { + uint16_t red = (uint16_t)(bmp->pixels[i][row].red / 8); + uint16_t green = (uint16_t)(bmp->pixels[i][row].green / 4); + uint16_t blue = (uint16_t)(bmp->pixels[i][row].blue / 8); + uint16_t value = (red << 11) + (green << 5) + blue; + + if (_is_big_endian()) value = UINT16_SWAP_LE_BE_CONSTANT(value); + + ret = bmp_write_to_buffer(&value, &ptr, &osize, &offset, sizeof(uint16_t)); + bmp_retvm_if(ret < 0, ptr, FALSE); + } + + for (write_number = 0; write_number < padding_bytes; ++write_number) { + ret = bmp_write_to_buffer(&zero_byte, &ptr, &osize, &offset, 1); + bmp_retvm_if(ret < 0, ptr, FALSE); + } + } + } + else { + double bytes_per_pixel; + int bytes_per_line; + + bytes_per_pixel = (bmp->dib.depth * 1.0) / 8.0; + bytes_per_line = (int)ceil(bytes_per_pixel * bmp->dib.width); + if (bytes_per_line % 4 != 0) + bytes_per_line += 4 - bytes_per_line % 4; + + buf = malloc(bytes_per_line); + + for (row = bmp->dib.height - 1; row >= 0; --row) { + memset(buf, 0, bytes_per_line); + + switch (bmp->dib.depth) { + case 1: + bmp_get_row_data_for_1(bmp, buf, bytes_per_line, row); + break; + + case 4: + bmp_get_row_data_for_4(bmp, buf, bytes_per_line, row); + break; + + case 8: + bmp_get_row_data_for_8(bmp, buf, bytes_per_line, row); + break; + + case 24: + bmp_get_row_data_for_24(bmp, buf, bytes_per_line, row); + break; + + case 32: + bmp_get_row_data_for_32(bmp, buf, bytes_per_line, row); + break; + } + + ret = bmp_write_to_buffer(buf, &ptr, &osize, &offset, bytes_per_line); + if (ret < 0) { + free(buf); + BMP_SAFE_FREE(ptr); + *size = 0; + return FALSE; + } + } + free(buf); + } + + *buffer = (void *)ptr; + *size = osize; + + return TRUE; +} + diff --git a/src/bmpfile.h b/src/bmpfile.h old mode 100644 new mode 100755 index ef537fa..b3641d3 --- a/src/bmpfile.h +++ b/src/bmpfile.h @@ -135,6 +135,7 @@ rgb_pixel_t *bmp_get_pixel(bmpfile_t *bmp, uint32_t x, uint32_t y); bool bmp_set_pixel(bmpfile_t *bmp, uint32_t x, uint32_t y, rgb_pixel_t pixel); bool bmp_save(bmpfile_t *bmp, const char *filename); +bool bmp_save2(bmpfile_t *bmp, void **buffer, size_t *size); BMP_END_DECLS -- 2.7.4