writeppm.c 3.2 KB

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