shithub: front

Download patch

ref: 9482f887f984582725e0ffbfa2232d00780e87eb
parent: ce97bb4998c06c964b1f3f9083cb726bd8176c66
author: rodri <rgl@antares-labs.eu>
date: Thu Sep 12 15:09:40 EDT 2024

jpg/tga: decode TGA32 images into RGBA32 ones

--- a/sys/src/cmd/jpg/imagefile.h
+++ b/sys/src/cmd/jpg/imagefile.h
@@ -29,6 +29,7 @@
 	CRGBA32	= 6,	/* one channel in correct data order for loadimage(RGBA32) */
 	CYA16	= 7,	/* one channel in correct data order for loadimage(Grey8+Alpha8) */
 	CRGBVA16= 8,	/* one channel in correct data order for loadimage(CMAP8+Alpha8) */
+	CRGBA	= 9,	/* four channels, no map */
 
 	/* GIF flags */
 	TRANSP	= 1,
--- a/sys/src/cmd/jpg/readtga.c
+++ b/sys/src/cmd/jpg/readtga.c
@@ -238,7 +238,7 @@
 }
 
 static int
-rgba(Biobuf *bp, int bpp, uchar *r, uchar *g, uchar *b, int num)
+rgba(Biobuf *bp, int bpp, uchar *r, uchar *g, uchar *b, uchar *a, int num)
 {
 	int i;
 	uchar buf[4], tmp;
@@ -275,6 +275,7 @@
 			*b++ = buf[0];
 			*g++ = buf[1];
 			*r++ = buf[2];
+			*a++ = buf[3];
 		}
 		break;
 	default:
@@ -285,7 +286,7 @@
 }
 
 static int
-rgba_rle(Biobuf *bp, int bpp, uchar *r, uchar *g, uchar *b, int num)
+rgba_rle(Biobuf *bp, int bpp, uchar *r, uchar *g, uchar *b, uchar *a, int num)
 {
 	uchar len;
 	int i, got;
@@ -296,23 +297,27 @@
 		if(len & 0x80){
 			len &= 0x7f;
 			len += 1;	/* run of zero is meaningless */
-			if(rgba(bp, bpp, r, g, b, 1) != 1)
+			if(rgba(bp, bpp, r, g, b, a, 1) != 1)
 				break;
 			for(i = 1; i < len && got+i < num; i++){
 				r[i] = *r;
 				g[i] = *g;
 				b[i] = *b;
+				if(bpp == 32)
+					a[i] = *a;
 			}
 			len = i;
 		}
 		else{
 			len += 1;	/* raw block of zero is meaningless */
-			if(rgba(bp, bpp, r, g, b, len) != len)
+			if(rgba(bp, bpp, r, g, b, a, len) != len)
 				break;
 		}
 		r += len;
 		g += len;
 		b += len;
+		if(bpp == 32)
+			a += len;
 	}
 	return got;
 }
@@ -380,7 +385,7 @@
 {
 	Tga *h;
 	int n, c, num;
-	uchar *r, *g, *b;
+	uchar *r, *g, *b, *a;
 	Rawimage *ar, **array;
 
 	if((h = rdhdr(bp)) == nil){
@@ -429,8 +434,8 @@
 		ar->chandesc = (h->cmapbpp == 32) ? CRGBV : CRGB1;
 	}
 	else{
-		ar->nchans = 3;
-		ar->chandesc = CRGB;
+		ar->nchans = (h->bpp == 32) ? 4: 3;
+		ar->chandesc = (h->bpp == 32) ? CRGBA: CRGB;
 	}
 
 	ar->cmap = h->cmap;
@@ -445,6 +450,7 @@
 	r = ar->chans[0];
 	g = ar->chans[1];
 	b = ar->chans[2];
+	a = ar->chans[3];
 
 	num = h->width*h->height;
 	switch(h->datatype){
@@ -452,7 +458,7 @@
 		n = cmap(bp, r, num);
 		break;
 	case 2:
-		n = rgba(bp, h->bpp, r, g, b, num);
+		n = rgba(bp, h->bpp, r, g, b, a, num);
 		break;
 	case 3:
 		n = luma(bp, h->bpp, r, num);
@@ -461,7 +467,7 @@
 		n = cmap_rle(bp, r, num);
 		break;
 	case 10:
-		n = rgba_rle(bp, h->bpp, r, g, b, num);
+		n = rgba_rle(bp, h->bpp, r, g, b, a, num);
 		break;
 	case 11:
 		n = luma_rle(bp, h->bpp, r, num);
--- a/sys/src/cmd/jpg/tga.c
+++ b/sys/src/cmd/jpg/tga.c
@@ -166,6 +166,9 @@
 		if(outchan==GREY8 || (r->chandesc==CY && threeflag==0)){
 			c = totruecolor(r, CY);
 			outchan = GREY8;
+		}else if(r->chandesc==CRGBA){
+			c = totruecolor(r, CRGBA32);
+			outchan = RGBA32;
 		}else
 			c = totruecolor(r, CRGB24);
 	}
--- a/sys/src/cmd/jpg/totruecolor.c
+++ b/sys/src/cmd/jpg/totruecolor.c
@@ -17,10 +17,11 @@
 	int j, k;
 	Rawimage *im;
 	char err[ERRMAX];
-	uchar *rp, *gp, *bp, *cmap, *inp, *outp, cmap1[4*256];
+	uchar *rp, *gp, *bp, *ap, *cmap, *inp, *outp, cmap1[4*256];
 	int r, g, b, Y, Cr, Cb, psize;
+	double a;
 
-	if(chandesc!=CY && chandesc!=CRGB24)
+	if(chandesc!=CY && chandesc!=CRGB24 && chandesc!=CRGBA32)
 		return _remaperror("remap: can't convert to chandesc %d", chandesc);
 
 	err[0] = '\0';
@@ -31,8 +32,10 @@
 	memset(im, 0, sizeof(Rawimage));
 	if(chandesc == CY)
 		im->chanlen = i->chanlen;
-	else
+	else if(chandesc == CRGB24)
 		im->chanlen = 3*i->chanlen;
+	else
+		im->chanlen = 4*i->chanlen;
 	im->chandesc = chandesc;
 	im->chans[0] = malloc(im->chanlen);
 	if(im->chans[0] == nil){
@@ -101,11 +104,13 @@
 		break;
 
 	case CRGB:
-		if(i->nchans != 3)
+	case CRGBA:
+		if(i->nchans != 3 && i->nchans != 4)
 			return _remaperror("remap: can't handle nchans %d", i->nchans);
 		rp = i->chans[0];
 		gp = i->chans[1];
 		bp = i->chans[2];
+		ap = i->chans[3];
 		if(chandesc == CY){
 			for(j=0; j<i->chanlen; j++){
 				r = *bp++;
@@ -116,6 +121,15 @@
 			}
 		}else
 			for(j=0; j<i->chanlen; j++){
+				if(i->nchans == 4){
+					*outp++ = *ap++;
+					/* pre-multiply alpha */
+					a = (double)ap[-1]/0xFF;
+					*outp++ = *bp++ * a;
+					*outp++ = *gp++ * a;
+					*outp++ = *rp++ * a;
+					continue;
+				}
 				*outp++ = *bp++;
 				*outp++ = *gp++;
 				*outp++ = *rp++;
--