onechan.c 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229
  1. #include <u.h>
  2. #include <libc.h>
  3. #include <draw.h>
  4. #include <memdraw.h>
  5. #include <bio.h>
  6. #include "imagefile.h"
  7. /* Convert image to a single channel, one byte per pixel */
  8. static
  9. int
  10. notrans(ulong chan)
  11. {
  12. switch(chan){
  13. case GREY1:
  14. case GREY2:
  15. case GREY4:
  16. case CMAP8:
  17. case GREY8:
  18. return 1;
  19. }
  20. return 0;
  21. }
  22. static
  23. int
  24. easycase(ulong chan)
  25. {
  26. switch(chan){
  27. case RGB16:
  28. case RGB24:
  29. case RGBA32:
  30. case ARGB32:
  31. return 1;
  32. }
  33. return 0;
  34. }
  35. /*
  36. * Convert to one byte per pixel, RGBV or grey, depending
  37. */
  38. static
  39. uchar*
  40. load(Image *image, Memimage *memimage)
  41. {
  42. uchar *data, *p, *q0, *q1, *q2;
  43. uchar *rgbv;
  44. int depth, ndata, dx, dy, i, v;
  45. ulong chan, pixel;
  46. Rectangle r;
  47. Rawimage ri, *nri;
  48. if(memimage == nil){
  49. r = image->r;
  50. depth = image->depth;
  51. chan = image->chan;
  52. }else{
  53. r = memimage->r;
  54. depth = memimage->depth;
  55. chan = memimage->chan;
  56. }
  57. dx = Dx(r);
  58. dy = Dy(r);
  59. /*
  60. * Read image data into memory
  61. * potentially one extra byte on each end of each scan line.
  62. */
  63. ndata = dy*(2+bytesperline(r, depth));
  64. data = malloc(ndata);
  65. if(data == nil)
  66. return nil;
  67. if(memimage != nil)
  68. ndata = unloadmemimage(memimage, r, data, ndata);
  69. else
  70. ndata = unloadimage(image, r, data, ndata);
  71. if(ndata < 0){
  72. werrstr("onechan: %r");
  73. free(data);
  74. return nil;
  75. }
  76. /*
  77. * Repack
  78. */
  79. memset(&ri, 0, sizeof(ri));
  80. ri.r = r;
  81. ri.cmap = nil;
  82. ri.cmaplen = 0;
  83. ri.nchans = 3;
  84. ri.chanlen = dx*dy;
  85. ri.chans[0] = malloc(ri.chanlen);
  86. ri.chans[1] = malloc(ri.chanlen);
  87. ri.chans[2] = malloc(ri.chanlen);
  88. if(ri.chans[0]==nil || ri.chans[1]==nil || ri.chans[2]==nil){
  89. Err:
  90. free(ri.chans[0]);
  91. free(ri.chans[1]);
  92. free(ri.chans[2]);
  93. free(data);
  94. return nil;
  95. }
  96. ri.chandesc = CRGB;
  97. p = data;
  98. q0 = ri.chans[0];
  99. q1 = ri.chans[1];
  100. q2 = ri.chans[2];
  101. switch(chan){
  102. default:
  103. werrstr("can't handle image type 0x%lux", chan);
  104. goto Err;
  105. case RGB16:
  106. for(i=0; i<ri.chanlen; i++, p+=2){
  107. pixel = (p[1]<<8)|p[0]; /* rrrrrggg gggbbbbb */
  108. v = (pixel & 0xF800) >> 8;
  109. *q0++ = v | (v>>5);
  110. v = (pixel & 0x07E0) >> 3;
  111. *q1++ = v | (v>>6);
  112. v = (pixel & 0x001F) << 3;
  113. *q2++ = v | (v>>5);
  114. }
  115. break;
  116. case RGB24:
  117. for(i=0; i<ri.chanlen; i++){
  118. *q2++ = *p++;
  119. *q1++ = *p++;
  120. *q0++ = *p++;
  121. }
  122. break;
  123. case RGBA32:
  124. for(i=0; i<ri.chanlen; i++){
  125. *q2++ = *p++;
  126. *q1++ = *p++;
  127. *q0++ = *p++;
  128. p++;
  129. }
  130. break;
  131. case ARGB32:
  132. for(i=0; i<ri.chanlen; i++){
  133. p++;
  134. *q2++ = *p++;
  135. *q1++ = *p++;
  136. *q0++ = *p++;
  137. }
  138. break;
  139. }
  140. rgbv = nil;
  141. nri = torgbv(&ri, 1);
  142. if(nri != nil){
  143. rgbv = nri->chans[0];
  144. free(nri);
  145. }
  146. free(ri.chans[0]);
  147. free(ri.chans[1]);
  148. free(ri.chans[2]);
  149. free(data);
  150. return rgbv;
  151. }
  152. Image*
  153. onechan(Image *i)
  154. {
  155. uchar *data;
  156. Image *ni;
  157. if(notrans(i->chan))
  158. return i;
  159. if(easycase(i->chan))
  160. data = load(i, nil);
  161. else{
  162. ni = allocimage(display, i->r, RGB24, 0, DNofill);
  163. if(ni == nil)
  164. return ni;
  165. draw(ni, ni->r, i, nil, i->r.min);
  166. data = load(ni, nil);
  167. freeimage(ni);
  168. }
  169. if(data == nil)
  170. return nil;
  171. ni = allocimage(display, i->r, CMAP8, 0, DNofill);
  172. if(ni != nil)
  173. if(loadimage(ni, ni->r, data, Dx(ni->r)*Dy(ni->r)) < 0){
  174. freeimage(ni);
  175. ni = nil;
  176. }
  177. free(data);
  178. return ni;
  179. }
  180. Memimage*
  181. memonechan(Memimage *i)
  182. {
  183. uchar *data;
  184. Memimage *ni;
  185. if(notrans(i->chan))
  186. return i;
  187. if(easycase(i->chan))
  188. data = load(nil, i);
  189. else{
  190. ni = allocmemimage(i->r, RGB24);
  191. if(ni == nil)
  192. return ni;
  193. memimagedraw(ni, ni->r, i, i->r.min, nil, ZP, S);
  194. data = load(nil, ni);
  195. freememimage(ni);
  196. }
  197. if(data == nil)
  198. return nil;
  199. ni = allocmemimage(i->r, CMAP8);
  200. if(ni != nil)
  201. if(loadmemimage(ni, ni->r, data, Dx(ni->r)*Dy(ni->r)) < 0){
  202. freememimage(ni);
  203. ni = nil;
  204. }
  205. free(data);
  206. return ni;
  207. }