totruecolor.c 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172
  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. enum {
  15. c1 = 2871, /* 1.402 * 2048 */
  16. c2 = 705, /* 0.34414 * 2048 */
  17. c3 = 1463, /* 0.71414 * 2048 */
  18. c4 = 3629, /* 1.772 * 2048 */
  19. };
  20. Rawimage*
  21. totruecolor(Rawimage *i, int chandesc)
  22. {
  23. int j, k;
  24. Rawimage *im;
  25. char err[ERRMAX];
  26. uint8_t *rp, *gp, *bp, *cmap, *inp, *outp, cmap1[3*256];
  27. int r, g, b, Y, Cr, Cb;
  28. if(chandesc!=CY && chandesc!=CRGB24)
  29. return _remaperror("remap: can't convert to chandesc %d", chandesc);
  30. err[0] = '\0';
  31. errstr(err, sizeof err); /* throw it away */
  32. im = malloc(sizeof(Rawimage));
  33. if(im == nil)
  34. return nil;
  35. memset(im, 0, sizeof(Rawimage));
  36. if(chandesc == CY)
  37. im->chanlen = i->chanlen;
  38. else
  39. im->chanlen = 3*i->chanlen;
  40. im->chandesc = chandesc;
  41. im->chans[0] = malloc(im->chanlen);
  42. if(im->chans[0] == nil){
  43. free(im);
  44. return nil;
  45. }
  46. im->r = i->r;
  47. im->nchans = 1;
  48. cmap = i->cmap;
  49. outp = im->chans[0];
  50. switch(i->chandesc){
  51. default:
  52. return _remaperror("remap: can't recognize channel type %d", i->chandesc);
  53. case CY:
  54. if(i->nchans != 1)
  55. return _remaperror("remap: Y image has %d chans", i->nchans);
  56. if(chandesc == CY){
  57. memmove(im->chans[0], i->chans[0], i->chanlen);
  58. break;
  59. }
  60. /* convert to three color */
  61. inp = i->chans[0];
  62. for(j=0; j<i->chanlen; j++){
  63. k = *inp++;
  64. *outp++ = k;
  65. *outp++ = k;
  66. *outp++ = k;
  67. }
  68. break;
  69. case CRGB1:
  70. if(cmap == nil)
  71. return _remaperror("remap: image has no color map");
  72. if(i->nchans != 1)
  73. return _remaperror("remap: can't handle nchans %d", i->nchans);
  74. for(j=1; j<=8; j++)
  75. if(i->cmaplen == 3*(1<<j))
  76. break;
  77. if(j > 8)
  78. return _remaperror("remap: can't do colormap size 3*%d", i->cmaplen/3);
  79. if(i->cmaplen != 3*256){
  80. /* to avoid a range check in loop below, make a full-size cmap */
  81. memmove(cmap1, cmap, i->cmaplen);
  82. cmap = cmap1;
  83. }
  84. inp = i->chans[0];
  85. if(chandesc == CY){
  86. for(j=0; j<i->chanlen; j++){
  87. k = *inp++;
  88. r = cmap[3*k+2];
  89. g = cmap[3*k+1];
  90. b = cmap[3*k+0];
  91. r = (2125*r + 7154*g + 721*b)/10000; /* Poynton page 84 */
  92. *outp++ = r;
  93. }
  94. }else{
  95. for(j=0; j<i->chanlen; j++){
  96. k = *inp++;
  97. *outp++ = cmap[3*k+2];
  98. *outp++ = cmap[3*k+1];
  99. *outp++ = cmap[3*k+0];
  100. }
  101. }
  102. break;
  103. case CRGB:
  104. if(i->nchans != 3)
  105. return _remaperror("remap: can't handle nchans %d", i->nchans);
  106. rp = i->chans[0];
  107. gp = i->chans[1];
  108. bp = i->chans[2];
  109. if(chandesc == CY){
  110. for(j=0; j<i->chanlen; j++){
  111. r = *bp++;
  112. g = *gp++;
  113. b = *rp++;
  114. r = (2125*r + 7154*g + 721*b)/10000; /* Poynton page 84 */
  115. *outp++ = r;
  116. }
  117. }else
  118. for(j=0; j<i->chanlen; j++){
  119. *outp++ = *bp++;
  120. *outp++ = *gp++;
  121. *outp++ = *rp++;
  122. }
  123. break;
  124. case CYCbCr:
  125. if(i->nchans != 3)
  126. return _remaperror("remap: can't handle nchans %d", i->nchans);
  127. rp = i->chans[0];
  128. gp = i->chans[1];
  129. bp = i->chans[2];
  130. for(j=0; j<i->chanlen; j++){
  131. Y = *rp++ << 11;
  132. Cb = *gp++ - 128;
  133. Cr = *bp++ - 128;
  134. r = (Y+c1*Cr) >> 11;
  135. g = (Y-c2*Cb-c3*Cr) >> 11;
  136. b = (Y+c4*Cb) >> 11;
  137. if(r < 0)
  138. r = 0;
  139. if(r > 255)
  140. r = 255;
  141. if(g < 0)
  142. g = 0;
  143. if(g > 255)
  144. g = 255;
  145. if(b < 0)
  146. b = 0;
  147. if(b > 255)
  148. b = 255;
  149. if(chandesc == CY){
  150. r = (2125*r + 7154*g + 721*b)/10000;
  151. *outp++ = r;
  152. }else{
  153. *outp++ = b;
  154. *outp++ = g;
  155. *outp++ = r;
  156. }
  157. }
  158. break;
  159. }
  160. return im;
  161. }