cbmp.c 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315
  1. #include <stdlib.h>
  2. #include <stdio.h>
  3. #include "cbmp.h"
  4. // Constants
  5. #define BITS_PER_BYTE 8
  6. #define BLUE 0
  7. #define GREEN 1
  8. #define RED 2
  9. #define ALPHA 3
  10. #define PIXEL_ARRAY_START_BYTES 4
  11. #define PIXEL_ARRAY_START_OFFSET 10
  12. #define WIDTH_BYTES 4
  13. #define WIDTH_OFFSET 18
  14. #define HEIGHT_BYTES 4
  15. #define HEIGHT_OFFSET 22
  16. #define DEPTH_BYTES 2
  17. #define DEPTH_OFFSET 28
  18. // Private function declarations
  19. void _throw_error(char* message);
  20. unsigned int _get_int_from_buffer(unsigned int bytes,
  21. unsigned int offset,
  22. unsigned char* buffer);
  23. unsigned int _get_file_byte_number(FILE* fp);
  24. unsigned char* _get_file_byte_contents(FILE* fp, unsigned int file_byte_number);
  25. int _validate_file_type(unsigned char* file_byte_contents);
  26. int _validate_depth(unsigned int depth);
  27. unsigned int _get_pixel_array_start(unsigned char* file_byte_contents);
  28. int _get_width(unsigned char* file_byte_contents);
  29. int _get_height(unsigned char* file_byte_contents);
  30. unsigned int _get_depth(unsigned char* file_byte_contents);
  31. void _update_file_byte_contents(BMP* bmp, int index, int offset, int channel);
  32. void _populate_pixel_array(BMP* bmp);
  33. void _map(BMP* bmp, void (*f)(BMP* bmp, int, int, int));
  34. void _get_pixel(BMP* bmp, int index, int offset, int channel);
  35. // Public function implementations
  36. BMP* bopen(char* file_path)
  37. {
  38. FILE* fp = fopen(file_path, "rb");
  39. if (fp == NULL)
  40. {
  41. perror("Error opening file");
  42. exit(EXIT_FAILURE);
  43. }
  44. BMP* bmp = (BMP*) malloc(sizeof(BMP));
  45. bmp->file_byte_number = _get_file_byte_number(fp);
  46. bmp->file_byte_contents = _get_file_byte_contents(fp, bmp->file_byte_number);
  47. fclose(fp);
  48. if(!_validate_file_type(bmp->file_byte_contents))
  49. {
  50. _throw_error("Invalid file type");
  51. }
  52. bmp->pixel_array_start = _get_pixel_array_start(bmp->file_byte_contents);
  53. bmp->width = _get_width(bmp->file_byte_contents);
  54. bmp->height = _get_height(bmp->file_byte_contents);
  55. bmp->depth = _get_depth(bmp->file_byte_contents);
  56. if(!_validate_depth(bmp->depth))
  57. {
  58. _throw_error("Invalid file depth");
  59. }
  60. _populate_pixel_array(bmp);
  61. return bmp;
  62. }
  63. BMP* b_deep_copy(BMP* to_copy)
  64. {
  65. BMP* copy = (BMP*) malloc(sizeof(BMP));
  66. copy->file_byte_number = to_copy->file_byte_number;
  67. copy->pixel_array_start = to_copy->pixel_array_start;
  68. copy->width = to_copy->width;
  69. copy->height = to_copy->height;
  70. copy->depth = to_copy->depth;
  71. copy->file_byte_contents = (unsigned char*) malloc(copy->file_byte_number * sizeof(unsigned char));
  72. unsigned int i;
  73. for (i = 0; i < copy->file_byte_number; i++)
  74. {
  75. copy->file_byte_contents[i] = to_copy->file_byte_contents[i];
  76. }
  77. copy->pixels = (pixel*) malloc(copy->width * copy->height * sizeof(pixel));
  78. unsigned int x, y;
  79. int index;
  80. for (y = 0; y < copy->height; y++)
  81. {
  82. for (x = 0; x < copy->width; x++)
  83. {
  84. index = y * copy->width + x;
  85. copy->pixels[index].red = to_copy->pixels[index].red;
  86. copy->pixels[index].green = to_copy->pixels[index].green;
  87. copy->pixels[index].blue = to_copy->pixels[index].blue;
  88. copy->pixels[index].alpha = to_copy->pixels[index].alpha;
  89. }
  90. }
  91. return copy;
  92. }
  93. int get_width(BMP* bmp)
  94. {
  95. return bmp->width;
  96. }
  97. int get_height(BMP* bmp)
  98. {
  99. return bmp->height;
  100. }
  101. unsigned int get_depth(BMP* bmp)
  102. {
  103. return bmp->depth;
  104. }
  105. void get_pixel_rgb(BMP* bmp, int x, int y, unsigned char* r, unsigned char* g, unsigned char* b)
  106. {
  107. int index = y * bmp->width + x;
  108. *r = bmp->pixels[index].red;
  109. *g = bmp->pixels[index].green;
  110. *b = bmp->pixels[index].blue;
  111. }
  112. void set_pixel_rgb(BMP* bmp, int x, int y, unsigned char r, unsigned char g, unsigned char b)
  113. {
  114. int index = y * bmp->width + x;
  115. bmp->pixels[index].red = r;
  116. bmp->pixels[index].green = g;
  117. bmp->pixels[index].blue = b;
  118. }
  119. void bwrite(BMP* bmp, char* file_name)
  120. {
  121. _map(bmp, _update_file_byte_contents);
  122. FILE* fp = fopen(file_name, "wb");
  123. fwrite(bmp->file_byte_contents, sizeof(char), bmp->file_byte_number, fp);
  124. fclose(fp);
  125. }
  126. void bclose(BMP* bmp)
  127. {
  128. free(bmp->pixels);
  129. bmp->pixels = NULL;
  130. free(bmp->file_byte_contents);
  131. bmp->file_byte_contents = NULL;
  132. free(bmp);
  133. bmp = NULL;
  134. }
  135. // Private function implementations
  136. void _throw_error(char* message)
  137. {
  138. fprintf(stderr, "%s\n", message);
  139. exit(1);
  140. }
  141. unsigned int _get_int_from_buffer(unsigned int bytes,
  142. unsigned int offset,
  143. unsigned char* buffer)
  144. {
  145. unsigned char* _buffer = (unsigned char*) malloc(bytes * sizeof(unsigned char));
  146. unsigned int i;
  147. for (i = 0; i < bytes; i++)
  148. {
  149. _buffer[i] = buffer[i + offset];
  150. }
  151. unsigned int value = *(unsigned int*) _buffer;
  152. free(_buffer);
  153. return value;
  154. }
  155. unsigned int _get_file_byte_number(FILE* fp)
  156. {
  157. unsigned int byte_number;
  158. fseek(fp, 0, SEEK_END);
  159. byte_number = ftell(fp);
  160. rewind(fp);
  161. return byte_number;
  162. }
  163. unsigned char* _get_file_byte_contents(FILE* fp, unsigned int file_byte_number)
  164. {
  165. unsigned char* buffer = (unsigned char*) malloc(file_byte_number * sizeof(char));
  166. unsigned int result = fread(buffer, 1, file_byte_number, fp);
  167. if (result != file_byte_number)
  168. {
  169. _throw_error("There was a problem reading the file");
  170. }
  171. return buffer;
  172. }
  173. int _validate_file_type(unsigned char* file_byte_contents)
  174. {
  175. return file_byte_contents[0] == 'B' && file_byte_contents[1] == 'M';
  176. }
  177. int _validate_depth(unsigned int depth)
  178. {
  179. return depth == 24 || depth == 32;
  180. }
  181. unsigned int _get_pixel_array_start(unsigned char* file_byte_contents)
  182. {
  183. return _get_int_from_buffer(PIXEL_ARRAY_START_BYTES, PIXEL_ARRAY_START_OFFSET, file_byte_contents);
  184. }
  185. int _get_width(unsigned char* file_byte_contents)
  186. {
  187. return (int) _get_int_from_buffer(WIDTH_BYTES, WIDTH_OFFSET, file_byte_contents);
  188. }
  189. int _get_height(unsigned char* file_byte_contents)
  190. {
  191. return (int) _get_int_from_buffer(HEIGHT_BYTES, HEIGHT_OFFSET, file_byte_contents);
  192. }
  193. unsigned int _get_depth(unsigned char* file_byte_contents)
  194. {
  195. return _get_int_from_buffer(DEPTH_BYTES, DEPTH_OFFSET, file_byte_contents);
  196. }
  197. void _update_file_byte_contents(BMP* bmp, int index, int offset, int channel)
  198. {
  199. char value;
  200. switch(channel)
  201. {
  202. case BLUE:
  203. value = bmp->pixels[index].blue;
  204. break;
  205. case GREEN:
  206. value = bmp->pixels[index].green;
  207. break;
  208. case RED:
  209. value = bmp->pixels[index].red;
  210. break;
  211. case ALPHA:
  212. value = bmp->pixels[index].alpha;
  213. break;
  214. }
  215. bmp->file_byte_contents[offset + channel] = value;
  216. }
  217. void _populate_pixel_array(BMP* bmp)
  218. {
  219. bmp->pixels = (pixel*) malloc(bmp->width * bmp->height * sizeof(pixel));
  220. _map(bmp, _get_pixel);
  221. }
  222. void _map(BMP* bmp, void (*f)(BMP*, int, int, int))
  223. {
  224. int channels = bmp->depth / (sizeof(unsigned char) * BITS_PER_BYTE);
  225. int row_size = ((int) (bmp->depth * bmp->width + 31) / 32) * 4;
  226. int padding = row_size - bmp->width * channels;
  227. int c;
  228. unsigned int x, y, index, offset;
  229. for (y = 0; y < bmp->height; y++)
  230. {
  231. for (x = 0; x < bmp->width; x++)
  232. {
  233. index = y * bmp->width + x;
  234. offset = bmp->pixel_array_start + index * channels + y * padding;
  235. for (c = 0; c < channels; c++)
  236. {
  237. (*f)(bmp, index, offset, c);
  238. }
  239. }
  240. }
  241. }
  242. void _get_pixel(BMP* bmp, int index, int offset, int channel)
  243. {
  244. unsigned char value = _get_int_from_buffer(sizeof(unsigned char), offset + channel, bmp->file_byte_contents);
  245. switch(channel)
  246. {
  247. case BLUE:
  248. bmp->pixels[index].blue = value;
  249. break;
  250. case GREEN:
  251. bmp->pixels[index].green = value;
  252. break;
  253. case RED:
  254. bmp->pixels[index].red = value;
  255. break;
  256. case ALPHA:
  257. bmp->pixels[index].alpha = value;
  258. break;
  259. }
  260. }