Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Download
7640 views
1
#include "mupdf/fitz.h"
2
#include "draw-imp.h"
3
4
/* PDF 1.4 blend modes. These are slow. */
5
6
typedef unsigned char byte;
7
8
static const char *fz_blendmode_names[] =
9
{
10
"Normal",
11
"Multiply",
12
"Screen",
13
"Overlay",
14
"Darken",
15
"Lighten",
16
"ColorDodge",
17
"ColorBurn",
18
"HardLight",
19
"SoftLight",
20
"Difference",
21
"Exclusion",
22
"Hue",
23
"Saturation",
24
"Color",
25
"Luminosity",
26
};
27
28
int fz_lookup_blendmode(const char *name)
29
{
30
int i;
31
for (i = 0; i < nelem(fz_blendmode_names); i++)
32
if (!strcmp(name, fz_blendmode_names[i]))
33
return i;
34
return FZ_BLEND_NORMAL;
35
}
36
37
char *fz_blendmode_name(int blendmode)
38
{
39
if (blendmode >= 0 && blendmode < nelem(fz_blendmode_names))
40
return (char*)fz_blendmode_names[blendmode];
41
return "Normal";
42
}
43
44
/* Separable blend modes */
45
46
static inline int fz_screen_byte(int b, int s)
47
{
48
return b + s - fz_mul255(b, s);
49
}
50
51
static inline int fz_hard_light_byte(int b, int s)
52
{
53
int s2 = s << 1;
54
if (s <= 127)
55
return fz_mul255(b, s2);
56
else
57
return fz_screen_byte(b, s2 - 255);
58
}
59
60
static inline int fz_overlay_byte(int b, int s)
61
{
62
return fz_hard_light_byte(s, b); /* note swapped order */
63
}
64
65
static inline int fz_darken_byte(int b, int s)
66
{
67
return fz_mini(b, s);
68
}
69
70
static inline int fz_lighten_byte(int b, int s)
71
{
72
return fz_maxi(b, s);
73
}
74
75
static inline int fz_color_dodge_byte(int b, int s)
76
{
77
s = 255 - s;
78
if (b <= 0)
79
return 0;
80
else if (b >= s)
81
return 255;
82
else
83
return (0x1fe * b + s) / (s << 1);
84
}
85
86
static inline int fz_color_burn_byte(int b, int s)
87
{
88
b = 255 - b;
89
if (b <= 0)
90
return 255;
91
else if (b >= s)
92
return 0;
93
else
94
return 0xff - (0x1fe * b + s) / (s << 1);
95
}
96
97
static inline int fz_soft_light_byte(int b, int s)
98
{
99
/* review this */
100
if (s < 128) {
101
return b - fz_mul255(fz_mul255((255 - (s<<1)), b), 255 - b);
102
}
103
else {
104
int dbd;
105
if (b < 64)
106
dbd = fz_mul255(fz_mul255((b << 4) - 12, b) + 4, b);
107
else
108
dbd = (int)sqrtf(255.0f * b);
109
return b + fz_mul255(((s<<1) - 255), (dbd - b));
110
}
111
}
112
113
static inline int fz_difference_byte(int b, int s)
114
{
115
return fz_absi(b - s);
116
}
117
118
static inline int fz_exclusion_byte(int b, int s)
119
{
120
return b + s - (fz_mul255(b, s)<<1);
121
}
122
123
/* Non-separable blend modes */
124
125
static void
126
fz_luminosity_rgb(unsigned char *rd, unsigned char *gd, unsigned char *bd, int rb, int gb, int bb, int rs, int gs, int bs)
127
{
128
int delta, scale;
129
int r, g, b, y;
130
131
/* 0.3, 0.59, 0.11 in fixed point */
132
delta = ((rs - rb) * 77 + (gs - gb) * 151 + (bs - bb) * 28 + 0x80) >> 8;
133
r = rb + delta;
134
g = gb + delta;
135
b = bb + delta;
136
137
if ((r | g | b) & 0x100)
138
{
139
y = (rs * 77 + gs * 151 + bs * 28 + 0x80) >> 8;
140
if (delta > 0)
141
{
142
int max;
143
max = fz_maxi(r, fz_maxi(g, b));
144
scale = (max == y ? 0 : ((255 - y) << 16) / (max - y));
145
}
146
else
147
{
148
int min;
149
min = fz_mini(r, fz_mini(g, b));
150
scale = (y == min ? 0 : (y << 16) / (y - min));
151
}
152
r = y + (((r - y) * scale + 0x8000) >> 16);
153
g = y + (((g - y) * scale + 0x8000) >> 16);
154
b = y + (((b - y) * scale + 0x8000) >> 16);
155
}
156
157
*rd = fz_clampi(r, 0, 255);
158
*gd = fz_clampi(g, 0, 255);
159
*bd = fz_clampi(b, 0, 255);
160
}
161
162
static void
163
fz_saturation_rgb(unsigned char *rd, unsigned char *gd, unsigned char *bd, int rb, int gb, int bb, int rs, int gs, int bs)
164
{
165
int minb, maxb;
166
int mins, maxs;
167
int y;
168
int scale;
169
int r, g, b;
170
171
minb = fz_mini(rb, fz_mini(gb, bb));
172
maxb = fz_maxi(rb, fz_maxi(gb, bb));
173
if (minb == maxb)
174
{
175
/* backdrop has zero saturation, avoid divide by 0 */
176
gb = fz_clampi(gb, 0, 255);
177
*rd = gb;
178
*gd = gb;
179
*bd = gb;
180
return;
181
}
182
183
mins = fz_mini(rs, fz_mini(gs, bs));
184
maxs = fz_maxi(rs, fz_maxi(gs, bs));
185
186
scale = ((maxs - mins) << 16) / (maxb - minb);
187
y = (rb * 77 + gb * 151 + bb * 28 + 0x80) >> 8;
188
r = y + ((((rb - y) * scale) + 0x8000) >> 16);
189
g = y + ((((gb - y) * scale) + 0x8000) >> 16);
190
b = y + ((((bb - y) * scale) + 0x8000) >> 16);
191
192
if ((r | g | b) & 0x100)
193
{
194
int scalemin, scalemax;
195
int min, max;
196
197
min = fz_mini(r, fz_mini(g, b));
198
max = fz_maxi(r, fz_maxi(g, b));
199
200
if (min < 0)
201
scalemin = (y << 16) / (y - min);
202
else
203
scalemin = 0x10000;
204
205
if (max > 255)
206
scalemax = ((255 - y) << 16) / (max - y);
207
else
208
scalemax = 0x10000;
209
210
scale = fz_mini(scalemin, scalemax);
211
r = y + (((r - y) * scale + 0x8000) >> 16);
212
g = y + (((g - y) * scale + 0x8000) >> 16);
213
b = y + (((b - y) * scale + 0x8000) >> 16);
214
}
215
216
*rd = fz_clampi(r, 0, 255);
217
*gd = fz_clampi(g, 0, 255);
218
*bd = fz_clampi(b, 0, 255);
219
}
220
221
static void
222
fz_color_rgb(unsigned char *rr, unsigned char *rg, unsigned char *rb, int br, int bg, int bb, int sr, int sg, int sb)
223
{
224
fz_luminosity_rgb(rr, rg, rb, sr, sg, sb, br, bg, bb);
225
}
226
227
static void
228
fz_hue_rgb(unsigned char *rr, unsigned char *rg, unsigned char *rb, int br, int bg, int bb, int sr, int sg, int sb)
229
{
230
unsigned char tr, tg, tb;
231
fz_luminosity_rgb(&tr, &tg, &tb, sr, sg, sb, br, bg, bb);
232
fz_saturation_rgb(rr, rg, rb, tr, tg, tb, br, bg, bb);
233
}
234
235
void
236
fz_blend_pixel(unsigned char dp[3], unsigned char bp[3], unsigned char sp[3], int blendmode)
237
{
238
int k;
239
/* non-separable blend modes */
240
switch (blendmode)
241
{
242
case FZ_BLEND_HUE: fz_hue_rgb(&dp[0], &dp[1], &dp[2], bp[0], bp[1], bp[2], sp[0], sp[1], sp[2]); return;
243
case FZ_BLEND_SATURATION: fz_saturation_rgb(&dp[0], &dp[1], &dp[2], bp[0], bp[1], bp[2], sp[0], sp[1], sp[2]); return;
244
case FZ_BLEND_COLOR: fz_color_rgb(&dp[0], &dp[1], &dp[2], bp[0], bp[1], bp[2], sp[0], sp[1], sp[2]); return;
245
case FZ_BLEND_LUMINOSITY: fz_luminosity_rgb(&dp[0], &dp[1], &dp[2], bp[0], bp[1], bp[2], sp[0], sp[1], sp[2]); return;
246
}
247
/* separable blend modes */
248
for (k = 0; k < 3; k++)
249
{
250
switch (blendmode)
251
{
252
default:
253
case FZ_BLEND_NORMAL: dp[k] = sp[k]; break;
254
case FZ_BLEND_MULTIPLY: dp[k] = fz_mul255(bp[k], sp[k]); break;
255
case FZ_BLEND_SCREEN: dp[k] = fz_screen_byte(bp[k], sp[k]); break;
256
case FZ_BLEND_OVERLAY: dp[k] = fz_overlay_byte(bp[k], sp[k]); break;
257
case FZ_BLEND_DARKEN: dp[k] = fz_darken_byte(bp[k], sp[k]); break;
258
case FZ_BLEND_LIGHTEN: dp[k] = fz_lighten_byte(bp[k], sp[k]); break;
259
case FZ_BLEND_COLOR_DODGE: dp[k] = fz_color_dodge_byte(bp[k], sp[k]); break;
260
case FZ_BLEND_COLOR_BURN: dp[k] = fz_color_burn_byte(bp[k], sp[k]); break;
261
case FZ_BLEND_HARD_LIGHT: dp[k] = fz_hard_light_byte(bp[k], sp[k]); break;
262
case FZ_BLEND_SOFT_LIGHT: dp[k] = fz_soft_light_byte(bp[k], sp[k]); break;
263
case FZ_BLEND_DIFFERENCE: dp[k] = fz_difference_byte(bp[k], sp[k]); break;
264
case FZ_BLEND_EXCLUSION: dp[k] = fz_exclusion_byte(bp[k], sp[k]); break;
265
}
266
}
267
}
268
269
/* Blending loops */
270
271
void
272
fz_blend_separable(byte * restrict bp, byte * restrict sp, int n, int w, int blendmode)
273
{
274
int k;
275
int n1 = n - 1;
276
while (w--)
277
{
278
int sa = sp[n1];
279
int ba = bp[n1];
280
int saba = fz_mul255(sa, ba);
281
282
/* ugh, division to get non-premul components */
283
int invsa = sa ? 255 * 256 / sa : 0;
284
int invba = ba ? 255 * 256 / ba : 0;
285
286
for (k = 0; k < n1; k++)
287
{
288
int sc = (sp[k] * invsa) >> 8;
289
int bc = (bp[k] * invba) >> 8;
290
int rc;
291
292
switch (blendmode)
293
{
294
default:
295
case FZ_BLEND_NORMAL: rc = sc; break;
296
case FZ_BLEND_MULTIPLY: rc = fz_mul255(bc, sc); break;
297
case FZ_BLEND_SCREEN: rc = fz_screen_byte(bc, sc); break;
298
case FZ_BLEND_OVERLAY: rc = fz_overlay_byte(bc, sc); break;
299
case FZ_BLEND_DARKEN: rc = fz_darken_byte(bc, sc); break;
300
case FZ_BLEND_LIGHTEN: rc = fz_lighten_byte(bc, sc); break;
301
case FZ_BLEND_COLOR_DODGE: rc = fz_color_dodge_byte(bc, sc); break;
302
case FZ_BLEND_COLOR_BURN: rc = fz_color_burn_byte(bc, sc); break;
303
case FZ_BLEND_HARD_LIGHT: rc = fz_hard_light_byte(bc, sc); break;
304
case FZ_BLEND_SOFT_LIGHT: rc = fz_soft_light_byte(bc, sc); break;
305
case FZ_BLEND_DIFFERENCE: rc = fz_difference_byte(bc, sc); break;
306
case FZ_BLEND_EXCLUSION: rc = fz_exclusion_byte(bc, sc); break;
307
}
308
309
bp[k] = fz_mul255(255 - sa, bp[k]) + fz_mul255(255 - ba, sp[k]) + fz_mul255(saba, rc);
310
}
311
312
bp[k] = ba + sa - saba;
313
314
sp += n;
315
bp += n;
316
}
317
}
318
319
void
320
fz_blend_nonseparable(byte * restrict bp, byte * restrict sp, int w, int blendmode)
321
{
322
while (w--)
323
{
324
unsigned char rr, rg, rb;
325
326
int sa = sp[3];
327
int ba = bp[3];
328
int saba = fz_mul255(sa, ba);
329
330
/* ugh, division to get non-premul components */
331
int invsa = sa ? 255 * 256 / sa : 0;
332
int invba = ba ? 255 * 256 / ba : 0;
333
334
int sr = (sp[0] * invsa) >> 8;
335
int sg = (sp[1] * invsa) >> 8;
336
int sb = (sp[2] * invsa) >> 8;
337
338
int br = (bp[0] * invba) >> 8;
339
int bg = (bp[1] * invba) >> 8;
340
int bb = (bp[2] * invba) >> 8;
341
342
switch (blendmode)
343
{
344
default:
345
case FZ_BLEND_HUE:
346
fz_hue_rgb(&rr, &rg, &rb, br, bg, bb, sr, sg, sb);
347
break;
348
case FZ_BLEND_SATURATION:
349
fz_saturation_rgb(&rr, &rg, &rb, br, bg, bb, sr, sg, sb);
350
break;
351
case FZ_BLEND_COLOR:
352
fz_color_rgb(&rr, &rg, &rb, br, bg, bb, sr, sg, sb);
353
break;
354
case FZ_BLEND_LUMINOSITY:
355
fz_luminosity_rgb(&rr, &rg, &rb, br, bg, bb, sr, sg, sb);
356
break;
357
}
358
359
bp[0] = fz_mul255(255 - sa, bp[0]) + fz_mul255(255 - ba, sp[0]) + fz_mul255(saba, rr);
360
bp[1] = fz_mul255(255 - sa, bp[1]) + fz_mul255(255 - ba, sp[1]) + fz_mul255(saba, rg);
361
bp[2] = fz_mul255(255 - sa, bp[2]) + fz_mul255(255 - ba, sp[2]) + fz_mul255(saba, rb);
362
bp[3] = ba + sa - saba;
363
364
sp += 4;
365
bp += 4;
366
}
367
}
368
369
static void
370
fz_blend_separable_nonisolated(byte * restrict bp, byte * restrict sp, int n, int w, int blendmode, byte * restrict hp, int alpha)
371
{
372
int k;
373
int n1 = n - 1;
374
375
if (alpha == 255 && blendmode == 0)
376
{
377
/* In this case, the uncompositing and the recompositing
378
* cancel one another out, and it's just a simple copy. */
379
/* FIXME: Maybe we can avoid using the shape plane entirely
380
* and just copy? */
381
while (w--)
382
{
383
int ha = fz_mul255(*hp++, alpha); /* ha = shape_alpha */
384
/* If ha == 0 then leave everything unchanged */
385
if (ha != 0)
386
{
387
for (k = 0; k < n; k++)
388
{
389
bp[k] = sp[k];
390
}
391
}
392
393
sp += n;
394
bp += n;
395
}
396
return;
397
}
398
while (w--)
399
{
400
int ha = *hp++;
401
int haa = fz_mul255(ha, alpha); /* ha = shape_alpha */
402
/* If haa == 0 then leave everything unchanged */
403
while (haa != 0) /* Use while, so we can break out */
404
{
405
int sa, ba, bahaa, ra, invsa, invba, invha, invra;
406
sa = sp[n1];
407
if (sa == 0)
408
break; /* No change! */
409
invsa = sa ? 255 * 256 / sa : 0;
410
ba = bp[n1];
411
if (ba == 0)
412
{
413
/* Just copy pixels (allowing for change in
414
* premultiplied alphas) */
415
for (k = 0; k < n1; k++)
416
{
417
bp[k] = fz_mul255((sp[k] * invsa) >> 8, haa);
418
}
419
bp[n1] = haa;
420
break;
421
}
422
bahaa = fz_mul255(ba, haa);
423
424
/* ugh, division to get non-premul components */
425
invba = ba ? 255 * 256 / ba : 0;
426
427
/* Calculate result_alpha - a combination of the
428
* background alpha, and 'shape' */
429
ra = bp[n1] = ba - bahaa + haa;
430
if (ra == 0)
431
break;
432
/* Because we are a non-isolated group, we need to
433
* 'uncomposite' before we blend (recomposite).
434
* We assume that normal blending has been done inside
435
* the group, so: rc = (1-ha).bc + ha.sc
436
* A bit of rearrangement, and that gives us that:
437
* sc = (rc - bc)/ha + bc
438
* Now, the result of the blend (rc) was stored in src, so
439
* we actually want to calculate:
440
* sc = (sc-bc)/ha + bc
441
*/
442
invha = ha ? 255 * 256 / ha : 0;
443
invra = ra ? 255 * 256 / ra : 0;
444
445
/* sa = the final alpha to blend with - this
446
* is calculated from the shape + alpha,
447
* divided by ra. */
448
sa = (haa*invra + 128)>>8;
449
if (sa < 0) sa = 0;
450
if (sa > 255) sa = 255;
451
452
for (k = 0; k < n1; k++)
453
{
454
/* Read pixels (and convert to non-premultiplied form) */
455
int sc = (sp[k] * invsa + 128) >> 8;
456
int bc = (bp[k] * invba + 128) >> 8;
457
int rc;
458
459
/* Uncomposite (see above) */
460
sc = (((sc-bc) * invha + 128)>>8) + bc;
461
if (sc < 0) sc = 0;
462
if (sc > 255) sc = 255;
463
464
switch (blendmode)
465
{
466
default:
467
case FZ_BLEND_NORMAL: rc = sc; break;
468
case FZ_BLEND_MULTIPLY: rc = fz_mul255(bc, sc); break;
469
case FZ_BLEND_SCREEN: rc = fz_screen_byte(bc, sc); break;
470
case FZ_BLEND_OVERLAY: rc = fz_overlay_byte(bc, sc); break;
471
case FZ_BLEND_DARKEN: rc = fz_darken_byte(bc, sc); break;
472
case FZ_BLEND_LIGHTEN: rc = fz_lighten_byte(bc, sc); break;
473
case FZ_BLEND_COLOR_DODGE: rc = fz_color_dodge_byte(bc, sc); break;
474
case FZ_BLEND_COLOR_BURN: rc = fz_color_burn_byte(bc, sc); break;
475
case FZ_BLEND_HARD_LIGHT: rc = fz_hard_light_byte(bc, sc); break;
476
case FZ_BLEND_SOFT_LIGHT: rc = fz_soft_light_byte(bc, sc); break;
477
case FZ_BLEND_DIFFERENCE: rc = fz_difference_byte(bc, sc); break;
478
case FZ_BLEND_EXCLUSION: rc = fz_exclusion_byte(bc, sc); break;
479
}
480
/* Composition formula, as given in pdf_reference17.pdf:
481
* rc = ( 1 - (ha/ra)) * bc + (ha/ra) * ((1-ba)*sc + ba * rc)
482
*/
483
rc = bc + fz_mul255(sa, fz_mul255(255 - ba, sc) + fz_mul255(ba, rc) - bc);
484
if (rc < 0) rc = 0;
485
if (rc > 255) rc = 255;
486
bp[k] = fz_mul255(rc, ra);
487
}
488
break;
489
}
490
491
sp += n;
492
bp += n;
493
}
494
}
495
496
static void
497
fz_blend_nonseparable_nonisolated(byte * restrict bp, byte * restrict sp, int w, int blendmode, byte * restrict hp, int alpha)
498
{
499
while (w--)
500
{
501
int ha = *hp++;
502
int haa = fz_mul255(ha, alpha);
503
if (haa != 0)
504
{
505
int sa = sp[3];
506
int ba = bp[3];
507
int baha = fz_mul255(ba, haa);
508
509
/* Calculate result_alpha */
510
int ra = bp[3] = ba - baha + haa;
511
if (ra != 0)
512
{
513
/* Because we are a non-isolated group, we
514
* need to 'uncomposite' before we blend
515
* (recomposite). We assume that normal
516
* blending has been done inside the group,
517
* so: ra.rc = (1-ha).bc + ha.sc
518
* A bit of rearrangement, and that gives us
519
* that: sc = (ra.rc - bc)/ha + bc
520
* Now, the result of the blend was stored in
521
* src, so: */
522
int invha = ha ? 255 * 256 / ha : 0;
523
524
unsigned char rr, rg, rb;
525
526
/* ugh, division to get non-premul components */
527
int invsa = sa ? 255 * 256 / sa : 0;
528
int invba = ba ? 255 * 256 / ba : 0;
529
530
int sr = (sp[0] * invsa) >> 8;
531
int sg = (sp[1] * invsa) >> 8;
532
int sb = (sp[2] * invsa) >> 8;
533
534
int br = (bp[0] * invba) >> 8;
535
int bg = (bp[1] * invba) >> 8;
536
int bb = (bp[2] * invba) >> 8;
537
538
/* Uncomposite */
539
sr = (((sr-br)*invha)>>8) + br;
540
sg = (((sg-bg)*invha)>>8) + bg;
541
sb = (((sb-bb)*invha)>>8) + bb;
542
543
switch (blendmode)
544
{
545
default:
546
case FZ_BLEND_HUE:
547
fz_hue_rgb(&rr, &rg, &rb, br, bg, bb, sr, sg, sb);
548
break;
549
case FZ_BLEND_SATURATION:
550
fz_saturation_rgb(&rr, &rg, &rb, br, bg, bb, sr, sg, sb);
551
break;
552
case FZ_BLEND_COLOR:
553
fz_color_rgb(&rr, &rg, &rb, br, bg, bb, sr, sg, sb);
554
break;
555
case FZ_BLEND_LUMINOSITY:
556
fz_luminosity_rgb(&rr, &rg, &rb, br, bg, bb, sr, sg, sb);
557
break;
558
}
559
560
rr = fz_mul255(255 - haa, bp[0]) + fz_mul255(fz_mul255(255 - ba, sr), haa) + fz_mul255(baha, rr);
561
rg = fz_mul255(255 - haa, bp[1]) + fz_mul255(fz_mul255(255 - ba, sg), haa) + fz_mul255(baha, rg);
562
rb = fz_mul255(255 - haa, bp[2]) + fz_mul255(fz_mul255(255 - ba, sb), haa) + fz_mul255(baha, rb);
563
bp[0] = fz_mul255(ra, rr);
564
bp[1] = fz_mul255(ra, rg);
565
bp[2] = fz_mul255(ra, rb);
566
}
567
}
568
569
sp += 4;
570
bp += 4;
571
}
572
}
573
574
void
575
fz_blend_pixmap(fz_pixmap *dst, fz_pixmap *src, int alpha, int blendmode, int isolated, fz_pixmap *shape)
576
{
577
unsigned char *sp, *dp;
578
fz_irect bbox;
579
fz_irect bbox2;
580
int x, y, w, h, n;
581
582
/* TODO: fix this hack! */
583
if (isolated && alpha < 255)
584
{
585
sp = src->samples;
586
n = src->w * src->h * src->n;
587
while (n--)
588
{
589
*sp = fz_mul255(*sp, alpha);
590
sp++;
591
}
592
}
593
594
fz_pixmap_bbox_no_ctx(dst, &bbox);
595
fz_pixmap_bbox_no_ctx(src, &bbox2);
596
fz_intersect_irect(&bbox, &bbox2);
597
598
x = bbox.x0;
599
y = bbox.y0;
600
w = bbox.x1 - bbox.x0;
601
h = bbox.y1 - bbox.y0;
602
603
n = src->n;
604
sp = src->samples + (unsigned int)(((y - src->y) * src->w + (x - src->x)) * n);
605
dp = dst->samples + (unsigned int)(((y - dst->y) * dst->w + (x - dst->x)) * n);
606
607
assert(src->n == dst->n);
608
609
if (!isolated)
610
{
611
unsigned char *hp = shape->samples + (unsigned int)((y - shape->y) * shape->w + (x - shape->x));
612
613
while (h--)
614
{
615
if (n == 4 && blendmode >= FZ_BLEND_HUE)
616
fz_blend_nonseparable_nonisolated(dp, sp, w, blendmode, hp, alpha);
617
else
618
fz_blend_separable_nonisolated(dp, sp, n, w, blendmode, hp, alpha);
619
sp += src->w * n;
620
dp += dst->w * n;
621
hp += shape->w;
622
}
623
}
624
else
625
{
626
while (h--)
627
{
628
if (n == 4 && blendmode >= FZ_BLEND_HUE)
629
fz_blend_nonseparable(dp, sp, w, blendmode);
630
else
631
fz_blend_separable(dp, sp, n, w, blendmode);
632
sp += src->w * n;
633
dp += dst->w * n;
634
}
635
}
636
}
637
638