xref: /plan9-contrib/sys/src/cmd/jpg/totruecolor.c (revision 9a747e4fd48b9f4522c70c07e8f882a15030f964)
17dd7cddfSDavid du Colombier #include <u.h>
27dd7cddfSDavid du Colombier #include <libc.h>
37dd7cddfSDavid du Colombier #include <bio.h>
47dd7cddfSDavid du Colombier #include <draw.h>
57dd7cddfSDavid du Colombier #include "imagefile.h"
67dd7cddfSDavid du Colombier 
77dd7cddfSDavid du Colombier enum {
87dd7cddfSDavid du Colombier 	c1 = 2871,	/* 1.402 * 2048 */
97dd7cddfSDavid du Colombier 	c2 = 705,		/* 0.34414 * 2048 */
107dd7cddfSDavid du Colombier 	c3 = 1463,	/* 0.71414 * 2048 */
117dd7cddfSDavid du Colombier 	c4 = 3629,	/* 1.772 * 2048 */
127dd7cddfSDavid du Colombier };
137dd7cddfSDavid du Colombier 
147dd7cddfSDavid du Colombier Rawimage*
totruecolor(Rawimage * i,int chandesc)157dd7cddfSDavid du Colombier totruecolor(Rawimage *i, int chandesc)
167dd7cddfSDavid du Colombier {
177dd7cddfSDavid du Colombier 	int j, k;
187dd7cddfSDavid du Colombier 	Rawimage *im;
19*9a747e4fSDavid du Colombier 	char err[ERRMAX];
207dd7cddfSDavid du Colombier 	uchar *rp, *gp, *bp, *cmap, *inp, *outp, cmap1[3*256];
217dd7cddfSDavid du Colombier 	int r, g, b, Y, Cr, Cb;
227dd7cddfSDavid du Colombier 
237dd7cddfSDavid du Colombier 	if(chandesc!=CY && chandesc!=CRGB24)
247dd7cddfSDavid du Colombier 		return _remaperror("remap: can't convert to chandesc %d", chandesc);
257dd7cddfSDavid du Colombier 
267dd7cddfSDavid du Colombier 	err[0] = '\0';
27*9a747e4fSDavid du Colombier 	errstr(err, sizeof err);	/* throw it away */
287dd7cddfSDavid du Colombier 	im = malloc(sizeof(Rawimage));
297dd7cddfSDavid du Colombier 	if(im == nil)
307dd7cddfSDavid du Colombier 		return nil;
317dd7cddfSDavid du Colombier 	memset(im, 0, sizeof(Rawimage));
327dd7cddfSDavid du Colombier 	if(chandesc == CY)
337dd7cddfSDavid du Colombier 		im->chanlen = i->chanlen;
347dd7cddfSDavid du Colombier 	else
357dd7cddfSDavid du Colombier 		im->chanlen = 3*i->chanlen;
367dd7cddfSDavid du Colombier 	im->chandesc = chandesc;
377dd7cddfSDavid du Colombier 	im->chans[0] = malloc(im->chanlen);
387dd7cddfSDavid du Colombier 	if(im->chans[0] == nil){
397dd7cddfSDavid du Colombier 		free(im);
407dd7cddfSDavid du Colombier 		return nil;
417dd7cddfSDavid du Colombier 	}
427dd7cddfSDavid du Colombier 	im->r = i->r;
437dd7cddfSDavid du Colombier 	im->nchans = 1;
447dd7cddfSDavid du Colombier 
457dd7cddfSDavid du Colombier 	cmap = i->cmap;
467dd7cddfSDavid du Colombier 
477dd7cddfSDavid du Colombier 	outp = im->chans[0];
487dd7cddfSDavid du Colombier 
497dd7cddfSDavid du Colombier 	switch(i->chandesc){
507dd7cddfSDavid du Colombier 	default:
517dd7cddfSDavid du Colombier 		return _remaperror("remap: can't recognize channel type %d", i->chandesc);
527dd7cddfSDavid du Colombier 	case CY:
537dd7cddfSDavid du Colombier 		if(i->nchans != 1)
547dd7cddfSDavid du Colombier 			return _remaperror("remap: Y image has %d chans", i->nchans);
557dd7cddfSDavid du Colombier 		if(chandesc == CY){
567dd7cddfSDavid du Colombier 			memmove(im->chans[0], i->chans[0], i->chanlen);
577dd7cddfSDavid du Colombier 			break;
587dd7cddfSDavid du Colombier 		}
597dd7cddfSDavid du Colombier 		/* convert to three color */
607dd7cddfSDavid du Colombier 		inp = i->chans[0];
617dd7cddfSDavid du Colombier 		for(j=0; j<i->chanlen; j++){
627dd7cddfSDavid du Colombier 			k = *inp++;
637dd7cddfSDavid du Colombier 			*outp++ = k;
647dd7cddfSDavid du Colombier 			*outp++ = k;
657dd7cddfSDavid du Colombier 			*outp++ = k;
667dd7cddfSDavid du Colombier 		}
677dd7cddfSDavid du Colombier 		break;
687dd7cddfSDavid du Colombier 
697dd7cddfSDavid du Colombier 	case CRGB1:
707dd7cddfSDavid du Colombier 		if(cmap == nil)
717dd7cddfSDavid du Colombier 			return _remaperror("remap: image has no color map");
727dd7cddfSDavid du Colombier 		if(i->nchans != 1)
737dd7cddfSDavid du Colombier 			return _remaperror("remap: can't handle nchans %d", i->nchans);
747dd7cddfSDavid du Colombier 		for(j=1; j<=8; j++)
757dd7cddfSDavid du Colombier 			if(i->cmaplen == 3*(1<<j))
767dd7cddfSDavid du Colombier 				break;
777dd7cddfSDavid du Colombier 		if(j > 8)
787dd7cddfSDavid du Colombier 			return _remaperror("remap: can't do colormap size 3*%d", i->cmaplen/3);
797dd7cddfSDavid du Colombier 		if(i->cmaplen != 3*256){
807dd7cddfSDavid du Colombier 			/* to avoid a range check in loop below, make a full-size cmap */
817dd7cddfSDavid du Colombier 			memmove(cmap1, cmap, i->cmaplen);
827dd7cddfSDavid du Colombier 			cmap = cmap1;
837dd7cddfSDavid du Colombier 		}
847dd7cddfSDavid du Colombier 		inp = i->chans[0];
857dd7cddfSDavid du Colombier 		if(chandesc == CY){
867dd7cddfSDavid du Colombier 			for(j=0; j<i->chanlen; j++){
877dd7cddfSDavid du Colombier 				k = *inp++;
887dd7cddfSDavid du Colombier 				r = cmap[3*k+2];
897dd7cddfSDavid du Colombier 				g = cmap[3*k+1];
907dd7cddfSDavid du Colombier 				b = cmap[3*k+0];
917dd7cddfSDavid du Colombier 				r = (2125*r + 7154*g + 721*b)/10000;	/* Poynton page 84 */
927dd7cddfSDavid du Colombier 				*outp++ = r;
937dd7cddfSDavid du Colombier 			}
947dd7cddfSDavid du Colombier 		}else{
957dd7cddfSDavid du Colombier 			for(j=0; j<i->chanlen; j++){
967dd7cddfSDavid du Colombier 				k = *inp++;
977dd7cddfSDavid du Colombier 				*outp++ = cmap[3*k+2];
987dd7cddfSDavid du Colombier 				*outp++ = cmap[3*k+1];
997dd7cddfSDavid du Colombier 				*outp++ = cmap[3*k+0];
1007dd7cddfSDavid du Colombier 			}
1017dd7cddfSDavid du Colombier 		}
1027dd7cddfSDavid du Colombier 		break;
1037dd7cddfSDavid du Colombier 
1047dd7cddfSDavid du Colombier 	case CRGB:
1057dd7cddfSDavid du Colombier 		if(i->nchans != 3)
1067dd7cddfSDavid du Colombier 			return _remaperror("remap: can't handle nchans %d", i->nchans);
1077dd7cddfSDavid du Colombier 		rp = i->chans[0];
1087dd7cddfSDavid du Colombier 		gp = i->chans[1];
1097dd7cddfSDavid du Colombier 		bp = i->chans[2];
1107dd7cddfSDavid du Colombier 		if(chandesc == CY){
1117dd7cddfSDavid du Colombier 			for(j=0; j<i->chanlen; j++){
1127dd7cddfSDavid du Colombier 				r = *bp++;
1137dd7cddfSDavid du Colombier 				g = *gp++;
1147dd7cddfSDavid du Colombier 				b = *rp++;
1157dd7cddfSDavid du Colombier 				r = (2125*r + 7154*g + 721*b)/10000;	/* Poynton page 84 */
1167dd7cddfSDavid du Colombier 				*outp++ = r;
1177dd7cddfSDavid du Colombier 			}
1187dd7cddfSDavid du Colombier 		}else
1197dd7cddfSDavid du Colombier 			for(j=0; j<i->chanlen; j++){
1207dd7cddfSDavid du Colombier 				*outp++ = *bp++;
1217dd7cddfSDavid du Colombier 				*outp++ = *gp++;
1227dd7cddfSDavid du Colombier 				*outp++ = *rp++;
1237dd7cddfSDavid du Colombier 			}
1247dd7cddfSDavid du Colombier 		break;
1257dd7cddfSDavid du Colombier 
1267dd7cddfSDavid du Colombier 	case CYCbCr:
1277dd7cddfSDavid du Colombier 		if(i->nchans != 3)
1287dd7cddfSDavid du Colombier 			return _remaperror("remap: can't handle nchans %d", i->nchans);
1297dd7cddfSDavid du Colombier 		rp = i->chans[0];
1307dd7cddfSDavid du Colombier 		gp = i->chans[1];
1317dd7cddfSDavid du Colombier 		bp = i->chans[2];
1327dd7cddfSDavid du Colombier 		for(j=0; j<i->chanlen; j++){
1337dd7cddfSDavid du Colombier 			Y = *rp++ << 11;
1347dd7cddfSDavid du Colombier 			Cb = *gp++ - 128;
1357dd7cddfSDavid du Colombier 			Cr = *bp++ - 128;
1367dd7cddfSDavid du Colombier 			r = (Y+c1*Cr) >> 11;
1377dd7cddfSDavid du Colombier 			g = (Y-c2*Cb-c3*Cr) >> 11;
1387dd7cddfSDavid du Colombier 			b = (Y+c4*Cb) >> 11;
1397dd7cddfSDavid du Colombier 			if(r < 0)
1407dd7cddfSDavid du Colombier 				r = 0;
1417dd7cddfSDavid du Colombier 			if(r > 255)
1427dd7cddfSDavid du Colombier 				r = 255;
1437dd7cddfSDavid du Colombier 			if(g < 0)
1447dd7cddfSDavid du Colombier 				g = 0;
1457dd7cddfSDavid du Colombier 			if(g > 255)
1467dd7cddfSDavid du Colombier 				g = 255;
1477dd7cddfSDavid du Colombier 			if(b < 0)
1487dd7cddfSDavid du Colombier 				b = 0;
1497dd7cddfSDavid du Colombier 			if(b > 255)
1507dd7cddfSDavid du Colombier 				b = 255;
1517dd7cddfSDavid du Colombier 			if(chandesc == CY){
1527dd7cddfSDavid du Colombier 				r = (2125*r + 7154*g + 721*b)/10000;
1537dd7cddfSDavid du Colombier 				*outp++ = r;
1547dd7cddfSDavid du Colombier 			}else{
1557dd7cddfSDavid du Colombier 				*outp++ = b;
1567dd7cddfSDavid du Colombier 				*outp++ = g;
1577dd7cddfSDavid du Colombier 				*outp++ = r;
1587dd7cddfSDavid du Colombier 			}
1597dd7cddfSDavid du Colombier 		}
1607dd7cddfSDavid du Colombier 		break;
1617dd7cddfSDavid du Colombier 	}
1627dd7cddfSDavid du Colombier 	return im;
1637dd7cddfSDavid du Colombier }
164