void bmp_write_palette(bmp_structp bmp) { if (bmp->dib.depth == 1 || bmp->dib.depth == 4 || bmp->dib.depth == 8) { bmp->write_fn(bmp, (uint8_t*)bmp->colors, sizeof(rgb_pixel_t) * bmp->dib.ncolors); } 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); } bmp->write_fn(bmp, (uint8_t*)&red_mask, sizeof(uint16_t)); bmp->write_fn(bmp, (uint8_t*)&zero_word, sizeof(uint16_t)); bmp->write_fn(bmp, (uint8_t*)&green_mask, sizeof(uint16_t)); bmp->write_fn(bmp, (uint8_t*)&zero_word, sizeof(uint16_t)); bmp->write_fn(bmp, (uint8_t*)&blue_mask, sizeof(uint16_t)); bmp->write_fn(bmp, (uint8_t*)&zero_word, sizeof(uint16_t)); } }
static void bmp_write_palette(bmpfile_t *bmp, FILE *fp) { if (bmp->dib.depth == 1 || bmp->dib.depth == 4 || bmp->dib.depth == 8) { int i; for (i = 0; i < bmp->dib.ncolors; ++i) fwrite(&(bmp->colors[i]), sizeof(rgb_pixel_t), 1, fp); } 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); } fwrite(&red_mask, sizeof(uint16_t), 1, fp); fwrite(&zero_word, sizeof(uint16_t), 1, fp); fwrite(&green_mask, sizeof(uint16_t), 1, fp); fwrite(&zero_word, sizeof(uint16_t), 1, fp); fwrite(&blue_mask, sizeof(uint16_t), 1, fp); fwrite(&zero_word, sizeof(uint16_t), 1, fp); } }
static void bmp_header_swap_endianess(bmp_header_t *header) { header->filesz = UINT32_SWAP_LE_BE_CONSTANT(header->filesz); header->creator1 = UINT16_SWAP_LE_BE_CONSTANT(header->creator1); header->creator2 = UINT16_SWAP_LE_BE_CONSTANT(header->creator2); header->offset = UINT32_SWAP_LE_BE_CONSTANT(header->offset); }
static void bmp_dib_v3_header_swap_endianess(bmp_dib_v3_header_t *dib) { dib->header_sz = UINT32_SWAP_LE_BE_CONSTANT(dib->header_sz); dib->width = UINT32_SWAP_LE_BE_CONSTANT(dib->width); dib->height = UINT32_SWAP_LE_BE_CONSTANT(dib->height); dib->nplanes = UINT16_SWAP_LE_BE_CONSTANT(dib->nplanes); dib->depth = UINT16_SWAP_LE_BE_CONSTANT(dib->depth); dib->compress_type = UINT32_SWAP_LE_BE_CONSTANT(dib->compress_type); dib->bmp_bytesz = UINT32_SWAP_LE_BE_CONSTANT(dib->bmp_bytesz); dib->hres = UINT32_SWAP_LE_BE_CONSTANT(dib->hres); dib->vres = UINT32_SWAP_LE_BE_CONSTANT(dib->vres); dib->ncolors = UINT32_SWAP_LE_BE_CONSTANT(dib->ncolors); dib->nimpcolors = UINT32_SWAP_LE_BE_CONSTANT(dib->nimpcolors); }
void bmp_write_pixels(bmp_structp bmp, uint32_t offset, uint32_t length) { int index; unsigned char *buf; if (bmp->dib.depth == 16) { uint32_t data_bytes = bmp->dib.width * 2; uint32_t padding_bytes = 4 - data_bytes % 4; unsigned char zero_byte = 0; for (; index = bmp->dib.height * data_bytes; ++index) { uint16_t red = (uint16_t)(bmp->pixels[index].red / 8); uint16_t green = (uint16_t)(bmp->pixels[index].green / 4); uint16_t blue = (uint16_t)(bmp->pixels[index].blue / 8); uint16_t value = (red << 11) + (green << 5) + blue; if (_is_big_endian()) value = UINT16_SWAP_LE_BE_CONSTANT(value); bmp->write_fn(bmp, (uint8_t*)&value, sizeof(uint16_t)); } } 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; int row; buf = (unsigned char*)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; } bmp->write_fn(bmp, buf, bytes_per_line); } free(buf); } }
bool bmp_save(bmpfile_t *bmp, const char *filename) { FILE *fp; int row; unsigned char *buf; /* Create the file */ if ((fp = fopen(filename, "wb")) == NULL) return FALSE; /* Write the file */ bmp_write_header(bmp, fp); bmp_write_dib(bmp, fp); bmp_write_palette(bmp, fp); 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].uniColour / 8); uint16_t green = (uint16_t)(bmp->pixels[i][row].uniColour / 4); uint16_t blue = (uint16_t)(bmp->pixels[i][row].uniColour / 8); uint16_t value = (red << 11) + (green << 5) + blue; if (_is_big_endian()) value = UINT16_SWAP_LE_BE_CONSTANT(value); fwrite(&value, sizeof(uint16_t), 1, fp); } for (write_number = 0; write_number < padding_bytes; ++write_number) fwrite(&zero_byte, 1, 1, fp); } } 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; } fwrite(buf, bytes_per_line, 1, fp); } free(buf); } fclose(fp); return TRUE; }