writeppm.c 3.0 KB

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