readppm.c 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237
  1. #include <u.h>
  2. #include <lib9.h>
  3. #include <bio.h>
  4. #include <draw.h>
  5. #include <chartypes.h>
  6. #include "imagefile.h"
  7. Rawimage *readppm(Biobuf*, Rawimage*);
  8. /*
  9. * fetch a non-comment character.
  10. */
  11. static
  12. int
  13. Bgetch(Biobufhdr *b)
  14. {
  15. int c;
  16. for(;;) {
  17. c = Bgetc(b);
  18. if(c == '#') {
  19. while((c = Bgetc(b)) != Beof && c != '\n')
  20. ;
  21. }
  22. return c;
  23. }
  24. }
  25. /*
  26. * fetch a nonnegative decimal integer.
  27. */
  28. static
  29. int
  30. Bgetint(Biobufhdr *b)
  31. {
  32. int c;
  33. int i;
  34. while((c = Bgetch(b)) != Beof && !isdigit(c))
  35. ;
  36. if(c == Beof)
  37. return -1;
  38. i = 0;
  39. do {
  40. i = i*10 + (c-'0');
  41. } while((c = Bgetch(b)) != Beof && isdigit(c));
  42. return i;
  43. }
  44. static
  45. int
  46. Bgetdecimalbit(Biobufhdr *b)
  47. {
  48. int c;
  49. while((c = Bgetch(b)) != Beof && c != '0' && c != '1')
  50. ;
  51. if(c == Beof)
  52. return -1;
  53. return c == '1';
  54. }
  55. static int bitc, nbit;
  56. static
  57. int
  58. Bgetbit(Biobufhdr *b)
  59. {
  60. if(nbit == 0) {
  61. nbit = 8;
  62. bitc = Bgetc(b);
  63. if(bitc == -1)
  64. return -1;
  65. }
  66. nbit--;
  67. return (bitc >> nbit) & 0x1;
  68. }
  69. static
  70. void
  71. Bflushbit(Biobufhdr* _)
  72. {
  73. nbit = 0;
  74. }
  75. Rawimage**
  76. readpixmap(int fd, int colorspace)
  77. {
  78. Rawimage **array, *a;
  79. Biobuf b;
  80. char buf[ERRMAX];
  81. int i;
  82. char *e;
  83. USED(colorspace);
  84. if(Binit(&b, fd, OREAD) < 0)
  85. return nil;
  86. werrstr("");
  87. e = "out of memory";
  88. if((array = malloc(sizeof *array)) == nil)
  89. goto Error;
  90. if((array[0] = malloc(sizeof *array[0])) == nil)
  91. goto Error;
  92. memset(array[0], 0, sizeof *array[0]);
  93. for(i=0; i<3; i++)
  94. array[0]->chans[i] = nil;
  95. e = "bad file format";
  96. switch(Bgetc(&b)) {
  97. case 'P':
  98. Bungetc(&b);
  99. a = readppm(&b, array[0]);
  100. break;
  101. default:
  102. a = nil;
  103. break;
  104. }
  105. if(a == nil)
  106. goto Error;
  107. array[0] = a;
  108. return array;
  109. Error:
  110. if(array)
  111. free(array[0]);
  112. free(array);
  113. sys_errstr(buf, sizeof buf);
  114. if(buf[0] == 0)
  115. strcpy(buf, e);
  116. sys_errstr(buf, sizeof buf);
  117. return nil;
  118. }
  119. typedef struct Pix Pix;
  120. struct Pix {
  121. char magic;
  122. int maxcol;
  123. int (*fetch)(Biobufhdr*);
  124. int nchan;
  125. int chandesc;
  126. int invert;
  127. void (*flush)(Biobufhdr*);
  128. };
  129. static Pix pix[] = {
  130. { '1', 1, Bgetdecimalbit, 1, CY, 1, nil }, /* portable bitmap */
  131. { '4', 1, Bgetbit, 1, CY, 1, Bflushbit }, /* raw portable bitmap */
  132. { '2', 0, Bgetint, 1, CY, 0, nil }, /* portable greymap */
  133. { '5', 0, Bgetc, 1, CY, 0, nil }, /* raw portable greymap */
  134. { '3', 0, Bgetint, 3, CRGB, 0, nil }, /* portable pixmap */
  135. { '6', 0, Bgetc, 3, CRGB, 0, nil }, /* raw portable pixmap */
  136. { 0 },
  137. };
  138. Rawimage*
  139. readppm(Biobuf *b, Rawimage *a)
  140. {
  141. int i, ch, wid, ht, r, c;
  142. int maxcol, nchan, invert;
  143. int (*fetch)(Biobufhdr*);
  144. unsigned char *rgb[3];
  145. char buf[ERRMAX];
  146. char *e;
  147. Pix *p;
  148. e = "bad file format";
  149. if(Bgetc(b) != 'P')
  150. goto Error;
  151. c = Bgetc(b);
  152. for(p=pix; p->magic; p++)
  153. if(p->magic == c)
  154. break;
  155. if(p->magic == 0)
  156. goto Error;
  157. wid = Bgetint(b);
  158. ht = Bgetint(b);
  159. if(wid <= 0 || ht <= 0)
  160. goto Error;
  161. a->r = Rect(0,0,wid,ht);
  162. maxcol = p->maxcol;
  163. if(maxcol == 0) {
  164. maxcol = Bgetint(b);
  165. if(maxcol <= 0)
  166. goto Error;
  167. }
  168. e = "out of memory";
  169. for(i=0; i<p->nchan; i++)
  170. if((rgb[i] = a->chans[i] = malloc(wid*ht)) == nil)
  171. goto Error;
  172. a->nchans = p->nchan;
  173. a->chanlen = wid*ht;
  174. a->chandesc = p->chandesc;
  175. e = "error reading file";
  176. fetch = p->fetch;
  177. nchan = p->nchan;
  178. invert = p->invert;
  179. for(r=0; r<ht; r++) {
  180. for(c=0; c<wid; c++) {
  181. for(i=0; i<nchan; i++) {
  182. if((ch = (*fetch)(b)) < 0)
  183. goto Error;
  184. if(invert)
  185. ch = maxcol - ch;
  186. *rgb[i]++ = (ch * 255)/maxcol;
  187. }
  188. }
  189. if(p->flush)
  190. (*p->flush)(b);
  191. }
  192. return a;
  193. Error:
  194. sys_errstr(buf, sizeof buf);
  195. if(buf[0] == 0)
  196. strcpy(buf, e);
  197. sys_errstr(buf, sizeof buf);
  198. for(i=0; i<3; i++)
  199. free(a->chans[i]);
  200. free(a->cmap);
  201. return nil;
  202. }