torgbv.c 7.0 KB

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