readbmp.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626
  1. #include <u.h>
  2. #include <libc.h>
  3. #include <bio.h>
  4. #include <draw.h>
  5. #include "imagefile.h"
  6. #include "bmp.h"
  7. /*
  8. MS-BMP file reader
  9. (c) 2003, I.P.Keller
  10. aims to decode *all* valid bitmap formats, although some of the
  11. flavours couldn't be verified due to lack of suitable test-files.
  12. the following flavours are supported:
  13. Bit/Pix Orientation Compression Tested?
  14. 1 top->bottom n/a yes
  15. 1 bottom->top n/a yes
  16. 4 top->bottom no yes
  17. 4 bottom->top no yes
  18. 4 top->bottom RLE4 yes, but not with displacement
  19. 8 top->bottom no yes
  20. 8 bottom->top no yes
  21. 8 top->bottom RLE8 yes, but not with displacement
  22. 16 top->bottom no no
  23. 16 bottom->top no no
  24. 16 top->bottom BITMASK no
  25. 16 bottom->top BITMASK no
  26. 24 top->bottom n/a yes
  27. 24 bottom->top n/a yes
  28. 32 top->bottom no no
  29. 32 bottom->top no no
  30. 32 top->bottom BITMASK no
  31. 32 bottom->top BITMASK no
  32. OS/2 1.x bmp files are recognised as well, but testing was very limited.
  33. verifying was done with a number of test files, generated by
  34. different tools. nevertheless, the tests were in no way exhaustive
  35. enough to guarantee bug-free decoding. caveat emptor!
  36. */
  37. static short
  38. r16(Biobuf*b)
  39. {
  40. short s;
  41. s = Bgetc(b);
  42. s |= ((short)Bgetc(b)) << 8;
  43. return s;
  44. }
  45. static long
  46. r32(Biobuf*b)
  47. {
  48. long l;
  49. l = Bgetc(b);
  50. l |= ((long)Bgetc(b)) << 8;
  51. l |= ((long)Bgetc(b)) << 16;
  52. l |= ((long)Bgetc(b)) << 24;
  53. return l;
  54. }
  55. /* get highest bit set */
  56. static int
  57. msb(ulong x)
  58. {
  59. int i;
  60. for(i = 32; i; i--, x <<= 1)
  61. if(x & 0x80000000L)
  62. return i;
  63. return 0;
  64. }
  65. /* Load a 1-Bit encoded BMP file (uncompressed) */
  66. static int
  67. load_1T(Biobuf *b, long width, long height, Rgb* buf, Rgb* clut)
  68. {
  69. long ix, iy, i = 0, step_up = 0, padded_width = ((width + 31) / 32) * 32;
  70. int val = 0, n;
  71. if(height > 0) { /* bottom-up */
  72. i = (height - 1) * width;
  73. step_up = -2 * width;
  74. } else
  75. height = -height;
  76. for(iy = height; iy; iy--, i += step_up)
  77. for(ix = 0, n = 0; ix < padded_width; ix++, n--) {
  78. if(!n) {
  79. val = Bgetc(b);
  80. n = 8;
  81. }
  82. if(ix < width) {
  83. buf[i] = clut[val & 0x80 ? 1 : 0];
  84. i++;
  85. }
  86. val <<= 1;
  87. }
  88. return 0;
  89. }
  90. /* Load a 4-Bit encoded BMP file (uncompressed) */
  91. static int
  92. load_4T(Biobuf* b, long width, long height, Rgb* buf, Rgb* clut)
  93. {
  94. long ix, iy, i = 0, step_up = 0, skip = (4 - (((width % 8) + 1) / 2)) & 3;
  95. uint valH, valL;
  96. if(height > 0) { /* bottom-up */
  97. i = (height - 1) * width;
  98. step_up = -2 * width;
  99. } else
  100. height = -height;
  101. for(iy = height; iy; iy--, i += step_up) {
  102. for(ix = 0; ix < width; ) {
  103. valH = valL = Bgetc(b) & 0xff;
  104. valH >>= 4;
  105. buf[i] = clut[valH];
  106. i++; ix++;
  107. if(ix < width) {
  108. valL &= 0xf;
  109. buf[i] = clut[valL];
  110. i++; ix++;
  111. }
  112. }
  113. Bseek(b, skip, 1);
  114. }
  115. return 0;
  116. }
  117. /* Load a 4-Bit encoded BMP file (RLE4-compressed) */
  118. static int
  119. load_4C(Biobuf *b, long width, long height, Rgb* buf, Rgb* clut)
  120. {
  121. long ix, iy = height -1;
  122. uint val, valS, skip;
  123. Rgb* p;
  124. while(iy >= 0) {
  125. ix = 0;
  126. while(ix < width) {
  127. val = Bgetc(b);
  128. if(0 != val) {
  129. valS = (uint)Bgetc(b);
  130. p = &buf[ix + iy * width];
  131. while(val--) {
  132. *p = clut[0xf & (valS >> 4)];
  133. p++;
  134. ix++;
  135. if(0 < val) {
  136. *p = clut[0xf & valS];
  137. p++;
  138. ix++;
  139. val--;
  140. }
  141. }
  142. } else {
  143. /* Special modes... */
  144. val = Bgetc(b);
  145. switch(val) {
  146. case 0: /* End-Of-Line detected */
  147. ix = width;
  148. iy--;
  149. break;
  150. case 1: /* End-Of-Picture detected -->> abort */
  151. ix = width;
  152. iy = -1;
  153. break;
  154. case 2: /* Position change detected */
  155. val = Bgetc(b);
  156. ix += val;
  157. val = Bgetc(b);
  158. iy -= val;
  159. break;
  160. default:/* Transparent data sequence detected */
  161. p = &buf[ix + iy * width];
  162. if((1 == (val & 3)) || (2 == (val & 3)))
  163. skip = 1;
  164. else
  165. skip = 0;
  166. while(val--) {
  167. valS = (uint)Bgetc(b);
  168. *p = clut[0xf & (valS >> 4)];
  169. p++;
  170. ix++;
  171. if(0 < val) {
  172. *p = clut[0xf & valS];
  173. p++;
  174. ix++;
  175. val--;
  176. }
  177. }
  178. if(skip)
  179. Bgetc(b);
  180. break;
  181. }
  182. }
  183. }
  184. }
  185. return 0;
  186. }
  187. /* Load a 8-Bit encoded BMP file (uncompressed) */
  188. static int
  189. load_8T(Biobuf *b, long width, long height, Rgb* buf, Rgb* clut)
  190. {
  191. long ix, iy, i = 0, step_up = 0, skip = (4 - (width % 4)) & 3;
  192. if(height > 0) { /* bottom-up */
  193. i = (height - 1) * width;
  194. step_up = -2 * width;
  195. } else
  196. height = -height;
  197. for(iy = height; iy; iy--, i += step_up) {
  198. for(ix = 0; ix < width; ix++, i++)
  199. buf[i] = clut[Bgetc(b) & 0xff];
  200. Bseek(b, skip, 1);
  201. }
  202. return 0;
  203. }
  204. /* Load a 8-Bit encoded BMP file (RLE8-compressed) */
  205. static int
  206. load_8C(Biobuf *b, long width, long height, Rgb* buf, Rgb* clut)
  207. {
  208. long ix, iy = height -1;
  209. int val, valS, skip;
  210. Rgb* p;
  211. while(iy >= 0) {
  212. ix = 0;
  213. while(ix < width) {
  214. val = Bgetc(b);
  215. if(0 != val) {
  216. valS = Bgetc(b);
  217. p = &buf[ix + iy * width];
  218. while(val--) {
  219. *p = clut[valS];
  220. p++;
  221. ix++;
  222. }
  223. } else {
  224. /* Special modes... */
  225. val = Bgetc(b);
  226. switch(val) {
  227. case 0: /* End-Of-Line detected */
  228. ix = width;
  229. iy--;
  230. break;
  231. case 1: /* End-Of-Picture detected */
  232. ix = width;
  233. iy = -1;
  234. break;
  235. case 2: /* Position change detected */
  236. val = Bgetc(b);
  237. ix += val;
  238. val = Bgetc(b);
  239. iy -= val;
  240. break;
  241. default: /* Transparent (not compressed) sequence detected */
  242. p = &buf[ix + iy * width];
  243. if(val & 1)
  244. skip = 1;
  245. else
  246. skip = 0;
  247. while(val--) {
  248. valS = Bgetc(b);
  249. *p = clut[valS];
  250. p++;
  251. ix++;
  252. }
  253. if(skip)
  254. /* Align data stream */
  255. Bgetc(b);
  256. break;
  257. }
  258. }
  259. }
  260. }
  261. return 0;
  262. }
  263. /* Load a 16-Bit encoded BMP file (uncompressed) */
  264. static int
  265. load_16(Biobuf *b, long width, long height, Rgb* buf, Rgb* clut)
  266. {
  267. uchar c[2];
  268. long ix, iy, i = 0, step_up = 0;
  269. if(height > 0) { /* bottom-up */
  270. i = (height - 1) * width;
  271. step_up = -2 * width;
  272. } else
  273. height = -height;
  274. if(clut) {
  275. unsigned mask_blue = (unsigned)clut[0].blue +
  276. ((unsigned)clut[0].green << 8);
  277. unsigned mask_green = (unsigned)clut[1].blue +
  278. ((unsigned)clut[1].green << 8);
  279. unsigned mask_red = (unsigned)clut[2].blue +
  280. ((unsigned)clut[2].green << 8);
  281. int shft_blue = msb((ulong)mask_blue) - 8;
  282. int shft_green = msb((ulong)mask_green) - 8;
  283. int shft_red = msb((ulong)mask_red) - 8;
  284. for(iy = height; iy; iy--, i += step_up)
  285. for(ix = 0; ix < width; ix++, i++) {
  286. unsigned val;
  287. Bread(b, c, sizeof(c));
  288. val = (unsigned)c[0] + ((unsigned)c[1] << 8);
  289. buf[i].alpha = 0;
  290. if(shft_blue >= 0)
  291. buf[i].blue = (uchar)((val & mask_blue) >> shft_blue);
  292. else
  293. buf[i].blue = (uchar)((val & mask_blue) << -shft_blue);
  294. if(shft_green >= 0)
  295. buf[i].green = (uchar)((val & mask_green) >> shft_green);
  296. else
  297. buf[i].green = (uchar)((val & mask_green) << -shft_green);
  298. if(shft_red >= 0)
  299. buf[i].red = (uchar)((val & mask_red) >> shft_red);
  300. else
  301. buf[i].red = (uchar)((val & mask_red) << -shft_red);
  302. }
  303. } else
  304. for(iy = height; iy; iy--, i += step_up)
  305. for(ix = 0; ix < width; ix++, i++) {
  306. Bread(b, c, sizeof(c));
  307. buf[i].blue = (uchar)((c[0] << 3) & 0xf8);
  308. buf[i].green = (uchar)(((((unsigned)c[1] << 6) +
  309. (((unsigned)c[0]) >> 2))) & 0xf8);
  310. buf[i].red = (uchar)((c[1] << 1) & 0xf8);
  311. }
  312. return 0;
  313. }
  314. /* Load a 24-Bit encoded BMP file (uncompressed) */
  315. static int
  316. load_24T(Biobuf* b, long width, long height, Rgb* buf)
  317. {
  318. long ix, iy, i = 0, step_up = 0, skip = (4 - ((width * 3) % 4)) & 3;
  319. if(height > 0) { /* bottom-up */
  320. i = (height - 1) * width;
  321. step_up = -2 * width;
  322. } else
  323. height = -height;
  324. for(iy = height; iy; iy--, i += step_up) {
  325. for(ix = 0; ix < width; ix++, i++) {
  326. buf[i].alpha = 0;
  327. buf[i].blue = Bgetc(b);
  328. buf[i].green = Bgetc(b);
  329. buf[i].red = Bgetc(b);
  330. }
  331. Bseek(b, skip, 1);
  332. }
  333. return 0;
  334. }
  335. /* Load a 32-Bit encoded BMP file (uncompressed) */
  336. static int
  337. load_32(Biobuf *b, long width, long height, Rgb* buf, Rgb* clut)
  338. {
  339. uchar c[4];
  340. long ix, iy, i = 0, step_up = 0;
  341. if(height > 0) { /* bottom-up */
  342. i = (height - 1) * width;
  343. step_up = -2 * width;
  344. } else
  345. height = -height;
  346. if(clut) {
  347. ulong mask_blue = (ulong)clut[0].blue +
  348. ((ulong)clut[0].green << 8) +
  349. ((ulong)clut[0].red << 16) +
  350. ((ulong)clut[0].alpha << 24);
  351. ulong mask_green = (ulong)clut[1].blue +
  352. ((ulong)clut[1].green << 8) +
  353. ((ulong)clut[1].red << 16) +
  354. ((ulong)clut[1].alpha << 24);
  355. ulong mask_red = (ulong)clut[2].blue +
  356. ((ulong)clut[2].green << 8) +
  357. ((ulong)clut[2].red << 16) +
  358. ((ulong)clut[2].alpha << 24);
  359. int shft_blue = msb(mask_blue) - 8;
  360. int shft_green = msb(mask_green) - 8;
  361. int shft_red = msb(mask_red) - 8;
  362. for(iy = height; iy; iy--, i += step_up)
  363. for(ix = 0; ix < width; ix++, i++) {
  364. ulong val;
  365. Bread(b, c, sizeof(c));
  366. val = (ulong)c[0] + ((ulong)c[1] << 8) +
  367. ((ulong)c[2] << 16) + ((ulong)c[1] << 24);
  368. buf[i].alpha = 0;
  369. if(shft_blue >= 0)
  370. buf[i].blue = (uchar)((val & mask_blue) >> shft_blue);
  371. else
  372. buf[i].blue = (uchar)((val & mask_blue) << -shft_blue);
  373. if(shft_green >= 0)
  374. buf[i].green = (uchar)((val & mask_green) >> shft_green);
  375. else
  376. buf[i].green = (uchar)((val & mask_green) << -shft_green);
  377. if(shft_red >= 0)
  378. buf[i].red = (uchar)((val & mask_red) >> shft_red);
  379. else
  380. buf[i].red = (uchar)((val & mask_red) << -shft_red);
  381. }
  382. } else
  383. for(iy = height; iy; iy--, i += step_up)
  384. for(ix = 0; ix < width; ix++, i++) {
  385. Bread(b, c, nelem(c));
  386. buf[i].blue = c[0];
  387. buf[i].green = c[1];
  388. buf[i].red = c[2];
  389. }
  390. return 0;
  391. }
  392. static Rgb*
  393. ReadBMP(Biobuf *b, int *width, int *height)
  394. {
  395. int colours, num_coltab = 0;
  396. Filehdr bmfh;
  397. Infohdr bmih;
  398. Rgb clut[256];
  399. Rgb* buf;
  400. bmfh.type = r16(b);
  401. if(bmfh.type != 0x4d42) /* signature must be 'BM' */
  402. sysfatal("bad magic number, not a BMP file");
  403. bmfh.size = r32(b);
  404. bmfh.reserved1 = r16(b);
  405. bmfh.reserved2 = r16(b);
  406. bmfh.offbits = r32(b);
  407. memset(&bmih, 0, sizeof(bmih));
  408. bmih.size = r32(b);
  409. if(bmih.size == 0x0c) { /* OS/2 1.x version */
  410. bmih.width = r16(b);
  411. bmih.height = r16(b);
  412. bmih.planes = r16(b);
  413. bmih.bpp = r16(b);
  414. bmih.compression = BMP_RGB;
  415. } else { /* Windows */
  416. bmih.width = r32(b);
  417. bmih.height = r32(b);
  418. bmih.planes = r16(b);
  419. bmih.bpp = r16(b);
  420. bmih.compression = r32(b);
  421. bmih.imagesize = r32(b);
  422. bmih.hres = r32(b);
  423. bmih.vres = r32(b);
  424. bmih.colours = r32(b);
  425. bmih.impcolours = r32(b);
  426. }
  427. if(bmih.bpp < 16) {
  428. /* load colour table */
  429. if(bmih.impcolours)
  430. num_coltab = (int)bmih.impcolours;
  431. else
  432. num_coltab = 1 << bmih.bpp;
  433. } else if(bmih.compression == BMP_BITFIELDS &&
  434. (bmih.bpp == 16 || bmih.bpp == 32))
  435. /* load bitmasks */
  436. num_coltab = 3;
  437. if(num_coltab) {
  438. int i;
  439. Bseek(b, bmih.size + sizeof(Infohdr), 0);
  440. for(i = 0; i < num_coltab; i++) {
  441. clut[i].blue = (uchar)Bgetc(b);
  442. clut[i].green = (uchar)Bgetc(b);
  443. clut[i].red = (uchar)Bgetc(b);
  444. clut[i].alpha = (uchar)Bgetc(b);
  445. }
  446. }
  447. *width = bmih.width;
  448. *height = bmih.height;
  449. colours = bmih.bpp;
  450. Bseek(b, bmfh.offbits, 0);
  451. if ((buf = calloc(sizeof(Rgb), *width * abs(*height))) == nil)
  452. sysfatal("no memory");
  453. switch(colours) {
  454. case 1:
  455. load_1T(b, *width, *height, buf, clut);
  456. break;
  457. case 4:
  458. if(bmih.compression == BMP_RLE4)
  459. load_4C(b, *width, *height, buf, clut);
  460. else
  461. load_4T(b, *width, *height, buf, clut);
  462. break;
  463. case 8:
  464. if(bmih.compression == BMP_RLE8)
  465. load_8C(b, *width, *height, buf, clut);
  466. else
  467. load_8T(b, *width, *height, buf, clut);
  468. break;
  469. case 16:
  470. load_16(b, *width, *height, buf,
  471. bmih.compression == BMP_BITFIELDS ? clut : nil);
  472. break;
  473. case 24:
  474. load_24T(b, *width, *height, buf);
  475. break;
  476. case 32:
  477. load_32(b, *width, *height, buf,
  478. bmih.compression == BMP_BITFIELDS ? clut : nil);
  479. break;
  480. }
  481. return buf;
  482. }
  483. Rawimage**
  484. Breadbmp(Biobuf *bp, int colourspace)
  485. {
  486. Rawimage *a, **array;
  487. int c, width, height;
  488. uchar *r, *g, *b;
  489. Rgb *s, *e;
  490. Rgb *bmp;
  491. char ebuf[128];
  492. a = nil;
  493. bmp = nil;
  494. array = nil;
  495. USED(a);
  496. USED(bmp);
  497. if (colourspace != CRGB) {
  498. errstr(ebuf, sizeof ebuf); /* throw it away */
  499. werrstr("ReadRGB: unknown colour space %d", colourspace);
  500. return nil;
  501. }
  502. if ((bmp = ReadBMP(bp, &width, &height)) == nil)
  503. return nil;
  504. if ((a = calloc(sizeof(Rawimage), 1)) == nil)
  505. goto Error;
  506. for (c = 0; c < 3; c++)
  507. if ((a->chans[c] = calloc(width, height)) == nil)
  508. goto Error;
  509. if ((array = calloc(sizeof(Rawimage *), 2)) == nil)
  510. goto Error;
  511. array[0] = a;
  512. array[1] = nil;
  513. a->nchans = 3;
  514. a->chandesc = CRGB;
  515. a->chanlen = width * height;
  516. a->r = Rect(0, 0, width, height);
  517. s = bmp;
  518. e = s + width * height;
  519. r = a->chans[0];
  520. g = a->chans[1];
  521. b = a->chans[2];
  522. do {
  523. *r++ = s->red;
  524. *g++ = s->green;
  525. *b++ = s->blue;
  526. }while(++s < e);
  527. free(bmp);
  528. return array;
  529. Error:
  530. if (a)
  531. for (c = 0; c < 3; c++)
  532. if (a->chans[c])
  533. free(a->chans[c]);
  534. if (a)
  535. free(a);
  536. if (array)
  537. free(array);
  538. if (bmp)
  539. free(bmp);
  540. return nil;
  541. }
  542. Rawimage**
  543. readbmp(int fd, int colorspace)
  544. {
  545. Rawimage * *a;
  546. Biobuf b;
  547. if (Binit(&b, fd, OREAD) < 0)
  548. return nil;
  549. a = Breadbmp(&b, colorspace);
  550. Bterm(&b);
  551. return a;
  552. }