writeppm.c 3.6 KB

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