[gs-commits] mupdf/master - 0_6-173-gfa4d27e - Implement correct blend mode functions and blending.

Tor Andersson tor at ghostscript.com
Fri Jul 16 10:26:25 UTC 2010


commit fa4d27eb5882e54986527a266b016d0995edb66e
Author: Tor Andersson <tor at ghostscript.com>
Date:   Thu Jul 15 18:53:36 2010 +0000

    Implement correct blend mode functions and blending.
    
    Ignore-this: 12ba68e48afeb49bacfa93975eb1d70f
    
    darcs-hash:20100715185336-f546f-bc0672b5cfecc3feaf2ef71846dc247c39d01db2.gz

 3 files changed, 242 insertions(+), 155 deletions(-)

diff --git a/draw/blendmodes.c b/draw/blendmodes.c
index 9dde35d..5a7530e 100644
--- a/draw/blendmodes.c
+++ b/draw/blendmodes.c
@@ -3,243 +3,321 @@
 typedef unsigned char byte;
 
 /*
-PDF 1.4 blend modes, except Normal and Multiply which are Over and In respectively.
-Only the actual blend routines are here, not the node rendering logic which lives in render.c.
+PDF 1.4 blend modes.
+Only the actual blend routines are here, not the rendering logic.
 These are slow.
 */
 
-/* These functions apply to a single component, 0-255 range typically */
+/* These functions apply to a single component, 0-255 range */
 
 static inline int
-fz_screen_byte(int bd, int s)
+fz_screen_byte(int b, int s)
 {
-	return bd + s - fz_mul255(bd, s);
+	return b + s - fz_mul255(b, s);
 }
 
 static inline int
-fz_hardlight_byte(int bd, int s)
+fz_hardlight_byte(int b, int s)
 {
 	int s2 = s << 1;
 	if (s <= 127)
-		return fz_mul255(bd, s2);
+		return fz_mul255(b, s2);
 	else
-		return fz_screen_byte(bd, s2 - 1);
+		return fz_screen_byte(b, s2 - 255);
 }
 
 static inline int
-fz_overlay_byte(int bd, int s)
+fz_overlay_byte(int b, int s)
 {
-	return fz_hardlight_byte(s, bd); // note swapped order
+	return fz_hardlight_byte(s, b); /* note swapped order */
 }
 
 static inline int
-fz_darken_byte(int bd, int s)
+fz_darken_byte(int b, int s)
 {
-	return MIN(bd, s);
+	return MIN(b, s);
 }
 
 static inline int
-fz_lighten_byte(int bd, int s)
+fz_lighten_byte(int b, int s)
 {
-	return MAX(bd, s);
+	return MAX(b, s);
 }
 
 static inline int
-fz_colordodge_byte(int bd, int s)
+fz_colordodge_byte(int b, int s)
 {
-	if (s < 255)
-		return MIN(255, 255 * bd / (255 - s));
-	else
+	s = 255 - s;
+	if (b == 0)
+		return 0;
+	else if (b >= s)
 		return 255;
+	else
+		return (0x1fe * b + s) / (s << 1);
 }
 
 static inline int
-fz_colorburn_byte(int bd, int s)
+fz_colorburn_byte(int b, int s)
 {
-	if (s > 0)
-		return 255 - MIN(255, 255 * (255 - bd) / s);
-	else
+	b = 255 - b;
+	if (b == 0)
+		return 255;
+	else if (b >= s)
 		return 0;
+	else
+		return 0xff - (0x1fe * b + s) / (s << 1);
 }
 
 static inline int
-fz_softlight_byte(int bd, int s)
+fz_softlight_byte(int b, int s)
 {
 	/* review this */
 	if (s < 128) {
-		return bd - fz_mul255(fz_mul255((255 - (s<<1)), bd), 255 - bd);
+		return b - fz_mul255(fz_mul255((255 - (s<<1)), b), 255 - b);
 	}
 	else {
 		int dbd;
-		if (bd < 64)
-			dbd = fz_mul255(fz_mul255((bd << 4) - 12, bd) + 4, bd);
+		if (b < 64)
+			dbd = fz_mul255(fz_mul255((b << 4) - 12, b) + 4, b);
 		else
-			dbd = (int)sqrtf(255.0f * bd);
-		return bd + fz_mul255(((s<<1) - 255), (dbd - bd));
+			dbd = (int)sqrtf(255.0f * b);
+		return b + fz_mul255(((s<<1) - 255), (dbd - b));
 	}
 }
 
 static inline int
-fz_difference_byte(int bd, int s)
+fz_difference_byte(int b, int s)
 {
-	return ABS(bd - s);
+	return ABS(b - s);
 }
 
 static inline int
-fz_exclusion_byte(int bd, int s)
+fz_exclusion_byte(int b, int s)
 {
-	return bd + s - (fz_mul255(bd, s)<<1);
+	return b + s - (fz_mul255(b, s)<<1);
 }
 
 /* Non-separable blend modes */
 
-static inline int
-lum(int r, int g, int b)
+static inline void
+fz_luminosity_rgb(int *rd, int *gd, int *bd, int rb, int gb, int bb, int rs, int gs, int bs)
 {
-	/* 0.3, 0.59, 0.11 in 16.16 fixed point */
-	return (19662 * r + 38666 * g + 7208 * b) >> 16;
-}
+	int delta, scale;
+	int r, g, b, y;
 
-static void
-clipcolor(int r, int g, int b, int *dr, int *dg, int *db)
-{
-	int l = lum(r, g, b);
-	int n = MIN(MIN(r, g), b);
-	int x = MAX(MAX(r, g), b);
-	if (n < 0) {
-		*dr = l + 255 * (r - l) / (l - n);
-		*dg = l + 255 * (g - l) / (l - n);
-		*db = l + 255 * (b - l) / (l - n);
-	}
-	else {
-		*dr = l + 255 * (255 - l) / (x - l);
-		*dg = l + 255 * (255 - l) / (x - l);
-		*db = l + 255 * (255 - l) / (x - l);
-	}
-}
+	/* 0.3, 0.59, 0.11 in fixed point */
+	delta = ((rs - rb) * 77 + (gs - gb) * 151 + (bs - bb) * 28 + 0x80) >> 8;
+	r = rb + delta;
+	g = gb + delta;
+	b = bb + delta;
 
-static void
-setlum(int r, int g, int b, int l, int *dr, int *dg, int *db)
-{
-	int d = 255 - lum(r, g, b);
-	clipcolor(r + d, g + d, b + d, dr, dg, db);
-}
+	if ((r | g | b) & 0x100)
+	{
+		y = (rs * 77 + gs * 151 + bs * 28 + 0x80) >> 8;
+		if (delta > 0) {
+			int max;
+			max = r > g ? r : g;
+			max = b > max ? b : max;
+			scale = ((255 - y) << 16) / (max - y);
+		} else {
+			int min;
+			min = r < g ? r : g;
+			min = b < min ? b : min;
+			scale = (y << 16) / (y - min);
+		}
+		r = y + (((r - y) * scale + 0x8000) >> 16);
+		g = y + (((g - y) * scale + 0x8000) >> 16);
+		b = y + (((b - y) * scale + 0x8000) >> 16);
+	}
 
-static inline int
-sat(int r, int g, int b)
-{
-	return MAX(MAX(r, g), b) - MIN(MIN(r, g), b);
+	*rd = r;
+	*gd = g;
+	*bd = b;
 }
 
 static void
-setsat(int r, int g, int b, int s, int *dr, int *dg, int *db)
+fz_saturation_rgb(int *rd, int *gd, int *bd, int rb, int gb, int bb, int rs, int gs, int bs)
 {
-	int *m[3]; /* min, med, max */
-	int *t;
-	m[0] = &r;
-	m[1] = &g;
-	m[2] = &b;
-#define SWAP(a, b) (t = a, a = b, b = t)
-	if (*m[0] > *m[1])
-		SWAP(m[0], m[1]);
-	if (*m[0] > *m[2])
-		SWAP(m[0], m[2]);
-	if (*m[1] > *m[2])
-		SWAP(m[1], m[2]);
-
-	if (*m[2] > *m[0]) {
-		*m[1] = (*m[1] - *m[0]) * s / (*m[2] - *m[0]);
-		*m[2] = s;
-	}
-	else {
-		*m[1] = 0;
-		*m[2] = 0;
+	int minb, maxb;
+	int mins, maxs;
+	int y;
+	int scale;
+	int r, g, b;
+
+	minb = rb < gb ? rb : gb;
+	minb = minb < bb ? minb : bb;
+	maxb = rb > gb ? rb : gb;
+	maxb = maxb > bb ? maxb : bb;
+	if (minb == maxb) {
+		/* backdrop has zero saturation, avoid divide by 0 */
+		*rd = gb;
+		*gd = gb;
+		*bd = gb;
+		return;
 	}
-	*dr = r;
-	*dg = g;
-	*db = b;
-}
 
-static void
-fz_hue_rgb(int *bdr, int *bdg, int *bdb, int sr, int sg, int sb)
-{
-	int tr, tg, tb;
-	setsat(sr, sg, sb, sat(*bdr, *bdg, *bdb), &tr, &tg, &tb);
-	setlum(tr, tg, tb, lum(*bdr, *bdg, *bdb), bdr, bdg, bdb);
-}
+	mins = rs < gs ? rs : gs;
+	mins = mins < bs ? mins : bs;
+	maxs = rs > gs ? rs : gs;
+	maxs = maxs > bs ? maxs : bs;
 
-static void
-fz_saturation_rgb(int *bdr, int *bdg, int *bdb, int sr, int sg, int sb)
-{
-	int tr, tg, tb;
-	setsat(*bdr, *bdg, *bdb, sat(sr, sg, sb), &tr, &tg, &tb);
-	setlum(tr, tg, tb, lum(*bdr, *bdg, *bdb), bdr, bdg, bdb);
+	scale = ((maxs - mins) << 16) / (maxb - minb);
+	y = (rb * 77 + gb * 151 + bb * 28 + 0x80) >> 8;
+	r = y + ((((rb - y) * scale) + 0x8000) >> 16);
+	g = y + ((((gb - y) * scale) + 0x8000) >> 16);
+	b = y + ((((bb - y) * scale) + 0x8000) >> 16);
+
+	if ((r | g | b) & 0x100) {
+		int scalemin, scalemax;
+		int min, max;
+
+		min = r < g ? r : g;
+		min = min < b ? min : b;
+		max = r > g ? r : g;
+		max = max > b ? max : b;
+
+		if (min < 0)
+			scalemin = (y << 16) / (y - min);
+		else
+			scalemin = 0x10000;
+
+		if (max > 255)
+			scalemax = ((255 - y) << 16) / (max - y);
+		else
+			scalemax = 0x10000;
+
+		scale = scalemin < scalemax ? scalemin : scalemax;
+		r = y + (((r - y) * scale + 0x8000) >> 16);
+		g = y + (((g - y) * scale + 0x8000) >> 16);
+		b = y + (((b - y) * scale + 0x8000) >> 16);
+	}
+
+	*rd = r;
+	*gd = g;
+	*bd = b;
 }
 
 static void
-fz_color_rgb(int *bdr, int *bdg, int *bdb, int sr, int sg, int sb)
+fz_color_rgb(int *rr, int *rg, int *rb, int br, int bg, int bb, int sr, int sg, int sb)
 {
-	setlum(sr, sg, sb, lum(*bdr, *bdg, *bdb), bdr, bdg, bdb);
+	fz_luminosity_rgb(rr, rg, rb, sr, sg, sb, br, bg, bb);
 }
 
 static void
-fz_luminosity_rgb(int *bdr, int *bdg, int *bdb, int sr, int sg, int sb)
+fz_hue_rgb(int *rr, int *rg, int *rb, int br, int bg, int bb, int sr, int sg, int sb)
 {
-	setlum(*bdr, *bdg, *bdb, lum(sr, sg, sb), bdr, bdg, bdb);
+	int tr, tg, tb;
+	fz_luminosity_rgb(&tr, &tg, &tb, sr, sg, sb, br, bg, bb);
+	fz_saturation_rgb(rr, rg, rb, tr, tg, tb, br, bg, bb);
 }
 
 /*
  *
  */
 
-void
-fz_blend_nxn(byte * restrict sp, int sw, int sn,
-	byte * restrict dp, int dw,
-	int w0, int h, fz_blendmode blendmode)
+static void
+fz_blendseparable(byte * restrict sp, byte * restrict bp, int n, int w, fz_blendmode blendmode)
 {
 	int k;
-
-	sw -= w0*sn;
-	dw -= w0*sn;
-	while (h--)
+	int n1 = n - 1;
+	while (w--)
 	{
-		int w = w0;
-		while (w--)
+		int sa = sp[n1];
+		int ba = bp[n1];
+		int saba = fz_mul255(sa, ba);
+
+		for (k = 0; k < n1; k++)
 		{
-			int sa = sp[sn-1];
-			int da = dp[sn-1];
-			int ta = 255 - sa;
-			int tb = 255 - da;
-			int tc = fz_mul255(sa, da);
-			for (k = 0; k < sn; k++)
+			int sc = sp[k];
+			int bc = bp[k];
+			int rc;
+
+			/* ugh, division to get non-premul components */
+			if (sa) sc = sc * 255 / sa;
+			if (ba) bc = bc * 255 / ba;
+
+			switch (blendmode)
 			{
-				int r, bd, s;
-				if (da)
-					bd = dp[k] * 255 / da;
-				if (sa)
-					s = sp[k] * 255 / sa;
-				switch (blendmode)
-				{
-				default:
-				case FZ_BMULTIPLY: r = fz_mul255(bd, s); break;
-				case FZ_BSCREEN: r = fz_screen_byte(bd, s); break;
-				case FZ_BOVERLAY: r = fz_overlay_byte(bd, s); break;
-				case FZ_BDARKEN: r = fz_darken_byte(bd, s); break;
-				case FZ_BLIGHTEN: r = fz_lighten_byte(bd, s); break;
-				case FZ_BCOLORDODGE: r = fz_colordodge_byte(bd, s); break;
-				case FZ_BCOLORBURN: r = fz_colorburn_byte(bd, s); break;
-				case FZ_BHARDLIGHT: r = fz_hardlight_byte(bd, s); break;
-				case FZ_BSOFTLIGHT: r = fz_softlight_byte(bd, s); break;
-				case FZ_BDIFFERENCE: r = fz_difference_byte(bd, s); break;
-				case FZ_BEXCLUSION: r = fz_exclusion_byte(bd, s); break;
-				}
-				dp[k] = fz_mul255(ta, dp[k]) + fz_mul255(tb, sp[k]) + fz_mul255(tc, r);
+			default:
+			case FZ_BNORMAL: rc = sc; break;
+			case FZ_BMULTIPLY: rc = fz_mul255(bc, sc); break;
+			case FZ_BSCREEN: rc = fz_screen_byte(bc, sc); break;
+			case FZ_BOVERLAY: rc = fz_overlay_byte(bc, sc); break;
+			case FZ_BDARKEN: rc = fz_darken_byte(bc, sc); break;
+			case FZ_BLIGHTEN: rc = fz_lighten_byte(bc, sc); break;
+			case FZ_BCOLORDODGE: rc = fz_colordodge_byte(bc, sc); break;
+			case FZ_BCOLORBURN: rc = fz_colorburn_byte(bc, sc); break;
+			case FZ_BHARDLIGHT: rc = fz_hardlight_byte(bc, sc); break;
+			case FZ_BSOFTLIGHT: rc = fz_softlight_byte(bc, sc); break;
+			case FZ_BDIFFERENCE: rc = fz_difference_byte(bc, sc); break;
+			case FZ_BEXCLUSION: rc = fz_exclusion_byte(bc, sc); break;
 			}
-			sp += sn;
-			dp += sn;
+
+			bp[k] = fz_mul255(255 - sa, bp[k]) + fz_mul255(255 - ba, sp[k]) + fz_mul255(saba, rc);
+		}
+
+		bp[k] = ba + sa - saba;
+
+		sp += n;
+		bp += n;
+	}
+}
+
+static void
+fz_blendnonseparable(byte * restrict sp, byte * restrict bp, int w, fz_blendmode blendmode)
+{
+	while (w--)
+	{
+		int rr, rg, rb, saba;
+
+		int sr = sp[0];
+		int sg = sp[1];
+		int sb = sp[2];
+		int sa = sp[3];
+
+		int br = bp[0];
+		int bg = bp[1];
+		int bb = bp[2];
+		int ba = bp[3];
+
+		saba = fz_mul255(sa, ba);
+
+		/* ugh, bivision to get non-premul components */
+		if (sa) {
+			sr = sr * 255 / sa;
+			sg = sg * 255 / sa;
+			sb = sb * 255 / sa;
+		}
+		if (ba) {
+			br = br * 255 / ba;
+			bg = bg * 255 / ba;
+			bb = bb * 255 / ba;
 		}
-		sp += sw;
-		dp += dw;
+
+		switch (blendmode)
+		{
+		default:
+		case FZ_BHUE:
+			fz_hue_rgb(&rr, &rg, &rb, br, bg, bb, sr, sg, sb);
+			break;
+		case FZ_BSATURATION:
+			fz_saturation_rgb(&rr, &rg, &rb, br, bg, bb, sr, sg, sb);
+			break;
+		case FZ_BCOLOR:
+			fz_color_rgb(&rr, &rg, &rb, br, bg, bb, sr, sg, sb);
+			break;
+		case FZ_BLUMINOSITY:
+			fz_luminosity_rgb(&rr, &rg, &rb, br, bg, bb, sr, sg, sb);
+			break;
+		}
+
+		bp[0] = fz_mul255(255 - sa, bp[0]) + fz_mul255(255 - ba, sp[0]) + fz_mul255(saba, rr);
+		bp[1] = fz_mul255(255 - sa, bp[1]) + fz_mul255(255 - ba, sp[1]) + fz_mul255(saba, rg);
+		bp[2] = fz_mul255(255 - sa, bp[2]) + fz_mul255(255 - ba, sp[2]) + fz_mul255(saba, rb);
+		bp[3] = ba + sa - saba;
+
+		sp += 4;
+		bp += 4;
 	}
 }
 
@@ -248,7 +326,7 @@ fz_blendpixmaps(fz_pixmap *src, fz_pixmap *dst, fz_blendmode blendmode)
 {
 	unsigned char *sp, *dp;
 	fz_bbox sr, dr;
-	int x, y, w, h;
+	int x, y, w, h, n;
 
 	assert(src->n == dst->n);
 
@@ -268,8 +346,17 @@ fz_blendpixmaps(fz_pixmap *src, fz_pixmap *dst, fz_blendmode blendmode)
 	w = dr.x1 - dr.x0;
 	h = dr.y1 - dr.y0;
 
-	sp = src->samples + ((y - src->y) * src->w + (x - src->x)) * src->n;
-	dp = dst->samples + ((y - dst->y) * dst->w + (x - dst->x)) * dst->n;
+	n = src->n;
+	sp = src->samples + ((y - src->y) * src->w + (x - src->x)) * n;
+	dp = dst->samples + ((y - dst->y) * dst->w + (x - dst->x)) * n;
 
-	fz_blend_nxn(sp, src->w * src->n, src->n, dp, dst->w * dst->n, w, h, blendmode);
+	while (h--)
+	{
+		if (n == 4 && blendmode >= FZ_BHUE)
+			fz_blendnonseparable(sp, dp, w, blendmode);
+		else
+			fz_blendseparable(sp, dp, n, w, blendmode);
+		sp += src->w * n;
+		dp += dst->w * n;
+	}
 }
diff --git a/fitz/res_pixmap.c b/fitz/res_pixmap.c
index ed596d7..f089c11 100644
--- a/fitz/res_pixmap.c
+++ b/fitz/res_pixmap.c
@@ -255,7 +255,6 @@ fz_writepng(fz_pixmap *pixmap, char *filename, int alpha)
 		return fz_throw("cannot compress image data");
 	}
 
-
 	fp = fopen(filename, "wb");
 	if (!fp)
 	{
diff --git a/mupdf/pdf_interpret.c b/mupdf/pdf_interpret.c
index acf4d2b..8a90146 100644
--- a/mupdf/pdf_interpret.c
+++ b/mupdf/pdf_interpret.c
@@ -316,11 +316,12 @@ pdf_runextgstate(pdf_gstate *gstate, pdf_xref *xref, fz_obj *rdb, fz_obj *extgst
 				{ "Multiply", FZ_BMULTIPLY },
 				{ "Screen", FZ_BSCREEN },
 				{ "Overlay", FZ_BOVERLAY },
+				{ "SoftLight", FZ_BSOFTLIGHT },
+				{ "HardLight", FZ_BHARDLIGHT },
+				{ "ColorDodge", FZ_BCOLORDODGE },
+				{ "ColorBurn", FZ_BCOLORBURN },
 				{ "Darken", FZ_BDARKEN },
 				{ "Lighten", FZ_BLIGHTEN },
-				{ "Colordodge", FZ_BCOLORDODGE },
-				{ "Hardlight", FZ_BHARDLIGHT },
-				{ "Softlight", FZ_BSOFTLIGHT },
 				{ "Difference", FZ_BDIFFERENCE },
 				{ "Exclusion", FZ_BEXCLUSION },
 				{ "Hue", FZ_BHUE },

--
git/hooks/post-receive


More information about the gs-commits mailing list