torgbv.c 7.4 KB

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