readppm.c 4.0 KB

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