torgbv.c 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299
  1. #include <u.h>
  2. #include <libc.h>
  3. #include <bio.h>
  4. #include <draw.h>
  5. #include "imagefile.h"
  6. #include "rgbv.h"
  7. #include "ycbcr.h"
  8. #define CLAMPOFF 128
  9. static int clamp[CLAMPOFF+256+CLAMPOFF];
  10. static int inited;
  11. void*
  12. _remaperror(char *fmt, ...)
  13. {
  14. va_list arg;
  15. char buf[256];
  16. va_start(arg, fmt);
  17. vseprint(buf, buf+sizeof buf, fmt, arg);
  18. va_end(arg);
  19. werrstr(buf);
  20. return nil;
  21. }
  22. Rawimage*
  23. torgbv(Rawimage *i, int errdiff)
  24. {
  25. int j, k, rgb, x, y, er, eg, eb, col, t;
  26. int r, g, b, r1, g1, b1;
  27. int *ered, *egrn, *eblu, *rp, *gp, *bp;
  28. uint *map3;
  29. uchar *closest;
  30. Rawimage *im;
  31. int dx, dy;
  32. char err[ERRMAX];
  33. uchar *cmap, *cm, *in, *out, *inp, *outp, cmap1[3*256], map[256], *rpic, *bpic, *gpic;
  34. err[0] = '\0';
  35. errstr(err, sizeof err); /* throw it away */
  36. im = malloc(sizeof(Rawimage));
  37. if(im == nil)
  38. return nil;
  39. memset(im, 0, sizeof(Rawimage));
  40. im->chans[0] = malloc(i->chanlen);
  41. if(im->chans[0] == nil){
  42. free(im);
  43. return nil;
  44. }
  45. im->r = i->r;
  46. im->nchans = 1;
  47. im->chandesc = CRGBV;
  48. im->chanlen = i->chanlen;
  49. dx = i->r.max.x-i->r.min.x;
  50. dy = i->r.max.y-i->r.min.y;
  51. cmap = i->cmap;
  52. if(inited == 0){
  53. inited = 1;
  54. for(j=0; j<CLAMPOFF; j++)
  55. clamp[j] = 0;
  56. for(j=0; j<256; j++)
  57. clamp[CLAMPOFF+j] = (j>>4);
  58. for(j=0; j<CLAMPOFF; j++)
  59. clamp[CLAMPOFF+256+j] = (255>>4);
  60. }
  61. in = i->chans[0];
  62. inp = in;
  63. out = im->chans[0];
  64. outp = out;
  65. ered = malloc((dx+1)*sizeof(int));
  66. egrn = malloc((dx+1)*sizeof(int));
  67. eblu = malloc((dx+1)*sizeof(int));
  68. if(ered==nil || egrn==nil || eblu==nil){
  69. free(im->chans[0]);
  70. free(im);
  71. free(ered);
  72. free(egrn);
  73. free(eblu);
  74. return _remaperror("remap: malloc failed: %r");
  75. }
  76. memset(ered, 0, (dx+1)*sizeof(int));
  77. memset(egrn, 0, (dx+1)*sizeof(int));
  78. memset(eblu, 0, (dx+1)*sizeof(int));
  79. switch(i->chandesc){
  80. default:
  81. return _remaperror("remap: can't recognize channel type %d", i->chandesc);
  82. case CRGB1:
  83. if(cmap == nil)
  84. return _remaperror("remap: image has no color map");
  85. if(i->nchans != 1)
  86. return _remaperror("remap: can't handle nchans %d", i->nchans);
  87. for(j=1; j<=8; j++)
  88. if(i->cmaplen == 3*(1<<j))
  89. break;
  90. if(j > 8)
  91. return _remaperror("remap: can't do colormap size 3*%d", i->cmaplen/3);
  92. if(i->cmaplen != 3*256){
  93. /* to avoid a range check in inner loop below, make a full-size cmap */
  94. memmove(cmap1, cmap, i->cmaplen);
  95. cmap = cmap1;
  96. }
  97. if(errdiff == 0){
  98. k = 0;
  99. for(j=0; j<256; j++){
  100. r = cmap[k]>>4;
  101. g = cmap[k+1]>>4;
  102. b = cmap[k+2]>>4;
  103. k += 3;
  104. map[j] = closestrgb[b+16*(g+16*r)];
  105. }
  106. for(j=0; j<i->chanlen; j++)
  107. out[j] = map[in[j]];
  108. }else{
  109. /* modified floyd steinberg, coefficients (1 0) 3/16, (0, 1) 3/16, (1, 1) 7/16 */
  110. for(y=0; y<dy; y++){
  111. er = 0;
  112. eg = 0;
  113. eb = 0;
  114. rp = ered;
  115. gp = egrn;
  116. bp = eblu;
  117. for(x=0; x<dx; x++){
  118. cm = &cmap[3 * *inp++];
  119. r = cm[0] +*rp;
  120. g = cm[1] +*gp;
  121. b = cm[2] +*bp;
  122. /* sanity checks are new */
  123. if(r >= 256+CLAMPOFF)
  124. r = 0;
  125. if(g >= 256+CLAMPOFF)
  126. g = 0;
  127. if(b >= 256+CLAMPOFF)
  128. b = 0;
  129. r1 = clamp[r+CLAMPOFF];
  130. g1 = clamp[g+CLAMPOFF];
  131. b1 = clamp[b+CLAMPOFF];
  132. if(r1 >= 16 || g1 >= 16 || b1 >= 16)
  133. col = 0;
  134. else
  135. col = closestrgb[b1+16*(g1+16*r1)];
  136. *outp++ = col;
  137. rgb = rgbmap[col];
  138. r -= (rgb>>16) & 0xFF;
  139. t = (3*r)>>4;
  140. *rp++ = t+er;
  141. *rp += t;
  142. er = r-3*t;
  143. g -= (rgb>>8) & 0xFF;
  144. t = (3*g)>>4;
  145. *gp++ = t+eg;
  146. *gp += t;
  147. eg = g-3*t;
  148. b -= rgb & 0xFF;
  149. t = (3*b)>>4;
  150. *bp++ = t+eb;
  151. *bp += t;
  152. eb = b-3*t;
  153. }
  154. }
  155. }
  156. break;
  157. case CYCbCr:
  158. closest = closestycbcr;
  159. map3 = ycbcrmap;
  160. goto Threecolor;
  161. case CRGB:
  162. closest = closestrgb;
  163. map3 = rgbmap;
  164. Threecolor:
  165. if(i->nchans != 3)
  166. return _remaperror("remap: RGB image has %d channels", i->nchans);
  167. rpic = i->chans[0];
  168. gpic = i->chans[1];
  169. bpic = i->chans[2];
  170. if(errdiff == 0){
  171. for(j=0; j<i->chanlen; j++){
  172. r = rpic[j]>>4;
  173. g = gpic[j]>>4;
  174. b = bpic[j]>>4;
  175. out[j] = closest[b+16*(g+16*r)];
  176. }
  177. }else{
  178. /* modified floyd steinberg, coefficients (1 0) 3/16, (0, 1) 3/16, (1, 1) 7/16 */
  179. for(y=0; y<dy; y++){
  180. er = 0;
  181. eg = 0;
  182. eb = 0;
  183. rp = ered;
  184. gp = egrn;
  185. bp = eblu;
  186. for(x=0; x<dx; x++){
  187. r = *rpic++ + *rp;
  188. g = *gpic++ + *gp;
  189. b = *bpic++ + *bp;
  190. /*
  191. * Errors can be uncorrectable if converting from YCbCr,
  192. * since we can't guarantee that an extremal value of one of
  193. * the components selects a color with an extremal value.
  194. * If we don't, the errors accumulate without bound. This
  195. * doesn't happen in RGB because the closest table can guarantee
  196. * a color on the edge of the gamut, producing a zero error in
  197. * that component. For the rotation YCbCr space, there may be
  198. * no color that can guarantee zero error at the edge.
  199. * Therefore we must clamp explicitly rather than by assuming
  200. * an upper error bound of CLAMPOFF. The performance difference
  201. * is miniscule anyway.
  202. */
  203. if(r < 0)
  204. r = 0;
  205. else if(r > 255)
  206. r = 255;
  207. if(g < 0)
  208. g = 0;
  209. else if(g > 255)
  210. g = 255;
  211. if(b < 0)
  212. b = 0;
  213. else if(b > 255)
  214. b = 255;
  215. r1 = r>>4;
  216. g1 = g>>4;
  217. b1 = b>>4;
  218. col = closest[b1+16*(g1+16*r1)];
  219. *outp++ = col;
  220. rgb = map3[col];
  221. r -= (rgb>>16) & 0xFF;
  222. t = (3*r)>>4;
  223. *rp++ = t+er;
  224. *rp += t;
  225. er = r-3*t;
  226. g -= (rgb>>8) & 0xFF;
  227. t = (3*g)>>4;
  228. *gp++ = t+eg;
  229. *gp += t;
  230. eg = g-3*t;
  231. b -= rgb & 0xFF;
  232. t = (3*b)>>4;
  233. *bp++ = t+eb;
  234. *bp += t;
  235. eb = b-3*t;
  236. }
  237. }
  238. }
  239. break;
  240. case CY:
  241. if(i->nchans != 1)
  242. return _remaperror("remap: Y image has %d chans", i->nchans);
  243. rpic = i->chans[0];
  244. if(errdiff == 0){
  245. for(j=0; j<i->chanlen; j++){
  246. r = rpic[j]>>4;
  247. *outp++ = closestrgb[r+16*(r+16*r)];
  248. }
  249. }else{
  250. /* modified floyd steinberg, coefficients (1 0) 3/16, (0, 1) 3/16, (1, 1) 7/16 */
  251. for(y=0; y<dy; y++){
  252. er = 0;
  253. rp = ered;
  254. for(x=0; x<dx; x++){
  255. r = *inp++ + *rp;
  256. r1 = clamp[r+CLAMPOFF];
  257. col = closestrgb[r1+16*(r1+16*r1)];
  258. *outp++ = col;
  259. rgb = rgbmap[col];
  260. r -= (rgb>>16) & 0xFF;
  261. t = (3*r)>>4;
  262. *rp++ = t+er;
  263. *rp += t;
  264. er = r-3*t;
  265. }
  266. }
  267. }
  268. break;
  269. }
  270. free(ered);
  271. free(egrn);
  272. free(eblu);
  273. return im;
  274. }