image_bmp.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643
  1. #include <rtthread.h>
  2. #include <rtgui/dc_hw.h>
  3. #include <rtgui/image.h>
  4. #include <rtgui/rtgui_system.h>
  5. #include <rtgui/image_bmp.h>
  6. #include <rtgui/blit.h>
  7. /* Compression encodings for BMP files */
  8. #ifndef BI_RGB
  9. #define BI_RGB 0
  10. #define BI_RLE8 1
  11. #define BI_RLE4 2
  12. #define BI_BITFIELDS 3
  13. #endif
  14. #define hw_driver (rtgui_graphic_driver_get_default())
  15. struct rtgui_image_bmp
  16. {
  17. rt_bool_t is_loaded;
  18. rt_uint32_t Rmask;
  19. rt_uint32_t Gmask;
  20. rt_uint32_t Bmask;
  21. rt_size_t pixel_offset;
  22. rt_uint8_t byte_per_pixel;
  23. rt_uint8_t pad;
  24. rt_uint8_t ExpandBMP;
  25. rt_uint8_t *pixels;
  26. rt_uint8_t *line_pixels;
  27. rt_uint32_t pitch;
  28. struct rtgui_filerw* filerw;
  29. };
  30. struct rtgui_image_bmp_header
  31. {
  32. /* The Win32 BMP file header (14 bytes) */
  33. char magic[2];
  34. rt_uint32_t bfSize;
  35. rt_uint16_t bfReserved1;
  36. rt_uint16_t bfReserved2;
  37. rt_uint32_t bfOffBits;
  38. /* The Win32 BITMAPINFOHEADER struct (40 bytes) */
  39. rt_uint32_t biSize;
  40. rt_int32_t biWidth;
  41. rt_int32_t biHeight;
  42. rt_uint16_t biPlanes;
  43. rt_uint16_t biBitCount;
  44. rt_uint32_t biCompression;
  45. rt_uint32_t biSizeImage;
  46. rt_int32_t biXPelsPerMeter;
  47. rt_int32_t biYPelsPerMeter;
  48. rt_uint32_t biClrUsed;
  49. rt_uint32_t biClrImportant;
  50. };
  51. static rt_bool_t rtgui_image_bmp_check(struct rtgui_filerw* file);
  52. static rt_bool_t rtgui_image_bmp_load(struct rtgui_image* image, struct rtgui_filerw* file, rt_bool_t load);
  53. static void rtgui_image_bmp_unload(struct rtgui_image* image);
  54. static void rtgui_image_bmp_blit(struct rtgui_image* image, struct rtgui_dc* dc, struct rtgui_rect* rect);
  55. struct rtgui_image_engine rtgui_image_bmp_engine =
  56. {
  57. "bmp",
  58. { RT_NULL },
  59. rtgui_image_bmp_check,
  60. rtgui_image_bmp_load,
  61. rtgui_image_bmp_unload,
  62. rtgui_image_bmp_blit
  63. };
  64. rt_inline rt_uint32_t rtgui_filerw_read32(struct rtgui_filerw* src)
  65. {
  66. rt_uint32_t value;
  67. rtgui_filerw_read(src, &value, (sizeof value), 1);
  68. return value;
  69. }
  70. rt_inline rt_uint16_t rtgui_filerw_read16(struct rtgui_filerw* src)
  71. {
  72. rt_uint16_t value;
  73. rtgui_filerw_read(src, &value, (sizeof value), 1);
  74. return value;
  75. }
  76. static rt_bool_t rtgui_image_bmp_check(struct rtgui_filerw* file)
  77. {
  78. char magic[2];
  79. rt_bool_t is_bmp;
  80. rt_off_t start;
  81. if ( !file ) return 0;
  82. start = rtgui_filerw_tell(file);
  83. /* move to the beginning of file */
  84. rtgui_filerw_seek(file, 0, RTGUI_FILE_SEEK_SET);
  85. is_bmp = RT_FALSE;
  86. if ( rtgui_filerw_read(file, magic, 1, sizeof(magic)) == sizeof(magic) )
  87. {
  88. if (magic[0] == 'B' &&
  89. magic[1] == 'M')
  90. {
  91. is_bmp = RT_TRUE;
  92. }
  93. }
  94. rtgui_filerw_seek(file, start, RTGUI_FILE_SEEK_SET);
  95. return(is_bmp);
  96. }
  97. static struct rtgui_image_palette* rtgui_image_bmp_load_palette(struct rtgui_image_bmp_header* header, struct rtgui_filerw* src)
  98. {
  99. /* Load the palette, if any */
  100. rt_size_t i;
  101. struct rtgui_image_palette* palette;
  102. if (header->biClrUsed == 0)
  103. header->biClrUsed = 1 << header->biBitCount;
  104. palette = rtgui_image_palette_create(header->biClrUsed);
  105. if (palette == RT_NULL) return RT_NULL;
  106. if ( header->biSize == 12 )
  107. {
  108. rt_uint8_t r, g, b;
  109. for ( i = 0; i < (int)header->biClrUsed; ++i )
  110. {
  111. rtgui_filerw_read(src, &b, 1, 1);
  112. rtgui_filerw_read(src, &g, 1, 1);
  113. rtgui_filerw_read(src, &r, 1, 1);
  114. palette->colors[i] = RTGUI_RGB(r, g, b);
  115. }
  116. }
  117. else
  118. {
  119. rt_uint8_t r, g, b, a;
  120. for ( i = 0; i < (int)header->biClrUsed; ++i )
  121. {
  122. rtgui_filerw_read(src, &b, 1, 1);
  123. rtgui_filerw_read(src, &g, 1, 1);
  124. rtgui_filerw_read(src, &r, 1, 1);
  125. rtgui_filerw_read(src, &a, 1, 1);
  126. palette->colors[i] = RTGUI_ARGB(a, r, g, b);
  127. }
  128. }
  129. return palette;
  130. }
  131. static rt_bool_t rtgui_image_bmp_load(struct rtgui_image* image, struct rtgui_filerw* src, rt_bool_t load)
  132. {
  133. rt_uint32_t Rmask;
  134. rt_uint32_t Gmask;
  135. rt_uint32_t Bmask;
  136. int ExpandBMP, bmpPitch;
  137. struct rtgui_image_bmp* bmp;
  138. struct rtgui_image_bmp_header* header;
  139. struct rtgui_image_palette* palette;
  140. bmp = RT_NULL;
  141. header = RT_NULL;
  142. palette = RT_NULL;
  143. header = (struct rtgui_image_bmp_header*) rtgui_malloc(sizeof(struct rtgui_image_bmp_header));
  144. if (header == RT_NULL) return RT_FALSE;
  145. if ( rtgui_filerw_read(src, header->magic, 1, sizeof(header->magic)) ==
  146. sizeof(sizeof(header->magic)) )
  147. {
  148. if (header->magic[0] != 'B' ||
  149. header->magic[1] != 'M')
  150. {
  151. goto __exit;
  152. }
  153. }
  154. header->bfSize = rtgui_filerw_read32(src);
  155. header->bfReserved1 = rtgui_filerw_read16(src);
  156. header->bfReserved2 = rtgui_filerw_read16(src);
  157. header->bfOffBits = rtgui_filerw_read32(src);
  158. /* Read the Win32 BITMAPINFOHEADER */
  159. header->biSize = rtgui_filerw_read32(src);
  160. if ( header->biSize == 12 )
  161. {
  162. header->biWidth = (rt_uint32_t)rtgui_filerw_read16(src);
  163. header->biHeight = (rt_uint32_t)rtgui_filerw_read16(src);
  164. header->biPlanes = rtgui_filerw_read16(src);
  165. header->biBitCount = rtgui_filerw_read16(src);
  166. header->biCompression = BI_RGB;
  167. header->biSizeImage = 0;
  168. header->biXPelsPerMeter = 0;
  169. header->biYPelsPerMeter = 0;
  170. header->biClrUsed = 0;
  171. header->biClrImportant = 0;
  172. }
  173. else
  174. {
  175. header->biWidth = rtgui_filerw_read32(src);
  176. header->biHeight = rtgui_filerw_read32(src);
  177. header->biPlanes = rtgui_filerw_read16(src);
  178. header->biBitCount = rtgui_filerw_read16(src);
  179. header->biCompression = rtgui_filerw_read32(src);
  180. header->biSizeImage = rtgui_filerw_read32(src);
  181. header->biXPelsPerMeter = rtgui_filerw_read32(src);
  182. header->biYPelsPerMeter = rtgui_filerw_read32(src);
  183. header->biClrUsed = rtgui_filerw_read32(src);
  184. header->biClrImportant = rtgui_filerw_read32(src);
  185. }
  186. /* allocate palette and expand 1 and 4 bit bitmaps to 8 bits per pixel */
  187. switch (header->biBitCount)
  188. {
  189. case 1:
  190. ExpandBMP = header->biBitCount;
  191. palette = rtgui_image_bmp_load_palette(header, src);
  192. header->biBitCount = 8;
  193. break;
  194. case 4:
  195. ExpandBMP = header->biBitCount;
  196. palette = rtgui_image_bmp_load_palette(header, src);
  197. header->biBitCount = 8;
  198. break;
  199. case 8:
  200. palette = rtgui_image_bmp_load_palette(header, src);
  201. ExpandBMP = 0;
  202. break;
  203. default:
  204. ExpandBMP = 0;
  205. break;
  206. }
  207. /* We don't support any BMP compression right now */
  208. Rmask = Gmask = Bmask = 0;
  209. switch (header->biCompression)
  210. {
  211. case BI_RGB:
  212. /* If there are no masks, use the defaults */
  213. if ( header->bfOffBits == (14 + header->biSize) )
  214. {
  215. /* Default values for the BMP format */
  216. switch (header->biBitCount)
  217. {
  218. case 15:
  219. case 16:
  220. Rmask = 0x7C00;
  221. Gmask = 0x03E0;
  222. Bmask = 0x001F;
  223. break;
  224. case 24:
  225. case 32:
  226. Rmask = 0x00FF0000;
  227. Gmask = 0x0000FF00;
  228. Bmask = 0x000000FF;
  229. break;
  230. default:
  231. break;
  232. }
  233. break;
  234. }
  235. /* Fall through -- read the RGB masks */
  236. case BI_BITFIELDS:
  237. switch (header->biBitCount)
  238. {
  239. case 15:
  240. case 16:
  241. case 32:
  242. Rmask = rtgui_filerw_read32(src);
  243. Gmask = rtgui_filerw_read32(src);
  244. Bmask = rtgui_filerw_read32(src);
  245. break;
  246. default:
  247. break;
  248. }
  249. break;
  250. default:
  251. rt_kprintf("Compressed BMP files not supported\n");
  252. goto __exit;
  253. }
  254. bmp = (struct rtgui_image_bmp*) rtgui_malloc(sizeof(struct rtgui_image_bmp));
  255. if (bmp == RT_NULL)
  256. goto __exit;
  257. /* set image information */
  258. image->w = header->biWidth;
  259. image->h = header->biHeight;
  260. image->engine = &rtgui_image_bmp_engine;
  261. image->data = bmp;
  262. bmp->filerw = src;
  263. bmp->byte_per_pixel = header->biBitCount/8;
  264. bmp->pitch = image->w * bmp->byte_per_pixel;
  265. bmp->pixel_offset = header->bfOffBits;
  266. bmp->Rmask = Rmask; bmp->Gmask = Gmask; bmp->Bmask = Bmask;
  267. bmp->ExpandBMP = ExpandBMP;
  268. if (palette != RT_NULL) image->palette = palette;
  269. /* get padding */
  270. switch (ExpandBMP)
  271. {
  272. case 1:
  273. bmpPitch = (header->biWidth + 7) >> 3;
  274. bmp->pad = (((bmpPitch)%4) ? (4-((bmpPitch)%4)) : 0);
  275. break;
  276. case 4:
  277. bmpPitch = (header->biWidth + 1) >> 1;
  278. bmp->pad = (((bmpPitch)%4) ? (4-((bmpPitch)%4)) : 0);
  279. break;
  280. default:
  281. bmp->pad = ((bmp->pitch%4) ? (4-(bmp->pitch%4)) : 0);
  282. break;
  283. }
  284. if (load == RT_TRUE)
  285. {
  286. rt_uint8_t *bits;
  287. rt_uint32_t i;
  288. /* load all pixels */
  289. bmp->pixels = rtgui_malloc(image->h * bmp->pitch);
  290. if (bmp->pixels == RT_NULL)
  291. goto __exit;
  292. /* Read the pixels. Note that the bmp image is upside down */
  293. if ( rtgui_filerw_seek(src, bmp->pixel_offset, RTGUI_FILE_SEEK_SET) < 0)
  294. goto __exit;
  295. bits = bmp->pixels + image->h * bmp->pitch;
  296. while ( bits > bmp->pixels )
  297. {
  298. bits -= bmp->pitch;
  299. switch (ExpandBMP)
  300. {
  301. case 1:
  302. case 4:
  303. {
  304. rt_uint8_t pixel = 0;
  305. int shift = (8 - ExpandBMP);
  306. for ( i=0; i < image->w; ++i )
  307. {
  308. if ( i % (8/ExpandBMP) == 0 )
  309. {
  310. if ( !rtgui_filerw_read(src, &pixel, 1, 1) )
  311. goto __exit;
  312. }
  313. *(bits+i) = (pixel>>shift);
  314. pixel <<= ExpandBMP;
  315. }
  316. }
  317. break;
  318. default:
  319. if ( rtgui_filerw_read(src, bits, 1, bmp->pitch) != bmp->pitch ) goto __exit;
  320. break;
  321. }
  322. /* Skip padding bytes */
  323. if ( bmp->pad )
  324. {
  325. rt_uint8_t padbyte;
  326. for ( i=0; i < bmp->pad; ++i )
  327. {
  328. rtgui_filerw_read(src, &padbyte, 1, 1);
  329. }
  330. }
  331. }
  332. rtgui_filerw_close(bmp->filerw);
  333. bmp->line_pixels = RT_NULL;
  334. bmp->filerw = RT_NULL;
  335. bmp->pixel_offset = 0;
  336. }
  337. else
  338. {
  339. bmp->pixels = RT_NULL;
  340. bmp->line_pixels = rtgui_malloc(bmp->pitch);
  341. }
  342. return RT_TRUE;
  343. __exit:
  344. rtgui_free(header);
  345. if (palette != RT_NULL)
  346. {
  347. rtgui_free(palette);
  348. image->palette = RT_NULL;
  349. }
  350. if (bmp != RT_NULL)
  351. rtgui_free(bmp->pixels);
  352. rtgui_free(bmp);
  353. return RT_FALSE;
  354. }
  355. static void rtgui_image_bmp_unload(struct rtgui_image* image)
  356. {
  357. struct rtgui_image_bmp* bmp;
  358. if (image != RT_NULL)
  359. {
  360. bmp = (struct rtgui_image_bmp*) image->data;
  361. if (bmp->pixels != RT_NULL) rtgui_free(bmp->pixels);
  362. if (bmp->line_pixels != RT_NULL) rtgui_free(bmp->line_pixels);
  363. if (bmp->filerw != RT_NULL)
  364. {
  365. rtgui_filerw_close(bmp->filerw);
  366. bmp->filerw = RT_NULL;
  367. }
  368. /* release data */
  369. rtgui_free(bmp);
  370. }
  371. }
  372. static void rtgui_image_bmp_blit(struct rtgui_image* image, struct rtgui_dc* dc, struct rtgui_rect* dst_rect)
  373. {
  374. int y;
  375. rt_uint16_t w, h;
  376. struct rtgui_image_bmp* bmp;
  377. RT_ASSERT(image != RT_NULL || dc != RT_NULL || dst_rect != RT_NULL);
  378. /* this dc is not visible */
  379. if (rtgui_dc_get_visible(dc) != RT_TRUE) return;
  380. bmp = (struct rtgui_image_bmp*) image->data;
  381. RT_ASSERT(bmp != RT_NULL);
  382. /* the minimum rect */
  383. if (image->w < rtgui_rect_width(*dst_rect)) w = image->w;
  384. else w = rtgui_rect_width(*dst_rect);
  385. if (image->h < rtgui_rect_height(*dst_rect)) h = image->h;
  386. else h = rtgui_rect_height(*dst_rect);
  387. if (bmp->pixels != RT_NULL)
  388. {
  389. rt_uint8_t* ptr;
  390. /* get pixel pointer */
  391. ptr = bmp->pixels;
  392. if (bmp->byte_per_pixel == hw_driver->byte_per_pixel)
  393. {
  394. for (y = 0; y < h; y ++)
  395. {
  396. dc->engine->blit_line(dc,
  397. dst_rect->x1, dst_rect->x1 + w,
  398. dst_rect->y1 + y,
  399. ptr);
  400. ptr += bmp->pitch;
  401. }
  402. }
  403. else
  404. {
  405. rt_size_t pitch;
  406. rt_uint8_t *line_ptr;
  407. if (image->palette == RT_NULL)
  408. {
  409. rtgui_blit_line_func blit_line;
  410. line_ptr = (rt_uint8_t*) rtgui_malloc(hw_driver->byte_per_pixel * w);
  411. blit_line = rtgui_blit_line_get(hw_driver->byte_per_pixel , bmp->byte_per_pixel);
  412. pitch = w * bmp->byte_per_pixel;
  413. if (line_ptr != RT_NULL)
  414. {
  415. for (y = 0; y < h; y ++)
  416. {
  417. blit_line(line_ptr, ptr, pitch);
  418. dc->engine->blit_line(dc,
  419. dst_rect->x1, dst_rect->x1 + w,
  420. dst_rect->y1 + y,
  421. line_ptr);
  422. ptr += bmp->pitch;
  423. }
  424. }
  425. rtgui_free(line_ptr);
  426. }
  427. else
  428. {
  429. int x;
  430. rtgui_color_t color;
  431. /* use palette */
  432. for (y = 0; y < h; y ++)
  433. {
  434. ptr = bmp->pixels + (y * bmp->pitch);
  435. for (x = 0; x < w; x ++)
  436. {
  437. color = image->palette->colors[*ptr]; ptr ++;
  438. rtgui_dc_draw_color_point(dc, dst_rect->x1 + x, dst_rect->y1 + y, color);
  439. }
  440. }
  441. }
  442. }
  443. }
  444. else
  445. {
  446. int offset;
  447. rt_uint8_t *bits;
  448. /* calculate offset */
  449. switch (bmp->ExpandBMP)
  450. {
  451. case 1:
  452. offset = (image->h - h) * (image->w/8) * bmp->byte_per_pixel;
  453. break;
  454. case 4:
  455. offset = (image->h - h) * (image->w/2) * bmp->byte_per_pixel;
  456. break;
  457. default:
  458. offset = (image->h - h) * image->w * bmp->byte_per_pixel;
  459. break;
  460. }
  461. /* seek to the begin of pixel data */
  462. rtgui_filerw_seek(bmp->filerw, bmp->pixel_offset + offset, RTGUI_FILE_SEEK_SET);
  463. if (bmp->ExpandBMP == 1 || bmp->ExpandBMP == 4)
  464. {
  465. int x;
  466. rtgui_color_t color;
  467. /* 1, 4 bit per pixels */
  468. /* draw each line */
  469. for (y = h - 1; y >= 0; y --)
  470. {
  471. /* read pixel data */
  472. rt_uint8_t pixel = 0;
  473. int shift = (8 - bmp->ExpandBMP);
  474. int i;
  475. bits = bmp->line_pixels;
  476. for ( i=0; i < image->w; ++i )
  477. {
  478. if ( i % (8/bmp->ExpandBMP) == 0 )
  479. {
  480. if ( !rtgui_filerw_read(bmp->filerw, &pixel, 1, 1) )
  481. return;
  482. }
  483. *(bits+i) = (pixel>>shift);
  484. pixel <<= bmp->ExpandBMP;
  485. }
  486. /* Skip padding bytes */
  487. if (bmp->pad)
  488. {
  489. int i;
  490. rt_uint8_t padbyte;
  491. for ( i=0; i < bmp->pad; ++i )
  492. rtgui_filerw_read(bmp->filerw, &padbyte, 1, 1);
  493. }
  494. /* use palette */
  495. bits = bmp->line_pixels;
  496. for (x = 0; x < w; x ++)
  497. {
  498. color = image->palette->colors[*bits]; bits ++;
  499. rtgui_dc_draw_color_point(dc, dst_rect->x1 + x, dst_rect->y1 + y, color);
  500. }
  501. }
  502. }
  503. else
  504. {
  505. rt_uint8_t *line_ptr = (rt_uint8_t*) rtgui_malloc(hw_driver->byte_per_pixel * w);
  506. if (line_ptr == RT_NULL) return;
  507. /* draw each line */
  508. for (y = h - 1; y >= 0; y --)
  509. {
  510. /* read line pixels */
  511. rtgui_filerw_read(bmp->filerw, bmp->line_pixels, 1, bmp->pitch);
  512. /* Skip padding bytes */
  513. if (bmp->pad)
  514. {
  515. int i;
  516. rt_uint8_t padbyte;
  517. for ( i=0; i < bmp->pad; ++i )
  518. rtgui_filerw_read(bmp->filerw, &padbyte, 1, 1);
  519. }
  520. if (image->palette == RT_NULL)
  521. {
  522. int pitch;
  523. rtgui_blit_line_func blit_line;
  524. blit_line = rtgui_blit_line_get(hw_driver->byte_per_pixel , bmp->byte_per_pixel);
  525. pitch = w * bmp->byte_per_pixel;
  526. if (line_ptr != RT_NULL)
  527. {
  528. blit_line(line_ptr, bmp->line_pixels, pitch);
  529. dc->engine->blit_line(dc,
  530. dst_rect->x1, dst_rect->x1 + w,
  531. dst_rect->y1 + y,
  532. line_ptr);
  533. }
  534. }
  535. else
  536. {
  537. int x;
  538. rtgui_color_t color;
  539. /* use palette */
  540. bits = bmp->line_pixels;
  541. for (x = 0; x < w; x ++)
  542. {
  543. color = image->palette->colors[*bits]; bits ++;
  544. rtgui_dc_draw_color_point(dc, dst_rect->x1 + x, dst_rect->y1 + y, color);
  545. }
  546. }
  547. }
  548. if (line_ptr != RT_NULL) rtgui_free(line_ptr);
  549. }
  550. }
  551. }
  552. void rtgui_image_bmp_init()
  553. {
  554. /* register bmp on image system */
  555. rtgui_image_register_engine(&rtgui_image_bmp_engine);
  556. }