image_bmp.c 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977
  1. /*
  2. * Change Logs:
  3. * Date Author Notes
  4. * 2012-01-24 onelife Reimplement to improve efficiency and add
  5. * features. The new decoder uses configurable fixed size working buffer and
  6. * provides scaledown function.
  7. */
  8. #include <rtthread.h>
  9. #include <rtgui/dc_hw.h>
  10. #include <rtgui/image.h>
  11. #include <rtgui/rtgui_system.h>
  12. #include <rtgui/image_bmp.h>
  13. #include <rtgui/blit.h>
  14. #include <math.h>
  15. #ifdef RTGUI_USING_DFS_FILERW
  16. #include <dfs_posix.h>
  17. #endif
  18. #ifdef RTGUI_IMAGE_BMP
  19. /* Compression encodings for BMP files */
  20. #ifndef BI_RGB
  21. #define BI_RGB 0
  22. #define BI_RLE8 1
  23. #define BI_RLE4 2
  24. #define BI_BITFIELDS 3
  25. #endif
  26. #define BMP_WORKING_BUFFER_SIZE (384) /* In multiple of 12 and bigger than 48 */
  27. #define BMP_MAX_SCALING_FACTOR (10) // TODO: find the max value!
  28. #define hw_driver (rtgui_graphic_driver_get_default())
  29. struct rtgui_image_bmp
  30. {
  31. rt_bool_t is_loaded;
  32. rt_uint8_t *pixels;
  33. struct rtgui_filerw *filerw;
  34. rt_uint32_t w, h;
  35. rt_uint32_t pixel_offset;
  36. rt_uint32_t pitch;
  37. rt_uint8_t scale;
  38. rt_uint8_t bit_per_pixel;
  39. rt_uint8_t pad;
  40. };
  41. static rt_bool_t rtgui_image_bmp_check(struct rtgui_filerw *file);
  42. static rt_bool_t rtgui_image_bmp_load(struct rtgui_image *image, struct rtgui_filerw *file, rt_bool_t load);
  43. static void rtgui_image_bmp_unload(struct rtgui_image *image);
  44. static void rtgui_image_bmp_blit(struct rtgui_image *image, struct rtgui_dc *dc, struct rtgui_rect *rect);
  45. struct rtgui_image_engine rtgui_image_bmp_engine =
  46. {
  47. "bmp",
  48. { RT_NULL },
  49. rtgui_image_bmp_check,
  50. rtgui_image_bmp_load,
  51. rtgui_image_bmp_unload,
  52. rtgui_image_bmp_blit,
  53. };
  54. static rt_bool_t rtgui_image_bmp_check(struct rtgui_filerw *file)
  55. {
  56. rt_uint8_t buffer[18];
  57. rt_bool_t is_bmp = RT_FALSE;
  58. do
  59. {
  60. if (!file)
  61. {
  62. break;
  63. }
  64. /* Prepare to decode */
  65. if (rtgui_filerw_seek(file, 0, RTGUI_FILE_SEEK_SET) < 0)
  66. {
  67. break;
  68. }
  69. if (rtgui_filerw_read(file, (void *)buffer, 18, 1) != 18)
  70. {
  71. break;
  72. }
  73. /* Read file type */
  74. if (buffer[0] != 'B' || buffer[1] != 'M')
  75. {
  76. break;
  77. }
  78. /* Read BMP header size */
  79. if (*(rt_uint32_t *)&buffer[14] == 12)
  80. {
  81. /* Bitmap Header Version 2.x */
  82. if (rtgui_filerw_read(file, (void *)buffer, 8, 1) != 8)
  83. {
  84. break;
  85. }
  86. /* Read image size */
  87. is_bmp = RT_TRUE;
  88. }
  89. else
  90. {
  91. /* Bitmap Header Version bigger than 2.x */
  92. if (rtgui_filerw_read(file, (void *)buffer, 8, 1) != 8)
  93. {
  94. break;
  95. }
  96. /* Read image size */
  97. is_bmp = RT_TRUE;
  98. }
  99. } while (0);
  100. return is_bmp;
  101. }
  102. static struct rtgui_image_palette *rtgui_image_bmp_load_palette(
  103. struct rtgui_filerw *file,
  104. rt_uint32_t colorsUsed,
  105. rt_bool_t alpha)
  106. {
  107. /* Load the palette, if any */
  108. rt_uint32_t i;
  109. struct rtgui_image_palette *palette;
  110. palette = rtgui_image_palette_create(colorsUsed);
  111. if (palette == RT_NULL)
  112. {
  113. return RT_NULL;
  114. }
  115. palette->ncolors = colorsUsed;
  116. if (alpha)
  117. {
  118. rt_uint8_t temp[4];
  119. for (i = 0; i < colorsUsed; i++)
  120. {
  121. if (rtgui_filerw_read(file, (void *)&temp, 1, 4) != 4)
  122. {
  123. rtgui_free(palette);
  124. return RT_NULL;
  125. }
  126. palette->colors[i] = RTGUI_ARGB(temp[3], temp[2], temp[1], temp[0]);
  127. }
  128. }
  129. else
  130. {
  131. rt_uint8_t temp[3];
  132. for (i = 0; i < colorsUsed; i++)
  133. {
  134. if (rtgui_filerw_read(file, (void *)&temp, 1, 3) != 3)
  135. {
  136. rtgui_free(palette);
  137. return RT_NULL;
  138. }
  139. palette->colors[i] = RTGUI_RGB(temp[2], temp[1], temp[0]);
  140. }
  141. }
  142. return palette;
  143. }
  144. static rt_bool_t rtgui_image_bmp_load(struct rtgui_image *image, struct rtgui_filerw *file, rt_bool_t load)
  145. {
  146. rt_uint8_t scale = 0;
  147. rt_uint8_t *wrkBuffer = RT_NULL;
  148. struct rtgui_image_bmp *bmp = RT_NULL;
  149. rt_uint32_t bmpHeaderSize;
  150. rt_uint32_t colorsUsed;
  151. if (scale > BMP_MAX_SCALING_FACTOR)
  152. {
  153. return RT_FALSE;
  154. }
  155. do
  156. {
  157. wrkBuffer = (rt_uint8_t *)rtgui_malloc(BMP_WORKING_BUFFER_SIZE);
  158. if (wrkBuffer == RT_NULL)
  159. {
  160. rt_kprintf("BMP err: no mem\n");
  161. break;
  162. }
  163. bmp = (struct rtgui_image_bmp *)rtgui_malloc(sizeof(struct rtgui_image_bmp));
  164. if (bmp == RT_NULL)
  165. {
  166. break;
  167. }
  168. bmp->pixels = RT_NULL;
  169. /* Prepare to decode */
  170. if (rtgui_filerw_seek(file, 0, RTGUI_FILE_SEEK_SET) < 0)
  171. {
  172. break;
  173. }
  174. if (rtgui_filerw_read(file, (void *)wrkBuffer, 18, 1) != 18)
  175. {
  176. break;
  177. }
  178. /* Read file type */
  179. if (wrkBuffer[0] != 'B' || wrkBuffer[1] != 'M')
  180. {
  181. break;
  182. }
  183. /* Read pixel array offset */
  184. bmp->pixel_offset = *(rt_uint32_t *)&wrkBuffer[10];
  185. /* Read BMP header size */
  186. bmpHeaderSize = *(rt_uint32_t *)&wrkBuffer[14];
  187. colorsUsed = 0;
  188. if (bmpHeaderSize == 12)
  189. {
  190. /* Bitmap Header Version 2.x */
  191. if (rtgui_filerw_read(file, (void *)wrkBuffer, 8, 1) != 8)
  192. {
  193. break;
  194. }
  195. /* Read image size */
  196. bmp->w = (rt_uint32_t) * (rt_uint16_t *)&wrkBuffer[0];
  197. bmp->h = (rt_uint32_t) * (rt_uint16_t *)&wrkBuffer[2];
  198. /* Read bits per pixel */
  199. bmp->bit_per_pixel = (rt_uint8_t) * (rt_uint16_t *)&wrkBuffer[6];
  200. }
  201. else
  202. {
  203. /* Bitmap Header Version bigger than 2.x */
  204. rt_uint32_t compression;
  205. if (rtgui_filerw_read(file, (void *)wrkBuffer, 36, 1) != 36)
  206. {
  207. break;
  208. }
  209. /* Read image size */
  210. bmp->w = *(rt_uint32_t *)&wrkBuffer[0];
  211. bmp->h = *(rt_uint32_t *)&wrkBuffer[4];
  212. /* Read bits per pixel */
  213. bmp->bit_per_pixel = (rt_uint8_t) * (rt_uint16_t *)&wrkBuffer[10];
  214. if (bmp->bit_per_pixel > 32)
  215. {
  216. rt_kprintf("BMP err: unsupported format\n");
  217. break;
  218. }
  219. /* Read compression method */
  220. compression = *(rt_uint32_t *)&wrkBuffer[12];
  221. if (compression != BI_RGB && compression != BI_BITFIELDS)
  222. {
  223. rt_kprintf("BMP err: unsupported format\n");
  224. break;
  225. }
  226. /* Read number of colors */
  227. colorsUsed = *(rt_uint32_t *)&wrkBuffer[28];
  228. }
  229. if (!colorsUsed)
  230. {
  231. colorsUsed = 1 << bmp->bit_per_pixel;
  232. }
  233. /* Load palette */
  234. if (bmp->bit_per_pixel <= 8)
  235. {
  236. if (rtgui_filerw_seek(file, 14 + bmpHeaderSize, RTGUI_FILE_SEEK_SET) < 0)
  237. {
  238. break;
  239. }
  240. image->palette = rtgui_image_bmp_load_palette(file, colorsUsed,
  241. bmpHeaderSize > 12 ? RT_TRUE : RT_FALSE);
  242. if (image->palette == RT_NULL)
  243. {
  244. break;
  245. }
  246. }
  247. /* Set image information */
  248. bmp->is_loaded = RT_FALSE;
  249. bmp->scale = scale;
  250. if (bmp->bit_per_pixel == 1)
  251. {
  252. bmp->pitch = (bmp->w + 7) >> 3;
  253. }
  254. else if (bmp->bit_per_pixel == 4)
  255. {
  256. bmp->pitch = (bmp->w + 1) >> 1;
  257. }
  258. else
  259. {
  260. bmp->pitch = bmp->w * (bmp->bit_per_pixel >> 3);
  261. }
  262. bmp->pad = ((bmp->pitch % 4) ? (4 - (bmp->pitch % 4)) : 0);
  263. bmp->filerw = file;
  264. image->w = (rt_uint16_t)bmp->w >> bmp->scale;
  265. image->h = (rt_uint16_t)bmp->h >> bmp->scale;
  266. image->engine = &rtgui_image_bmp_engine;
  267. image->data = bmp;
  268. /* Start to decode */
  269. if (load == RT_TRUE)
  270. {
  271. rt_bool_t error = RT_FALSE;
  272. rt_uint8_t *dst;
  273. rt_uint32_t imageWidth;
  274. rt_uint16_t readLength, readIndex, loadIndex;
  275. rt_uint8_t skipLength;
  276. rt_uint16_t y;
  277. rt_uint8_t bytePerPixel;
  278. rt_int8_t scale1, scale2;
  279. bytePerPixel = _UI_BITBYTES(bmp->bit_per_pixel);
  280. imageWidth = image->w * bytePerPixel; /* Scaled width in byte */
  281. bmp->pixels = rtgui_malloc(image->h * imageWidth);
  282. if (bmp->pixels == RT_NULL)
  283. {
  284. rt_kprintf("BMP err: no mem to load (%d)\n", image->h * imageWidth);
  285. break;
  286. }
  287. /* Read the pixels. Note that the bmp image is upside down */
  288. if (rtgui_filerw_seek(file, bmp->pixel_offset, RTGUI_FILE_SEEK_SET) < 0)
  289. {
  290. break;
  291. }
  292. if (bmp->bit_per_pixel == 1)
  293. {
  294. if (bmp->scale > 3)
  295. {
  296. scale1 = bmp->scale - 3;
  297. scale2 = 3;
  298. }
  299. else
  300. {
  301. scale1 = 0;
  302. scale2 = bmp->scale;
  303. }
  304. }
  305. else if (bmp->bit_per_pixel == 4)
  306. {
  307. if (bmp->scale > 1)
  308. {
  309. scale1 = bmp->scale - 1;
  310. scale2 = 1;
  311. }
  312. else
  313. {
  314. scale1 = 0;
  315. scale2 = bmp->scale;
  316. }
  317. }
  318. /* Process whole image */
  319. y = 0;
  320. while (y < image->h)
  321. {
  322. dst = bmp->pixels + (image->h - y - 1) * imageWidth;
  323. readIndex = 0;
  324. skipLength = 0;
  325. /* Process a line */
  326. while (readIndex < bmp->pitch)
  327. {
  328. /* Read data to buffer */
  329. readLength = (BMP_WORKING_BUFFER_SIZE > ((rt_uint16_t)bmp->pitch - readIndex)) ? \
  330. ((rt_uint16_t)bmp->pitch - readIndex) : BMP_WORKING_BUFFER_SIZE;
  331. if (rtgui_filerw_read(file, (void *)wrkBuffer, 1, readLength) != readLength)
  332. {
  333. rt_kprintf("BMP err: read failed\n");
  334. error = RT_TRUE;
  335. break;
  336. }
  337. readIndex += readLength;
  338. /* Process read buffer */
  339. if (bmp->bit_per_pixel == 1)
  340. {
  341. rt_uint8_t j;
  342. for (loadIndex = skipLength; loadIndex < readLength; loadIndex += 1 << scale1)
  343. {
  344. for (j = 0; j < 8; j += 1 << scale2)
  345. {
  346. *(dst++) = (wrkBuffer[loadIndex] & (1 << (7 - j))) >> (7 - j);
  347. }
  348. }
  349. if (scale1 && (readLength % (1 << scale1)))
  350. {
  351. skipLength = (1 << scale1) - readLength % (1 << scale1);
  352. }
  353. }
  354. else if (bmp->bit_per_pixel == 4)
  355. {
  356. rt_uint8_t j;
  357. for (loadIndex = skipLength; loadIndex < readLength; loadIndex += 1 << scale1)
  358. {
  359. for (j = 0; j < 8; j += 1 << (2 + scale2))
  360. {
  361. *(dst++) = (wrkBuffer[loadIndex] & (0x0F << (4 - j))) >> (4 - j);
  362. }
  363. }
  364. if (scale1 && (readLength % (1 << scale1)))
  365. {
  366. skipLength = (1 << scale1) - readLength % (1 << scale1);
  367. }
  368. }
  369. else
  370. {
  371. if (bmp->scale == 0)
  372. {
  373. rt_memcpy((void *)dst, (void *)wrkBuffer, readLength);
  374. dst += readLength;
  375. }
  376. else
  377. {
  378. for (loadIndex = skipLength; loadIndex < readLength; loadIndex += bytePerPixel << bmp->scale)
  379. {
  380. rt_memcpy((void *)dst, (void *)&wrkBuffer[loadIndex], bytePerPixel);
  381. dst += bytePerPixel;
  382. }
  383. if (readLength % (1 << bmp->scale))
  384. {
  385. skipLength = (1 << bmp->scale) - readLength % (1 << bmp->scale);
  386. }
  387. }
  388. }
  389. }
  390. if (error)
  391. {
  392. break;
  393. }
  394. y++;
  395. /* Skip padding bytes */
  396. if (bmp->pad)
  397. {
  398. if (rtgui_filerw_seek(file, bmp->pad, RTGUI_FILE_SEEK_CUR) < 0)
  399. {
  400. error = RT_TRUE;
  401. break;
  402. }
  403. }
  404. /* Height scale down */
  405. if (bmp->scale)
  406. {
  407. if (rtgui_filerw_seek(file, (bmp->pitch + bmp->pad) * ((1 << bmp->scale) - 1),
  408. RTGUI_FILE_SEEK_CUR) < 0)
  409. {
  410. error = RT_TRUE;
  411. break;
  412. }
  413. }
  414. }
  415. if (error)
  416. {
  417. break;
  418. }
  419. /* Close file */
  420. rtgui_filerw_close(bmp->filerw);
  421. bmp->filerw = RT_NULL;
  422. bmp->is_loaded = RT_TRUE;
  423. }
  424. /* Release memory */
  425. rtgui_free(wrkBuffer);
  426. return RT_TRUE;
  427. } while (0);
  428. /* Release memory */
  429. rtgui_free(wrkBuffer);
  430. rtgui_free(image->palette);
  431. if (bmp)
  432. rtgui_free(bmp->pixels);
  433. rtgui_free(bmp);
  434. return RT_FALSE;
  435. }
  436. static void rtgui_image_bmp_unload(struct rtgui_image *image)
  437. {
  438. struct rtgui_image_bmp *bmp;
  439. if (image != RT_NULL)
  440. {
  441. bmp = (struct rtgui_image_bmp *)image->data;
  442. /* Release memory */
  443. rtgui_free(bmp->pixels);
  444. if (bmp->filerw != RT_NULL)
  445. {
  446. /* Close file */
  447. rtgui_filerw_close(bmp->filerw);
  448. bmp->filerw = RT_NULL;
  449. }
  450. rtgui_free(bmp);
  451. }
  452. }
  453. static void rtgui_image_bmp_blit(struct rtgui_image *image, struct rtgui_dc *dc, struct rtgui_rect *dst_rect)
  454. {
  455. rt_uint16_t w, h;
  456. struct rtgui_image_bmp *bmp;
  457. rt_uint8_t bytePerPixel;
  458. rt_uint32_t imageWidth;
  459. rt_bool_t error;
  460. bmp = (struct rtgui_image_bmp *)image->data;
  461. RT_ASSERT(image != RT_NULL || dc != RT_NULL || dst_rect != RT_NULL || bmp != RT_NULL);
  462. bytePerPixel = _UI_BITBYTES(bmp->bit_per_pixel);
  463. imageWidth = image->w * bytePerPixel; /* Scaled width in byte */
  464. error = RT_FALSE;
  465. do
  466. {
  467. /* this dc is not visible */
  468. if (rtgui_dc_get_visible(dc) != RT_TRUE) break;
  469. /* the minimum rect */
  470. w = _UI_MIN(image->w, rtgui_rect_width(*dst_rect));
  471. h = _UI_MIN(image->h, rtgui_rect_height(*dst_rect));
  472. if (!bmp->is_loaded)
  473. {
  474. rt_uint8_t *wrkBuffer;
  475. rt_uint16_t readLength, readIndex, loadIndex;
  476. rt_uint8_t skipLength;
  477. rt_uint16_t x, y;
  478. rt_int8_t scale1, scale2;
  479. rt_uint16_t y_start = dst_rect->y1 + h - 1;
  480. /* Read the pixels. Note that the bmp image is upside down */
  481. if (rtgui_filerw_seek(bmp->filerw, bmp->pixel_offset, RTGUI_FILE_SEEK_SET) < 0)
  482. {
  483. break;
  484. }
  485. /* the image is upside down. So we need to start from middle if the
  486. * image is higher than the dst_rect. */
  487. if (image->h > rtgui_rect_height(*dst_rect))
  488. {
  489. int hdelta = image->h - rtgui_rect_height(*dst_rect);
  490. if (rtgui_filerw_seek(bmp->filerw, hdelta * (bmp->pitch + bmp->pad) * (1 << bmp->scale),
  491. RTGUI_FILE_SEEK_CUR) < 0)
  492. {
  493. error = RT_TRUE;
  494. break;
  495. }
  496. }
  497. if (bmp->bit_per_pixel == 1)
  498. {
  499. if (bmp->scale > 3)
  500. {
  501. scale1 = bmp->scale - 3;
  502. scale2 = 3;
  503. }
  504. else
  505. {
  506. scale1 = 0;
  507. scale2 = bmp->scale;
  508. }
  509. }
  510. else if (bmp->bit_per_pixel == 4)
  511. {
  512. if (bmp->scale > 1)
  513. {
  514. scale1 = bmp->scale - 1;
  515. scale2 = 1;
  516. }
  517. else
  518. {
  519. scale1 = 0;
  520. scale2 = bmp->scale;
  521. }
  522. }
  523. wrkBuffer = (rt_uint8_t *)rtgui_malloc(
  524. (BMP_WORKING_BUFFER_SIZE > bmp->pitch) ? \
  525. bmp->pitch : BMP_WORKING_BUFFER_SIZE);
  526. if (wrkBuffer == RT_NULL)
  527. {
  528. rt_kprintf("BMP err: no mem (%d)\n", BMP_WORKING_BUFFER_SIZE);
  529. break;
  530. }
  531. /* Process whole image */
  532. y = 0;
  533. while (y < h)
  534. {
  535. x = 0;
  536. readIndex = 0;
  537. skipLength = 0;
  538. /* Process a line */
  539. while (readIndex < bmp->pitch)
  540. {
  541. /* Read data to buffer */
  542. readLength = (BMP_WORKING_BUFFER_SIZE > ((rt_uint16_t)bmp->pitch - readIndex)) ? \
  543. ((rt_uint16_t)bmp->pitch - readIndex) : BMP_WORKING_BUFFER_SIZE;
  544. if (rtgui_filerw_read(bmp->filerw, (void *)wrkBuffer, 1, readLength) != readLength)
  545. {
  546. rt_kprintf("BMP err: read failed\n");
  547. error = RT_TRUE;
  548. break;
  549. }
  550. readIndex += readLength;
  551. /* Process read buffer */
  552. if (bmp->bit_per_pixel == 1)
  553. {
  554. for (loadIndex = skipLength; loadIndex < readLength; loadIndex += 1 << scale1)
  555. {
  556. rt_uint8_t j;
  557. for (j = 0; j < 8; j += 1 << scale2)
  558. {
  559. rtgui_color_t color;
  560. color = image->palette->colors[(wrkBuffer[loadIndex] & (1 << (7 - j))) >> (7 - j)];
  561. rtgui_dc_draw_color_point(dc,
  562. dst_rect->x1 + x++,
  563. y_start - y,
  564. color);
  565. if (x >= w)
  566. break;
  567. }
  568. if (scale1 && (readLength % (1 << scale1)))
  569. {
  570. skipLength = (1 << scale1) - readLength % (1 << scale1);
  571. }
  572. }
  573. }
  574. else if (bmp->bit_per_pixel == 4)
  575. {
  576. for (loadIndex = skipLength; loadIndex < readLength; loadIndex += 1 << scale1)
  577. {
  578. rt_uint8_t j;
  579. for (j = 0; j < 8; j += 1 << (2 + scale2))
  580. {
  581. rtgui_color_t color;
  582. color = image->palette->colors[(wrkBuffer[loadIndex] & (0x0F << (4 - j))) >> (4 - j)];
  583. rtgui_dc_draw_color_point(dc,
  584. dst_rect->x1 + x++,
  585. y_start - y,
  586. color);
  587. if (x >= w)
  588. break;
  589. }
  590. }
  591. if (scale1 && (readLength % (1 << scale1)))
  592. {
  593. skipLength = (1 << scale1) - readLength % (1 << scale1);
  594. }
  595. }
  596. else if (bmp->bit_per_pixel == 8)
  597. {
  598. for (loadIndex = skipLength; loadIndex < readLength; loadIndex += 1 << bmp->scale)
  599. {
  600. rtgui_color_t color;
  601. color = image->palette->colors[wrkBuffer[loadIndex]];
  602. rtgui_dc_draw_color_point(dc,
  603. dst_rect->x1 + x++,
  604. y_start - y,
  605. color);
  606. if (x >= w)
  607. break;
  608. }
  609. if (readLength % (1 << bmp->scale))
  610. {
  611. skipLength = (1 << bmp->scale) - readLength % (1 << bmp->scale);
  612. }
  613. }
  614. else
  615. {
  616. rtgui_blit_line_func blit_line;
  617. rt_uint8_t hw_bytePerPixel = _UI_BITBYTES(hw_driver->bits_per_pixel);
  618. rt_uint8_t temp[4] = {0};
  619. if (!hw_bytePerPixel)
  620. {
  621. hw_bytePerPixel = 1;
  622. }
  623. if (hw_driver->pixel_format == RTGRAPHIC_PIXEL_FORMAT_BGR565)
  624. {
  625. blit_line = rtgui_blit_line_get_inv(hw_bytePerPixel, bytePerPixel);
  626. }
  627. else
  628. {
  629. blit_line = rtgui_blit_line_get(hw_bytePerPixel, bytePerPixel);
  630. }
  631. for (loadIndex = skipLength;
  632. loadIndex < readLength;
  633. loadIndex += bytePerPixel << bmp->scale)
  634. {
  635. blit_line(temp, &wrkBuffer[loadIndex], bytePerPixel);
  636. dc->engine->blit_line(dc,
  637. dst_rect->x1 + x, dst_rect->x1 + x + 1,
  638. y_start - y,
  639. temp);
  640. x++;
  641. if (x >= w)
  642. break;
  643. }
  644. if (readLength % (1 << bmp->scale))
  645. {
  646. skipLength = (1 << bmp->scale) - readLength % (1 << bmp->scale);
  647. }
  648. }
  649. }
  650. if (error)
  651. {
  652. break;
  653. }
  654. y++;
  655. /* Skip padding bytes */
  656. if (bmp->pad)
  657. {
  658. if (rtgui_filerw_seek(bmp->filerw, bmp->pad, RTGUI_FILE_SEEK_CUR) < 0)
  659. {
  660. error = RT_TRUE;
  661. break;
  662. }
  663. }
  664. /* Height scale down */
  665. if (bmp->scale)
  666. {
  667. if (rtgui_filerw_seek(bmp->filerw, (bmp->pitch + bmp->pad) * ((1 << bmp->scale) - 1),
  668. RTGUI_FILE_SEEK_CUR) < 0)
  669. {
  670. error = RT_TRUE;
  671. break;
  672. }
  673. }
  674. }
  675. if (error)
  676. {
  677. break;
  678. }
  679. /* Release memory */
  680. rtgui_free(wrkBuffer);
  681. }
  682. else
  683. {
  684. rt_uint16_t x, y;
  685. rt_uint8_t *ptr;
  686. if (bmp->bit_per_pixel <= 8)
  687. {
  688. rtgui_color_t color;
  689. /* 1bpp, and using palette */
  690. for (y = 0; y < h; y ++)
  691. {
  692. ptr = bmp->pixels + (y * imageWidth);
  693. for (x = 0; x < w; x ++)
  694. {
  695. color = image->palette->colors[*(ptr++)];
  696. rtgui_dc_draw_color_point(dc,
  697. dst_rect->x1 + x, dst_rect->y1 + y,
  698. color);
  699. }
  700. }
  701. }
  702. else
  703. {
  704. rtgui_blit_line_func blit_line;
  705. rt_uint8_t hw_bytePerPixel = _UI_BITBYTES(hw_driver->bits_per_pixel);
  706. rt_uint8_t *line_data;
  707. if (hw_driver->pixel_format == RTGRAPHIC_PIXEL_FORMAT_BGR565)
  708. {
  709. blit_line = rtgui_blit_line_get_inv(hw_bytePerPixel, bytePerPixel);
  710. }
  711. else
  712. {
  713. blit_line = rtgui_blit_line_get(hw_bytePerPixel, bytePerPixel);
  714. }
  715. line_data = (rt_uint8_t *)rtgui_malloc(w * rtgui_color_get_bpp(hw_driver->pixel_format));
  716. if (line_data == RT_NULL) break; /* out of memory */
  717. ptr = bmp->pixels;
  718. for (y = 0; y < h; y ++)
  719. {
  720. blit_line(line_data, ptr, bytePerPixel * w);
  721. ptr += imageWidth;
  722. dc->engine->blit_line(dc, dst_rect->x1, dst_rect->x1 + w,
  723. dst_rect->y1 + y, line_data);
  724. }
  725. rtgui_free(line_data);
  726. }
  727. }
  728. } while (0);
  729. }
  730. /*
  731. * config bitmap header.
  732. */
  733. void rtgui_image_bmp_header_cfg(struct rtgui_image_bmp_header *bhr, rt_int32_t w, rt_int32_t h, rt_uint16_t bits_per_pixel)
  734. {
  735. int image_size = w * h * _UI_BITBYTES(bits_per_pixel);
  736. int header_size = sizeof(struct rtgui_image_bmp_header);
  737. bhr->bfType = 0x4d42; /* BM */
  738. bhr->bfSize = header_size + image_size; /* data size */
  739. bhr->bfReserved1 = 0;
  740. bhr->bfReserved2 = 0;
  741. bhr->bfOffBits = header_size;
  742. bhr->biSize = 40; /* sizeof BITMAPINFOHEADER */
  743. bhr->biWidth = w;
  744. bhr->biHeight = h;
  745. bhr->biPlanes = 1;
  746. bhr->biBitCount = bits_per_pixel;
  747. bhr->biCompression = BI_BITFIELDS;
  748. bhr->biSizeImage = image_size;
  749. bhr->biXPelsPerMeter = 0;
  750. bhr->biYPelsPerMeter = 0;
  751. bhr->biClrUsed = 0;
  752. bhr->biClrImportant = 0;
  753. if (bhr->biBitCount == 16 && bhr->biCompression == BI_BITFIELDS)
  754. {
  755. bhr->bfSize += 12;
  756. bhr->bfOffBits += 12;
  757. }
  758. }
  759. #ifdef RTGUI_USING_DFS_FILERW
  760. #define WRITE_CLUSTER_SIZE 2048
  761. void bmp_align_write(struct rtgui_filerw *file, char *dest, char *src, rt_int32_t len, rt_int32_t *count)
  762. {
  763. rt_int32_t len_bak = len;
  764. while (len)
  765. {
  766. if (*count >= WRITE_CLUSTER_SIZE)
  767. {
  768. rtgui_filerw_write(file, dest, WRITE_CLUSTER_SIZE, 1);
  769. *count = 0;
  770. }
  771. *(dest + *count) = *(src + (len_bak - len));
  772. len --;
  773. (*count) ++;
  774. }
  775. }
  776. /*
  777. * Grab screen and save as a BMP file
  778. * MACRO RGB_CONVERT_TO_BGR: If the pixel of colors is BGR mode, defined it.
  779. */
  780. void screenshot(const char *filename)
  781. {
  782. struct rtgui_filerw *file;
  783. int w, h, i, pitch;
  784. rt_uint16_t *src;
  785. rt_uint32_t mask;
  786. struct rtgui_image_bmp_header bhr;
  787. struct rtgui_graphic_driver *grp = hw_driver;
  788. #ifdef RGB_CONVERT_TO_BGR
  789. int j;
  790. rt_uint16_t *line_buf;
  791. rt_uint16_t color, tmp;
  792. #endif
  793. char *pixel_buf;
  794. rt_int32_t write_count = 0;
  795. file = rtgui_filerw_create_file(filename, "wb");
  796. if (file == RT_NULL)
  797. {
  798. rt_kprintf("create file failed\n");
  799. return;
  800. }
  801. w = grp->width;
  802. h = grp->height;
  803. pitch = w * sizeof(rt_uint16_t);
  804. #ifdef RGB_CONVERT_TO_BGR
  805. line_buf = rt_malloc(pitch);
  806. if (line_buf == RT_NULL)
  807. {
  808. rt_kprintf("no memory!\n");
  809. return;
  810. }
  811. #endif
  812. pixel_buf = rt_malloc(WRITE_CLUSTER_SIZE);
  813. if (pixel_buf == RT_NULL)
  814. {
  815. rt_kprintf("no memory!\n");
  816. #ifdef RGB_CONVERT_TO_BGR
  817. rt_free(line_buf);
  818. #endif
  819. return;
  820. }
  821. rtgui_image_bmp_header_cfg(&bhr, w, h, grp->bits_per_pixel);
  822. bmp_align_write(file, pixel_buf, (char *)&bhr,
  823. sizeof(struct rtgui_image_bmp_header), &write_count);
  824. if (bhr.biCompression == BI_BITFIELDS)
  825. {
  826. mask = 0xF800; /* Red Mask */
  827. bmp_align_write(file, pixel_buf, (char *)&mask, 4, &write_count);
  828. mask = 0x07E0; /* Green Mask */
  829. bmp_align_write(file, pixel_buf, (char *)&mask, 4, &write_count);
  830. mask = 0x001F; /* Blue Mask */
  831. bmp_align_write(file, pixel_buf, (char *)&mask, 4, &write_count);
  832. }
  833. rtgui_screen_lock(RT_WAITING_FOREVER);
  834. if (grp->framebuffer != RT_NULL)
  835. {
  836. src = (rt_uint16_t *)grp->framebuffer;
  837. src += w * h;
  838. for (i = 0; i < h; i++)
  839. {
  840. src -= w;
  841. #ifdef RGB_CONVERT_TO_BGR
  842. for (j = 0; j < w; j++)
  843. {
  844. tmp = *(src + j);
  845. color = (tmp & 0x001F) << 11;
  846. color += (tmp & 0x07E0);
  847. color += (tmp & 0xF800) >> 11;
  848. *(line_buf + i) = color;
  849. }
  850. bmp_align_write(file, pixel_buf, (char *)line_buf, pitch, &write_count);
  851. #else
  852. bmp_align_write(file, pixel_buf, (char *)src, pitch, &write_count);
  853. #endif
  854. }
  855. }
  856. else
  857. {
  858. rtgui_color_t pixel_color;
  859. rt_uint16_t write_color;
  860. int x;
  861. for (i = h - 1; i >= 0; i--)
  862. {
  863. x = 0;
  864. if (i % 10 == 0)rt_kprintf(">", i);
  865. while (x < w)
  866. {
  867. grp->ops->get_pixel(&pixel_color, x, i);
  868. write_color = rtgui_color_to_565p(pixel_color);
  869. bmp_align_write(file, pixel_buf, (char *)&write_color,
  870. sizeof(rt_uint16_t), &write_count);
  871. x++;
  872. }
  873. }
  874. }
  875. /* write The tail of the last */
  876. if (write_count < WRITE_CLUSTER_SIZE)
  877. rtgui_filerw_write(file, pixel_buf, write_count, 1);
  878. rtgui_screen_unlock();
  879. #ifdef RGB_CONVERT_TO_BGR
  880. rt_free(line_buf);
  881. #endif
  882. rt_free(pixel_buf);
  883. rt_kprintf("bmp create succeed.\n");
  884. rtgui_filerw_close(file);
  885. }
  886. #ifdef RT_USING_FINSH
  887. #include <finsh.h>
  888. FINSH_FUNCTION_EXPORT(screenshot, usage: screenshot(filename));
  889. #endif
  890. #endif
  891. void rtgui_image_bmp_init()
  892. {
  893. /* register bmp on image system */
  894. rtgui_image_register_engine(&rtgui_image_bmp_engine);
  895. }
  896. #endif