libbmp.c 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276
  1. /* ************************************************************************* */
  2. /* Organizacion del Computador II */
  3. /* */
  4. /* Biblioteca de funciones para operar imagenes BMP */
  5. /* */
  6. /* Esta biblioteca permite crear, abrir, modificar y guardar archivos en */
  7. /* formato bmp de forma sencilla. Soporta solamente archivos con header de */
  8. /* versiones info_header (40 bytes) y info_v5_header (124 bytes). Para la */
  9. /* primera imagenes de 24 bits (BGR) y la segunda imagenes de 32 (ABGR). */
  10. /* */
  11. /* bmp.h : headers de la biblioteca */
  12. /* bmp.c : codigo fuente de la biblioteca */
  13. /* example.c : ejemplos de uso de la biblioteca */
  14. /* $ gcc example.c bmp.c -o example */
  15. /* ************************************************************************* */
  16. #include "libbmp.h"
  17. /* ************************************************************************* */
  18. BMPIH* get_BMPIH(uint32_t width, uint32_t height) {
  19. if(width%4!=0) return 0; // TODO: dont support padding
  20. BMPIH* new_bmp_info_ih = (BMPIH*)malloc(sizeof(BMPIH));
  21. new_bmp_info_ih->biSize = sizeof(BMPIH);
  22. new_bmp_info_ih->biWidth = width;
  23. new_bmp_info_ih->biHeight = height;
  24. new_bmp_info_ih->biPlanes = 1;
  25. new_bmp_info_ih->biBitCount = 24; //TODO: dont support other bitcount
  26. new_bmp_info_ih->biCompression = BI_RGB;
  27. new_bmp_info_ih->biSizeImage = width*height*(new_bmp_info_ih->biBitCount/8);
  28. new_bmp_info_ih->biXPelsPerMeter = 2952; // 75 dpi
  29. new_bmp_info_ih->biYPelsPerMeter = 2952; // 75 dpi
  30. new_bmp_info_ih->biClrUsed = 0;
  31. new_bmp_info_ih->biClrImportant = 0;
  32. return new_bmp_info_ih;
  33. }
  34. /* ************************************************************************* */
  35. BMPV5H* get_BMPV5H(uint32_t width, uint32_t height) {
  36. if(width%4!=0) return 0; // TODO: dont support padding
  37. BMPV5H* new_bmp_info_v5h = (BMPV5H*)malloc(sizeof(BMPV5H));
  38. new_bmp_info_v5h->bV5Size = sizeof(BMPV5H);
  39. new_bmp_info_v5h->bV5Width = width;
  40. new_bmp_info_v5h->bV5Height = height;
  41. new_bmp_info_v5h->bV5Planes = 1;
  42. new_bmp_info_v5h->bV5BitCount = 32; //TODO: dont support other bitcount
  43. new_bmp_info_v5h->bV5Compression = BI_BITFIELDS;
  44. new_bmp_info_v5h->bV5SizeImage = width*height*(new_bmp_info_v5h->bV5BitCount/8);
  45. new_bmp_info_v5h->bV5XPelsPerMeter = 2952; // 75 dpi
  46. new_bmp_info_v5h->bV5YPelsPerMeter = 2952; // 75 dpi
  47. new_bmp_info_v5h->bV5ClrUsed = 0;
  48. new_bmp_info_v5h->bV5ClrImportant = 0;
  49. new_bmp_info_v5h->bV5RedMask = 0xff000000;
  50. new_bmp_info_v5h->bV5GreenMask = 0x00ff0000;
  51. new_bmp_info_v5h->bV5BlueMask = 0x0000ff00;
  52. new_bmp_info_v5h->bV5AlphaMask = 0x000000ff;
  53. new_bmp_info_v5h->bV5CSType = LCS_sRGB;
  54. CIEXYZTRIPLE bV5Endpoints_ = {{0,0,0},{0,0,0},{0,0,0}};
  55. new_bmp_info_v5h->bV5Endpoints = bV5Endpoints_;
  56. new_bmp_info_v5h->bV5GammaRed = 0;
  57. new_bmp_info_v5h->bV5GammaGreen = 0;
  58. new_bmp_info_v5h->bV5GammaBlue = 0;
  59. new_bmp_info_v5h->bV5Intent = LCS_GM_GRAPHICS;
  60. new_bmp_info_v5h->bV5ProfileData = 0;
  61. new_bmp_info_v5h->bV5ProfileSize = 0;
  62. new_bmp_info_v5h->bV5Reserved = 0;
  63. return new_bmp_info_v5h;
  64. }
  65. /* ************************************************************************* */
  66. BMP* bmp_create(void* info_header, int init_data) {
  67. unsigned int i;
  68. BMPIH* ih = (BMPIH*)info_header;
  69. // (1) creo la data area
  70. unsigned int data_size = ih->biSizeImage;
  71. uint8_t* new_bmp_data = (uint8_t*)malloc(data_size);
  72. if(init_data)
  73. for(i=0;i<data_size;i++)
  74. new_bmp_data[i] = 0;
  75. // (2) creo un nuevo fh
  76. BMPFH* new_bmp_fh = (BMPFH*) malloc(sizeof(BMPFH));
  77. new_bmp_fh->bfType[0] = 'B';
  78. new_bmp_fh->bfType[1] = 'M';
  79. new_bmp_fh->bfOffBits = ih->biSize + sizeof(BMPFH);
  80. new_bmp_fh->bfSize = data_size + new_bmp_fh->bfOffBits;
  81. new_bmp_fh->bfReserved1 = 0;
  82. new_bmp_fh->bfReserved2 = 0;
  83. // (3) store information on a BMP struct
  84. BMP* bmp = (BMP*)malloc(sizeof(BMP));
  85. bmp->fh = new_bmp_fh;
  86. bmp->ih = info_header;
  87. bmp->data = new_bmp_data;
  88. return bmp;
  89. }
  90. /* ************************************************************************* */
  91. BMP* bmp_copy(BMP* img, int copy_data) {
  92. unsigned int i;
  93. // (1) copy the fh
  94. BMPFH* new_bmp_fh = (BMPFH*) malloc(sizeof(BMPFH));
  95. (*new_bmp_fh) = (*(img->fh));
  96. // (2) copy the ih/v5h
  97. int info_header_size = new_bmp_fh->bfOffBits - sizeof(BMPFH);
  98. char* new_bmp_info = 0;
  99. if( info_header_size == sizeof(BMPIH) ) {
  100. BMPIH* new_bmp_info_ih = (BMPIH*)malloc(sizeof(BMPIH));
  101. (*new_bmp_info_ih) = *(BMPIH*)(img->ih);
  102. new_bmp_info = (char*)new_bmp_info_ih;
  103. } else
  104. if( info_header_size == sizeof(BMPV5H) ) {
  105. BMPV5H* new_bmp_info_v5h = (BMPV5H*)malloc(sizeof(BMPV5H));
  106. (*new_bmp_info_v5h) = *(BMPV5H*)(img->ih);
  107. new_bmp_info = (char*)new_bmp_info_v5h;
  108. }
  109. // (3) data area
  110. unsigned int data_size = ((BMPIH*)(new_bmp_info))->biSizeImage;
  111. uint8_t* new_bmp_data = (uint8_t*)malloc(data_size);
  112. if( copy_data )
  113. for(i=0;i<data_size;i++)
  114. new_bmp_data[i] = img->data[i];
  115. // (4) store information on a BMP struct
  116. BMP* bmp = (BMP*)malloc(sizeof(BMP));
  117. bmp->fh = new_bmp_fh;
  118. bmp->ih = new_bmp_info;
  119. bmp->data = new_bmp_data;
  120. return bmp;
  121. }
  122. /* ************************************************************************* */
  123. BMP* bmp_read(char* src) {
  124. // (0) open file
  125. FILE* fsrc = fopen(src,"r");
  126. if (fsrc == 0) {
  127. fprintf(stderr, "Error al abrir el archivo.\n");
  128. return 0;
  129. } // Error al abrir el archivo
  130. // (1) read bitmap file header
  131. BMPFH* bmp_fh = (BMPFH*) malloc(sizeof(BMPFH));
  132. if(!fread(bmp_fh, sizeof(BMPFH), 1, fsrc)){
  133. fprintf(stderr, "Error al leer el archivo.\n");
  134. return 0;
  135. } // Error al leer el archivo
  136. // (2) read bitmap info header (TODO: only support BMPV5H(130B) and BMPIH(40B))
  137. int info_header_size = bmp_fh->bfOffBits - sizeof(BMPFH);
  138. char* bmp_info = 0;
  139. if( info_header_size == sizeof(BMPIH) ) {
  140. bmp_info = malloc(sizeof(BMPIH));
  141. } else
  142. if( info_header_size == sizeof(BMPV5H) ) {
  143. bmp_info = malloc(sizeof(BMPV5H));
  144. } else
  145. if( info_header_size == sizeof(BMPV3IH) ) {
  146. bmp_info = malloc(sizeof(BMPV3IH));
  147. }
  148. if(!bmp_info){
  149. fprintf(stderr, "Formato de archivo no soportado.\n");
  150. return 0;
  151. } // Error formato no soportado
  152. if(!fread(bmp_info, info_header_size, 1, fsrc)){ return 0; } // Error al leer el archivo
  153. // (3) read bitmap data pixels
  154. int image_data_size = bmp_fh->bfSize - info_header_size - sizeof(BMPFH);
  155. uint8_t* bmp_data = (uint8_t*) malloc(image_data_size);
  156. if(!fread(bmp_data, image_data_size, 1, fsrc)){ return 0; } // Error al leer el archivo
  157. // (4) store information on a BMP struct
  158. BMP* bmp = (BMP*)malloc(sizeof(BMP));
  159. bmp->fh = bmp_fh;
  160. bmp->ih = bmp_info;
  161. bmp->data = bmp_data;
  162. fclose(fsrc);
  163. return bmp;
  164. }
  165. /* ************************************************************************* */
  166. int bmp_save(char* dst, BMP* img) {
  167. int r=0,b;
  168. // (0) open file
  169. FILE* fdst = fopen (dst,"w+");
  170. if(fdst == 0){ return 0; } // Error al abrir el archivo
  171. // (1) write bitmap file header
  172. b=fwrite(img->fh, sizeof(BMPFH), 1, fdst); r=b;
  173. if(!b){ return 0; } // Error al escribir el archivo
  174. // (2) write bitmap info header
  175. b=fwrite(img->ih, img->fh->bfOffBits-sizeof(BMPFH), 1, fdst); r=r+b;
  176. if(!b){ return 0; } // Error al escribir el archivo
  177. // (3) write bitmap data
  178. b=fwrite(img->data, img->fh->bfSize-img->fh->bfOffBits, 1, fdst); r=r+b;
  179. if(!b){ return 0; } // Error al escribir el archivo
  180. fclose(fdst);
  181. return r;
  182. }
  183. /* ************************************************************************* */
  184. void bmp_delete(BMP* img) {
  185. free(img->fh);
  186. free(img->ih);
  187. free(img->data);
  188. free(img);
  189. }
  190. /* ************************************************************************* */
  191. uint32_t bmp_width(BMP* img) {
  192. return (((BMPIH*)(img->ih))->biWidth);
  193. }
  194. /* ************************************************************************* */
  195. uint32_t bmp_height(BMP* img) {
  196. return (((BMPIH*)(img->ih))->biHeight);
  197. }
  198. /* ************************************************************************* */
  199. uint8_t* bmp_data(BMP* img) {
  200. return img->data;
  201. }
  202. /* ************************************************************************* */
  203. uint16_t bmp_bit_count(BMP* img) {
  204. return (((BMPIH*)(img->ih))->biBitCount);
  205. }
  206. /* ************************************************************************* */
  207. uint32_t bmp_compression(BMP* img) {
  208. return (((BMPIH*)(img->ih))->biCompression);
  209. }
  210. void bmp_set_bit_count(BMP* img, uint16_t new_bit_count) {
  211. (((BMPIH*)(img->ih))->biBitCount = new_bit_count);
  212. }
  213. /* ************************************************************************* */
  214. uint32_t bmp_bytes_per_row(BMP* img)
  215. {
  216. return ((bmp_width(img) * bmp_bit_count(img) + 31) >> 5) << 2;
  217. }
  218. /* ************************************************************************* */
  219. void bmp_convert_24_to_32_bpp (BMP *img)
  220. {
  221. unsigned int * data32 = (unsigned int *)malloc(32 * bmp_height(img) * bmp_width(img));
  222. unsigned char * data24 = (unsigned char *)img->data;
  223. unsigned int i = 0;
  224. unsigned int val;
  225. for (i = 0; i < bmp_height(img) * bmp_width(img); i++) {
  226. val = 0xFF;
  227. val = (val << 8) + data24[3 * i + 2];
  228. val = (val << 8) + data24[3 * i + 1];
  229. val = (val << 8) + data24[3 * i];
  230. data32[i] = val;
  231. }
  232. free(data24);
  233. bmp_set_bit_count(img, 32);
  234. img->data = (uint8_t*) data32;
  235. ((BMPIH*)(img->ih))->biSizeImage = bmp_height(img) * bmp_width(img) * 4;
  236. uint32_t file_size = ((BMPIH*)(img->ih))->biSizeImage + ((BMPIH*)(img->ih))->biSize + sizeof(BMPFH);
  237. ((BMPFH*)(img->fh))->bfSize = file_size;
  238. }