summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--draw/blendmodes.c389
-rw-r--r--fitz/res_pixmap.c1
-rw-r--r--mupdf/pdf_interpret.c7
3 files changed, 242 insertions, 155 deletions
diff --git a/draw/blendmodes.c b/draw/blendmodes.c
index 9dde35d1..5a7530ec 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 ed596d7b..f089c11c 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 acf4d2bf..8a901468 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 },