image_bmp.c 31 KB

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