Advertisement
Guest User

Untitled

a guest
Nov 17th, 2017
393
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 17.52 KB | None | 0 0
  1. /**
  2.  * @file bmpfile.c
  3.  * @brief The BMP library implementation
  4.  *
  5.  * libbmp - BMP library
  6.  * Copyright (C) 2009 lidaibin(超越无限)
  7.  * mail: lidaibin@gmail.com
  8.  *
  9.  * This library is free software; you can redistribute it and/or
  10.  * modify it under the terms of the GNU Lesser General Public
  11.  * License as published by the Free Software Foundation; either
  12.  * version 2 of the License, or (at your option) any later version.
  13.  *
  14.  * This library is distributed in the hope that it will be useful,
  15.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  17.  * Lesser General Public License for more details.
  18.  *
  19.  * You should have received a copy of the GNU Lesser General Public
  20.  * License along with this library; if not, write to the
  21.  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
  22.  * Boston, MA 02111-1307, USA.
  23.  *
  24.  * $Id$
  25.  */
  26.  
  27.  
  28. /*
  29.  * BMP File Header  Stores general information about the BMP file.
  30.  * DIB header       Stores detailed information about the bitmap image.
  31.  * Color Palette    Stores the definition of the colors being used for
  32.  *                    indexed color bitmaps.
  33.  * Bitmap Data      Stores the actual image, pixel by pixel.
  34.  */
  35.  
  36. #include <math.h>
  37. #include <stdio.h>
  38. #include <stdlib.h>
  39. #include <string.h>
  40.  
  41. #include "bmpfile.h"
  42.  
  43. #define DEFAULT_DPI_X 3780
  44. #define DEFAULT_DPI_Y 3780
  45. #define DPI_FACTOR 39.37007874015748
  46.  
  47. struct _bmpfile {
  48.   bmp_header_t header;
  49.   bmp_dib_v3_header_t dib;
  50.  
  51.   rgb_pixel_t **pixels;
  52.   rgb_pixel_t *colors;
  53. };
  54.  
  55. static uint32_t
  56. uint32_pow(uint32_t base, uint32_t depth)
  57. {
  58.   uint32_t i, result = 1;
  59.  
  60.   for (i = 0; i < depth; ++i)
  61.     result *= base;
  62.  
  63.   return result;
  64. }
  65.  
  66. /**
  67.  * Create the standard color table for BMP object
  68.  */
  69. static void
  70. bmp_create_standard_color_table(bmpfile_t *bmp)
  71. {
  72.   int i, j, k, ell;
  73.  
  74.   switch (bmp->dib.depth) {
  75.   case 1:
  76.     for (i = 0; i < 2; ++i) {
  77.       bmp->colors[i].red = i * 255;
  78.       bmp->colors[i].green = i * 255;
  79.       bmp->colors[i].blue = i * 255;
  80.       bmp->colors[i].alpha = 0;
  81.     }
  82.     break;
  83.  
  84.   case 4:
  85.     i = 0;
  86.     for (ell = 0; ell < 2; ++ell) {
  87.       for (k = 0; k < 2; ++k) {
  88.     for (j = 0; j < 2; ++j) {
  89.       bmp->colors[i].red = j * 128;
  90.       bmp->colors[i].green = k * 128;
  91.       bmp->colors[i].blue = ell * 128;
  92.       bmp->colors[i].alpha = 0;
  93.       ++i;
  94.     }
  95.       }
  96.     }
  97.  
  98.     for (ell = 0; ell < 2; ++ell) {
  99.       for (k = 0; k < 2; ++k) {
  100.     for (j = 0; j < 2; ++j) {
  101.       bmp->colors[i].red = j * 255;
  102.       bmp->colors[i].green = k * 255;
  103.       bmp->colors[i].blue = ell * 255;
  104.       bmp->colors[i].alpha = 0;
  105.       ++i;
  106.     }
  107.       }
  108.     }
  109.  
  110.     i = 8;
  111.     bmp->colors[i].red = 192;
  112.     bmp->colors[i].green = 192;
  113.     bmp->colors[i].blue = 192;
  114.     bmp->colors[i].alpha = 0;
  115.  
  116.     break;
  117.  
  118.   case 8:
  119.     i = 0;
  120.     for (ell = 0; ell < 4; ++ell) {
  121.       for (k = 0; k < 8; ++k) {
  122.     for (j = 0; j < 8; ++j) {
  123.       bmp->colors[i].red = j * 32;
  124.       bmp->colors[i].green = k * 32;
  125.       bmp->colors[i].blue = ell * 64;
  126.       bmp->colors[i].alpha = 0;
  127.       ++i;
  128.     }
  129.       }
  130.     }
  131.  
  132.     i = 0;
  133.     for (ell = 0; ell < 2; ++ell) {
  134.       for (k = 0; k < 2; ++k) {
  135.     for (j = 0; j < 2; ++j) {
  136.       bmp->colors[i].red = j * 128;
  137.       bmp->colors[i].green = k * 128;
  138.       bmp->colors[i].blue = ell * 128;
  139.       ++i;
  140.     }
  141.       }
  142.     }
  143.  
  144.     // overwrite colors 7, 8, 9
  145.     i = 7;
  146.     bmp->colors[i].red = 192;
  147.     bmp->colors[i].green = 192;
  148.     bmp->colors[i].blue = 192;
  149.     i++; // 8
  150.     bmp->colors[i].red = 192;
  151.     bmp->colors[i].green = 220;
  152.     bmp->colors[i].blue = 192;
  153.     i++; // 9
  154.     bmp->colors[i].red = 166;
  155.     bmp->colors[i].green = 202;
  156.     bmp->colors[i].blue = 240;
  157.  
  158.     // overwrite colors 246 to 255
  159.     i = 246;
  160.     bmp->colors[i].red = 255;
  161.     bmp->colors[i].green = 251;
  162.     bmp->colors[i].blue = 240;
  163.     i++; // 247
  164.     bmp->colors[i].red = 160;
  165.     bmp->colors[i].green = 160;
  166.     bmp->colors[i].blue = 164;
  167.     i++; // 248
  168.     bmp->colors[i].red = 128;
  169.     bmp->colors[i].green = 128;
  170.     bmp->colors[i].blue = 128;
  171.     i++; // 249
  172.     bmp->colors[i].red = 255;
  173.     bmp->colors[i].green = 0;
  174.     bmp->colors[i].blue = 0;
  175.     i++; // 250
  176.     bmp->colors[i].red = 0;
  177.     bmp->colors[i].green = 255;
  178.     bmp->colors[i].blue = 0;
  179.     i++; // 251
  180.     bmp->colors[i].red = 255;
  181.     bmp->colors[i].green = 255;
  182.     bmp->colors[i].blue = 0;
  183.     i++; // 252
  184.     bmp->colors[i].red = 0;
  185.     bmp->colors[i].green = 0;
  186.     bmp->colors[i].blue = 255;
  187.     i++; // 253
  188.     bmp->colors[i].red = 255;
  189.     bmp->colors[i].green = 0;
  190.     bmp->colors[i].blue = 255;
  191.     i++; // 254
  192.     bmp->colors[i].red = 0;
  193.     bmp->colors[i].green = 255;
  194.     bmp->colors[i].blue = 255;
  195.     i++; // 255
  196.     bmp->colors[i].red = 255;
  197.     bmp->colors[i].green = 255;
  198.     bmp->colors[i].blue = 255;
  199.     break;
  200.   }
  201. }
  202.  
  203. /**
  204.  * Create grayscale color table for BMP object
  205.  */
  206. /*static void
  207. bmp_create_grayscale_color_table(bmpfile_t *bmp)
  208. {
  209.   int i;
  210.   uint8_t step_size;
  211.   uint8_t value;
  212.   rgb_pixel_t color;
  213.  
  214.   if (!bmp->colors) return;
  215.  
  216.   if (bmp->dib.depth != 1)
  217.     step_size = 255 / (bmp->dib.ncolors - 1);
  218.   else
  219.     step_size = 255;
  220.  
  221.   for (i = 0; i < bmp->dib.ncolors; ++i) {
  222.     value = i * step_size;
  223.     color.blue=value;
  224.     color.green=value;
  225.     color.red=value;
  226.     color.alpha=0;
  227.     bmp->colors[i] = color;
  228.   }
  229. }*/
  230.  
  231. /**
  232.  * Malloc the memory for color palette
  233.  */
  234. static void
  235. bmp_malloc_colors(bmpfile_t *bmp)
  236. {
  237.   bmp->dib.ncolors = uint32_pow(2, bmp->dib.depth);
  238.   if (bmp->dib.depth == 1 || bmp->dib.depth == 4 || bmp->dib.depth == 8) {
  239.     bmp->colors = malloc(sizeof(rgb_pixel_t) * bmp->dib.ncolors);
  240.     bmp_create_standard_color_table(bmp);
  241.   }
  242. }
  243.  
  244. /**
  245.  * Free the memory of color palette
  246.  */
  247. static void
  248. bmp_free_colors(bmpfile_t *bmp)
  249. {
  250.   if (bmp->colors)
  251.     free(bmp->colors);
  252. }
  253.  
  254. /**
  255.  * Malloc the memory for pixels
  256.  */
  257. static void
  258. bmp_malloc_pixels(bmpfile_t *bmp)
  259. {
  260.   int i, j;
  261.  
  262.   bmp->pixels = malloc(sizeof(rgb_pixel_t *) * bmp->dib.width);
  263.   for (i = 0; i < bmp->dib.width; ++i) {
  264.     bmp->pixels[i] = malloc(sizeof(rgb_pixel_t) * bmp->dib.height);
  265.     for (j = 0; j < bmp->dib.height; ++j) {
  266.       bmp->pixels[i][j].red = 255;
  267.       bmp->pixels[i][j].green = 255;
  268.       bmp->pixels[i][j].blue = 255;
  269.       bmp->pixels[i][j].alpha = 0;
  270.     }
  271.   }
  272. }
  273.  
  274. /**
  275.  * Free the memory of pixels
  276.  */
  277. static void
  278. bmp_free_pixels(bmpfile_t *bmp)
  279. {
  280.   int i;
  281.  
  282.   for (i = 0; i < bmp->dib.width; ++i)
  283.     free(bmp->pixels[i]);
  284.  
  285.   free(bmp->pixels), bmp->pixels = NULL;
  286. }
  287.  
  288. /**
  289.  * Create the BMP object with specified width and height and depth.
  290.  */
  291. bmpfile_t *
  292. bmp_create(uint32_t width, uint32_t height, uint32_t depth)
  293. {
  294.   bmpfile_t *result;
  295.   double bytes_per_pixel;
  296.   uint32_t bytes_per_line;
  297.   uint32_t palette_size;
  298.  
  299.   if (depth != 1 && depth != 4 && depth != 8 && depth != 16 && depth != 24 &&
  300.       depth != 32)
  301.     return NULL;
  302.  
  303.   result = malloc(sizeof(bmpfile_t));
  304.  
  305.   memset(result, 0, sizeof(bmpfile_t));
  306.  
  307.   result->header.magic[0] = 'B';
  308.   result->header.magic[1] = 'M';
  309.  
  310.   result->dib.header_sz = 40;
  311.   result->dib.width = width;
  312.   result->dib.height = height;
  313.   result->dib.nplanes = 1;
  314.   result->dib.depth = depth;
  315.   result->dib.hres = DEFAULT_DPI_X;
  316.   result->dib.vres = DEFAULT_DPI_Y;
  317.  
  318.   if (depth == 16)
  319.     result->dib.compress_type = BI_BITFIELDS;
  320.   else
  321.     result->dib.compress_type = BI_RGB;
  322.  
  323.   bmp_malloc_pixels(result);
  324.   bmp_malloc_colors(result);
  325.  
  326.   /* Calculate the field value of header and DIB */
  327.   bytes_per_pixel = (result->dib.depth * 1.0) / 8.0;
  328.   bytes_per_line = (int)ceil(bytes_per_pixel * result->dib.width);
  329.   if (bytes_per_line % 4 != 0)
  330.     bytes_per_line += 4 - bytes_per_line % 4;
  331.  
  332.   result->dib.bmp_bytesz = bytes_per_line * result->dib.height;
  333.  
  334.   palette_size = 0;
  335.   if (depth == 1 || depth == 4 || depth == 8)
  336.     palette_size = uint32_pow(2, result->dib.depth) * 4;
  337.   else if (result->dib.depth == 16)
  338.     palette_size = 3 * 4;
  339.  
  340.   result->header.offset = 14 + result->dib.header_sz + palette_size;
  341.   result->header.filesz = result->header.offset + result->dib.bmp_bytesz;
  342.  
  343.   return result;
  344. }
  345.  
  346. void
  347. bmp_destroy(bmpfile_t *bmp)
  348. {
  349.   bmp_free_pixels(bmp);
  350.   bmp_free_colors(bmp);
  351.   free(bmp);
  352. }
  353.  
  354. uint32_t
  355. bmp_get_width(bmpfile_t *bmp)
  356. {
  357.   return bmp->dib.width;
  358. }
  359.  
  360. uint32_t
  361. bmp_get_height(bmpfile_t *bmp)
  362. {
  363.   return bmp->dib.height;
  364. }
  365.  
  366. uint32_t
  367. bmp_get_depth(bmpfile_t *bmp)
  368. {
  369.   return bmp->dib.depth;
  370. }
  371.  
  372. bmp_header_t
  373. bmp_get_header(bmpfile_t *bmp)
  374. {
  375.   return bmp->header;
  376. }
  377.  
  378. bmp_dib_v3_header_t
  379. bmp_get_dib(bmpfile_t *bmp)
  380. {
  381.   return bmp->dib;
  382. }
  383.  
  384. uint32_t
  385. bmp_get_dpi_x(bmpfile_t *bmp)
  386. {
  387.   return (uint32_t)(bmp->dib.hres / DPI_FACTOR);
  388. }
  389.  
  390. uint32_t
  391. bmp_get_dpi_y(bmpfile_t *bmp)
  392. {
  393.   return (uint32_t)(bmp->dib.vres / DPI_FACTOR);
  394. }
  395.  
  396. void
  397. bmp_set_dpi(bmpfile_t *bmp, uint32_t x, uint32_t y)
  398. {
  399.   bmp->dib.hres = (uint32_t)(x * DPI_FACTOR);
  400.   bmp->dib.vres = (uint32_t)(y * DPI_FACTOR);
  401. }
  402.  
  403. rgb_pixel_t *
  404. bmp_get_pixel(bmpfile_t *bmp, uint32_t x, uint32_t y)
  405. {
  406.   if ((x >= bmp->dib.width) || (y >= bmp->dib.height))
  407.     return NULL;
  408.  
  409.   return &(bmp->pixels[x][y]);
  410. }
  411.  
  412. bool
  413. bmp_set_pixel(bmpfile_t *bmp, uint32_t x, uint32_t y, rgb_pixel_t pixel)
  414. {
  415.   if ((x >= bmp->dib.width) || (y >= bmp->dib.height))
  416.     return FALSE;
  417.  
  418.   bmp->pixels[x][y] = pixel;
  419.   return TRUE;
  420. }
  421.  
  422. static bool
  423. _is_big_endian(void)
  424. {
  425.   uint16_t value = 0x0001;
  426.  
  427.   return (*(uint8_t *)&value) != 0x01;
  428. }
  429.  
  430. #define UINT16_SWAP_LE_BE_CONSTANT(val)     \
  431.   ((uint16_t)                   \
  432.    (                        \
  433.     (uint16_t) ((uint16_t) (val) >> 8) |    \
  434.     (uint16_t) ((uint16_t) (val) << 8)))
  435.  
  436. #define UINT32_SWAP_LE_BE_CONSTANT(val)           \
  437.   ((uint32_t)                         \
  438.    (                              \
  439.     (((uint32_t) (val) & (uint32_t) 0x000000ffU) << 24) | \
  440.     (((uint32_t) (val) & (uint32_t) 0x0000ff00U) <<  8) | \
  441.     (((uint32_t) (val) & (uint32_t) 0x00ff0000U) >>  8) | \
  442.     (((uint32_t) (val) & (uint32_t) 0xff000000U) >> 24)))
  443.  
  444. static void
  445. bmp_header_swap_endianess(bmp_header_t *header)
  446. {
  447.   header->filesz = UINT32_SWAP_LE_BE_CONSTANT(header->filesz);
  448.   header->creator1 = UINT16_SWAP_LE_BE_CONSTANT(header->creator1);
  449.   header->creator2 = UINT16_SWAP_LE_BE_CONSTANT(header->creator2);
  450.   header->offset = UINT32_SWAP_LE_BE_CONSTANT(header->offset);
  451. }
  452.  
  453. static void
  454. bmp_dib_v3_header_swap_endianess(bmp_dib_v3_header_t *dib)
  455. {
  456.   dib->header_sz = UINT32_SWAP_LE_BE_CONSTANT(dib->header_sz);
  457.   dib->width = UINT32_SWAP_LE_BE_CONSTANT(dib->width);
  458.   dib->height = UINT32_SWAP_LE_BE_CONSTANT(dib->height);
  459.   dib->nplanes = UINT16_SWAP_LE_BE_CONSTANT(dib->nplanes);
  460.   dib->depth = UINT16_SWAP_LE_BE_CONSTANT(dib->depth);
  461.   dib->compress_type = UINT32_SWAP_LE_BE_CONSTANT(dib->compress_type);
  462.   dib->bmp_bytesz = UINT32_SWAP_LE_BE_CONSTANT(dib->bmp_bytesz);
  463.   dib->hres = UINT32_SWAP_LE_BE_CONSTANT(dib->hres);
  464.   dib->vres = UINT32_SWAP_LE_BE_CONSTANT(dib->vres);
  465.   dib->ncolors = UINT32_SWAP_LE_BE_CONSTANT(dib->ncolors);
  466.   dib->nimpcolors = UINT32_SWAP_LE_BE_CONSTANT(dib->nimpcolors);
  467. }
  468.  
  469. static void
  470. bmp_write_header(bmpfile_t *bmp, FILE *fp)
  471. {
  472.   bmp_header_t header = bmp->header;
  473.  
  474.   if (_is_big_endian()) bmp_header_swap_endianess(&header);
  475.  
  476.   fwrite(header.magic, sizeof(header.magic), 1, fp);
  477.   fwrite(&(header.filesz), sizeof(uint32_t), 1, fp);
  478.   fwrite(&(header.creator1), sizeof(uint16_t), 1, fp);
  479.   fwrite(&(header.creator2), sizeof(uint16_t), 1, fp);
  480.   fwrite(&(header.offset), sizeof(uint32_t), 1, fp);
  481. }
  482.  
  483. static void
  484. bmp_write_dib(bmpfile_t *bmp, FILE *fp)
  485. {
  486.   bmp_dib_v3_header_t dib = bmp->dib;
  487.  
  488.   if (_is_big_endian()) bmp_dib_v3_header_swap_endianess(&dib);
  489.  
  490.   fwrite(&(dib.header_sz), sizeof(uint32_t), 1, fp);
  491.   fwrite(&(dib.width), sizeof(uint32_t), 1, fp);
  492.   fwrite(&(dib.height), sizeof(uint32_t), 1, fp);
  493.   fwrite(&(dib.nplanes), sizeof(uint16_t), 1, fp);
  494.   fwrite(&(dib.depth), sizeof(uint16_t), 1, fp);
  495.   fwrite(&(dib.compress_type), sizeof(uint32_t), 1, fp);
  496.   fwrite(&(dib.bmp_bytesz), sizeof(uint32_t), 1, fp);
  497.   fwrite(&(dib.hres), sizeof(uint32_t), 1, fp);
  498.   fwrite(&(dib.vres), sizeof(uint32_t), 1, fp);
  499.   fwrite(&(dib.ncolors), sizeof(uint32_t), 1, fp);
  500.   fwrite(&(dib.nimpcolors), sizeof(uint32_t), 1, fp);
  501. }
  502.  
  503. static void
  504. bmp_write_palette(bmpfile_t *bmp, FILE *fp)
  505. {
  506.   if (bmp->dib.depth == 1 || bmp->dib.depth == 4 || bmp->dib.depth == 8) {
  507.     int i;
  508.     for (i = 0; i < bmp->dib.ncolors; ++i)
  509.       fwrite(&(bmp->colors[i]), sizeof(rgb_pixel_t), 1, fp);
  510.   }
  511.   else if (bmp->dib.depth == 16) { /* the bit masks, not palette */
  512.     uint16_t red_mask = 63488;  /* bits 1-5 */
  513.     uint16_t green_mask = 2016; /* bits 6-11 */
  514.     uint16_t blue_mask = 31;    /* bits 12-16 */
  515.     uint16_t zero_word = 0;
  516.  
  517.     if (_is_big_endian()) {
  518.       red_mask = UINT16_SWAP_LE_BE_CONSTANT(red_mask);
  519.       green_mask = UINT16_SWAP_LE_BE_CONSTANT(green_mask);
  520.       blue_mask = UINT16_SWAP_LE_BE_CONSTANT(blue_mask);
  521.     }
  522.  
  523.     fwrite(&red_mask, sizeof(uint16_t), 1, fp);
  524.     fwrite(&zero_word, sizeof(uint16_t), 1, fp);
  525.  
  526.     fwrite(&green_mask, sizeof(uint16_t), 1, fp);
  527.     fwrite(&zero_word, sizeof(uint16_t), 1, fp);
  528.  
  529.     fwrite(&blue_mask, sizeof(uint16_t), 1, fp);
  530.     fwrite(&zero_word, sizeof(uint16_t), 1, fp);
  531.   }
  532. }
  533.  
  534. #define INT_SQUARE(v) ((int)((v) * (v)))
  535.  
  536. static int
  537. find_closest_color(bmpfile_t *bmp, rgb_pixel_t pixel)
  538. {
  539.   int i, best = 0;
  540.   int best_match = 999999;
  541.  
  542.   for (i = 0; i < bmp->dib.ncolors; ++i) {
  543.     rgb_pixel_t color = bmp->colors[i];
  544.     int temp_match = INT_SQUARE(color.red - pixel.red) +
  545.       INT_SQUARE(color.green - pixel.green) +
  546.       INT_SQUARE(color.blue - pixel.blue);
  547.  
  548.     if (temp_match < best_match) {
  549.       best = i;
  550.       best_match = temp_match;
  551.     }
  552.  
  553.     if (best_match < 1)
  554.       break;
  555.   }
  556.  
  557.   return best;
  558. }
  559.  
  560. static void
  561. bmp_get_row_data_for_1(bmpfile_t *bmp, unsigned char *buf, size_t buf_len,
  562.                uint32_t row)
  563. {
  564.   uint8_t pos_weights[8] = {128, 64, 32, 16, 8, 4, 2, 1};
  565.   uint32_t i = 0, j, k = 0;
  566.   uint32_t index;
  567.  
  568.   if (bmp->dib.width > 8 * buf_len) return;
  569.  
  570.   while (i < bmp->dib.width) {
  571.     for (j = 0, index = 0; j < 8 && i < bmp->dib.width; ++i, ++j)
  572.       index += pos_weights[j] * find_closest_color(bmp, bmp->pixels[i][row]);
  573.  
  574.     buf[k++] = index & 0xff;
  575.   }
  576. }
  577.  
  578. static void
  579. bmp_get_row_data_for_4(bmpfile_t *bmp, unsigned char *buf, size_t buf_len,
  580.                uint32_t row)
  581. {
  582.   uint8_t pos_weights[2] = {16, 1};
  583.   uint32_t i = 0, j, k = 0;
  584.   uint32_t index;
  585.  
  586.   if (bmp->dib.width > 2 * buf_len) return;
  587.  
  588.   while (i < bmp->dib.width) {
  589.     for (j = 0, index = 0; j < 2 && i < bmp->dib.width; ++i, ++j)
  590.       index += pos_weights[j] * find_closest_color(bmp, bmp->pixels[i][row]);
  591.  
  592.     buf[k++] = index & 0xff;
  593.   }
  594. }
  595.  
  596. static void
  597. bmp_get_row_data_for_8(bmpfile_t *bmp, unsigned char *buf, size_t buf_len,
  598.                uint32_t row)
  599. {
  600.   int i;
  601.  
  602.   if (bmp->dib.width > buf_len) return;
  603.  
  604.   for (i = 0; i < bmp->dib.width; ++i)
  605.     buf[i] = find_closest_color(bmp, bmp->pixels[i][row]);
  606. }
  607.  
  608. static void
  609. bmp_get_row_data_for_24(bmpfile_t *bmp, unsigned char *buf, size_t buf_len,
  610.             uint32_t row)
  611. {
  612.   int i;
  613.  
  614.   if (bmp->dib.width * 3 > buf_len) return;
  615.  
  616.   for (i = 0; i < bmp->dib.width; ++i)
  617.     memcpy(buf + 3 * i, (uint8_t *)&(bmp->pixels[i][row]), 3);
  618. }
  619.  
  620. static void
  621. bmp_get_row_data_for_32(bmpfile_t *bmp, unsigned char *buf, size_t buf_len,
  622.             uint32_t row)
  623. {
  624.   int i;
  625.  
  626.   if (bmp->dib.width * 4 > buf_len) return;
  627.  
  628.   for (i = 0; i < bmp->dib.width; ++i)
  629.     memcpy(buf + 4 * i, (uint8_t *)&(bmp->pixels[i][row]), 4);
  630. }
  631.  
  632. bool
  633. bmp_save(bmpfile_t *bmp, const char *filename)
  634. {
  635.   FILE *fp;
  636.   int row;
  637.   unsigned char *buf;
  638.  
  639.   /* Create the file */
  640.   if ((fp = fopen(filename, "wb")) == NULL)
  641.     return FALSE;
  642.  
  643.   /* Write the file */
  644.   bmp_write_header(bmp, fp);
  645.   bmp_write_dib(bmp, fp);
  646.   bmp_write_palette(bmp, fp);
  647.  
  648.   if (bmp->dib.depth == 16) {
  649.     uint32_t data_bytes = bmp->dib.width * 2;
  650.     uint32_t padding_bytes = 4 - data_bytes % 4;
  651.  
  652.     for (row = bmp->dib.height - 1; row >= 0; --row) {
  653.       int i;
  654.       unsigned char zero_byte = 0;
  655.       uint32_t write_number = 0;
  656.  
  657.       for (i = 0; write_number < data_bytes; ++i, write_number += 2) {
  658.     uint16_t red = (uint16_t)(bmp->pixels[i][row].red / 8);
  659.     uint16_t green = (uint16_t)(bmp->pixels[i][row].green / 4);
  660.     uint16_t blue = (uint16_t)(bmp->pixels[i][row].blue / 8);
  661.     uint16_t value = (red << 11) + (green << 5) + blue;
  662.  
  663.     if (_is_big_endian()) value = UINT16_SWAP_LE_BE_CONSTANT(value);
  664.     fwrite(&value, sizeof(uint16_t), 1, fp);
  665.       }
  666.  
  667.       for (write_number = 0; write_number < padding_bytes; ++write_number)
  668.     fwrite(&zero_byte, 1, 1, fp);
  669.     }
  670.   }
  671.   else {
  672.     double bytes_per_pixel;
  673.     int bytes_per_line;
  674.  
  675.     bytes_per_pixel = (bmp->dib.depth * 1.0) / 8.0;
  676.     bytes_per_line = (int)ceil(bytes_per_pixel * bmp->dib.width);
  677.     if (bytes_per_line % 4 != 0)
  678.       bytes_per_line += 4 - bytes_per_line % 4;
  679.  
  680.     buf = malloc(bytes_per_line);
  681.  
  682.     for (row = bmp->dib.height - 1; row >= 0; --row) {
  683.       memset(buf, 0, bytes_per_line);
  684.  
  685.       switch (bmp->dib.depth) {
  686.       case 1:
  687.     bmp_get_row_data_for_1(bmp, buf, bytes_per_line, row);
  688.     break;
  689.  
  690.       case 4:
  691.     bmp_get_row_data_for_4(bmp, buf, bytes_per_line, row);
  692.     break;
  693.  
  694.       case 8:
  695.     bmp_get_row_data_for_8(bmp, buf, bytes_per_line, row);
  696.     break;
  697.  
  698.       case 24:
  699.     bmp_get_row_data_for_24(bmp, buf, bytes_per_line, row);
  700.     break;
  701.  
  702.       case 32:
  703.     bmp_get_row_data_for_32(bmp, buf, bytes_per_line, row);
  704.     break;
  705.       }
  706.  
  707.       fwrite(buf, bytes_per_line, 1, fp);
  708.     }
  709.     free(buf);
  710.   }
  711.  
  712.   fclose(fp);
  713.  
  714.   return TRUE;
  715. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement