writeppm.c 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214
  1. #include <u.h>
  2. #include <lib9.h>
  3. #include <draw.h>
  4. #include <memdraw.h>
  5. #include <bio.h>
  6. #define MAXLINE 70
  7. /* imported from libdraw/arith.c to permit an extern log2 function */
  8. static int log2[] = {
  9. -1, 0, 1, -1, 2, -1, -1, -1, 3, -1, -1, -1, -1, -1, -1, -1, 4,
  10. -1, -1, -1, -1, -1, -1, -1, 4 /* BUG */, -1, -1, -1, -1, -1, -1, -1, 5
  11. };
  12. static int bitc = 0;
  13. static int nbit = 0;
  14. static
  15. void
  16. Bputbit(Biobufhdr *b, int c)
  17. {
  18. if(c >= 0x0){
  19. bitc = (bitc << 1) | (c & 0x1);
  20. nbit++;
  21. }else if(nbit > 0){
  22. for(; nbit < 8; nbit++)
  23. bitc <<= 1;
  24. }
  25. if(nbit == 8){
  26. Bputc(b, bitc);
  27. bitc = nbit = 0;
  28. }
  29. }
  30. /*
  31. * Write data
  32. */
  33. static
  34. char*
  35. writedata(Biobuf *fd, Image *image, Memimage *memimage, int rflag)
  36. {
  37. char *err;
  38. unsigned char *data;
  39. int i, x, y, ndata, depth, col, pix, xmask, pmask;
  40. uint32_t chan;
  41. Rectangle r;
  42. if(memimage != nil){
  43. r = memimage->r;
  44. depth = memimage->depth;
  45. chan = memimage->chan;
  46. }else{
  47. r = image->r;
  48. depth = image->depth;
  49. chan = image->chan;
  50. }
  51. /*
  52. * Read image data into memory
  53. * potentially one extra byte on each end of each scan line
  54. */
  55. ndata = Dy(r)*(2+Dx(r)*depth/8);
  56. data = malloc(ndata);
  57. if(data == nil)
  58. return "WritePPM: malloc failed";
  59. if(memimage != nil)
  60. ndata = unloadmemimage(memimage, r, data, ndata);
  61. else
  62. ndata = unloadimage(image, r, data, ndata);
  63. if(ndata < 0){
  64. err = malloc(ERRMAX);
  65. if(err == nil)
  66. return "WritePPM: malloc failed";
  67. snprint(err, ERRMAX, "WritePPM: %r");
  68. free(data);
  69. return err;
  70. }
  71. /* Encode and emit the data */
  72. col = 0;
  73. switch(chan){
  74. case GREY1:
  75. case GREY2:
  76. case GREY4:
  77. pmask = (1<<depth)-1;
  78. xmask = 7>>log2[depth];
  79. for(y=r.min.y; y<r.max.y; y++){
  80. i = (y-r.min.y)*bytesperline(r, depth);
  81. for(x=r.min.x; x<r.max.x; x++){
  82. pix = (data[i]>>depth*((xmask-x)&xmask))&pmask;
  83. if(((x+1)&xmask) == 0)
  84. i++;
  85. if(chan == GREY1){
  86. pix ^= 1;
  87. if(rflag){
  88. Bputbit(fd, pix);
  89. continue;
  90. }
  91. } else {
  92. if(rflag){
  93. Bputc(fd, pix);
  94. continue;
  95. }
  96. }
  97. col += Bprint(fd, "%d", pix);
  98. if(col >= MAXLINE-(2+1)){
  99. Bprint(fd, "\n");
  100. col = 0;
  101. }else if(y < r.max.y-1 || x < r.max.x-1)
  102. col += Bprint(fd, " ");
  103. }
  104. if(rflag)
  105. Bputbit(fd, -1);
  106. }
  107. break;
  108. case GREY8:
  109. for(i=0; i<ndata; i++){
  110. if(rflag){
  111. Bputc(fd, data[i]);
  112. continue;
  113. }
  114. col += Bprint(fd, "%d", data[i]);
  115. if(col >= MAXLINE-(4+1)){
  116. Bprint(fd, "\n");
  117. col = 0;
  118. }else if(i < ndata-1)
  119. col += Bprint(fd, " ");
  120. }
  121. break;
  122. case RGB24:
  123. for(i=0; i<ndata; i+=3){
  124. if(rflag){
  125. Bputc(fd, data[i+2]);
  126. Bputc(fd, data[i+1]);
  127. Bputc(fd, data[i]);
  128. continue;
  129. }
  130. col += Bprint(fd, "%d %d %d", data[i+2], data[i+1], data[i]);
  131. if(col >= MAXLINE-(4+4+4+1)){
  132. Bprint(fd, "\n");
  133. col = 0;
  134. }else if(i < ndata-3)
  135. col += Bprint(fd, " ");
  136. }
  137. break;
  138. default:
  139. return "WritePPM: can't handle channel type";
  140. }
  141. return nil;
  142. }
  143. static
  144. char*
  145. writeppm0(Biobuf *fd, Image *image, Memimage *memimage, Rectangle r, int chan, char *comment, int rflag)
  146. {
  147. char *err;
  148. switch(chan){
  149. case GREY1:
  150. Bprint(fd, "%s\n", rflag? "P4": "P1");
  151. break;
  152. case GREY2:
  153. case GREY4:
  154. case GREY8:
  155. Bprint(fd, "%s\n", rflag? "P5": "P2");
  156. break;
  157. case RGB24:
  158. Bprint(fd, "%s\n", rflag? "P6": "P3");
  159. break;
  160. default:
  161. return "WritePPM: can't handle channel type";
  162. }
  163. if(comment!=nil && comment[0]!='\0'){
  164. Bprint(fd, "# %s", comment);
  165. if(comment[strlen(comment)-1] != '\n')
  166. Bprint(fd, "\n");
  167. }
  168. Bprint(fd, "%d %d\n", Dx(r), Dy(r));
  169. /* maximum pixel value */
  170. switch(chan){
  171. case GREY2:
  172. Bprint(fd, "%d\n", 3);
  173. break;
  174. case GREY4:
  175. Bprint(fd, "%d\n", 15);
  176. break;
  177. case GREY8:
  178. case RGB24:
  179. Bprint(fd, "%d\n", 255);
  180. break;
  181. }
  182. err = writedata(fd, image, memimage, rflag);
  183. if(!rflag)
  184. Bprint(fd, "\n");
  185. Bflush(fd);
  186. return err;
  187. }
  188. char*
  189. writeppm(Biobuf *fd, Image *image, char *comment, int rflag)
  190. {
  191. return writeppm0(fd, image, nil, image->r, image->chan, comment, rflag);
  192. }
  193. char*
  194. memwriteppm(Biobuf *fd, Memimage *memimage, char *comment, int rflag)
  195. {
  196. return writeppm0(fd, nil, memimage, memimage->r, memimage->chan, comment, rflag);
  197. }