/src/mupdf/source/fitz/draw-mesh.c
Line | Count | Source (jump to first uncovered line) |
1 | | // Copyright (C) 2004-2021 Artifex Software, Inc. |
2 | | // |
3 | | // This file is part of MuPDF. |
4 | | // |
5 | | // MuPDF is free software: you can redistribute it and/or modify it under the |
6 | | // terms of the GNU Affero General Public License as published by the Free |
7 | | // Software Foundation, either version 3 of the License, or (at your option) |
8 | | // any later version. |
9 | | // |
10 | | // MuPDF is distributed in the hope that it will be useful, but WITHOUT ANY |
11 | | // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS |
12 | | // FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more |
13 | | // details. |
14 | | // |
15 | | // You should have received a copy of the GNU Affero General Public License |
16 | | // along with MuPDF. If not, see <https://www.gnu.org/licenses/agpl-3.0.en.html> |
17 | | // |
18 | | // Alternative licensing terms are available from the licensor. |
19 | | // For commercial licensing, see <https://www.artifex.com/> or contact |
20 | | // Artifex Software, Inc., 39 Mesa Street, Suite 108A, San Francisco, |
21 | | // CA 94129, USA, for further information. |
22 | | |
23 | | #include "mupdf/fitz.h" |
24 | | |
25 | | #include "color-imp.h" |
26 | | #include "draw-imp.h" |
27 | | #include "pixmap-imp.h" |
28 | | |
29 | | #include <assert.h> |
30 | | #include <math.h> |
31 | | |
32 | | enum { MAXN = 2 + FZ_MAX_COLORS }; |
33 | | |
34 | | static void paint_scan(fz_pixmap *FZ_RESTRICT pix, int y, int fx0, int fx1, int cx0, int cx1, const int *FZ_RESTRICT v0, const int *FZ_RESTRICT v1, int n) |
35 | 8.78M | { |
36 | 8.78M | unsigned char *p; |
37 | 8.78M | int c[MAXN], dc[MAXN]; |
38 | 8.78M | int k, w; |
39 | 8.78M | float div, mul; |
40 | 8.78M | int x0, x1, pa; |
41 | | |
42 | | /* Ensure that fx0 is left edge, and fx1 is right */ |
43 | 8.78M | if (fx0 > fx1) |
44 | 3.41M | { |
45 | 3.41M | const int *v; |
46 | 3.41M | int t = fx0; fx0 = fx1; fx1 = t; |
47 | 3.41M | v = v0; v0 = v1; v1 = v; |
48 | 3.41M | } |
49 | 5.36M | else if (fx0 == fx1) |
50 | 2.11M | return; |
51 | | |
52 | | /* Clip fx0, fx1 to range */ |
53 | 6.67M | if (fx0 >= cx1) |
54 | 2.57M | return; |
55 | 4.09M | if (fx1 <= cx0) |
56 | 841k | return; |
57 | 3.25M | x0 = (fx0 > cx0 ? fx0 : cx0); |
58 | 3.25M | x1 = (fx1 < cx1 ? fx1 : cx1); |
59 | | |
60 | 3.25M | w = x1 - x0; |
61 | 3.25M | if (w == 0) |
62 | 0 | return; |
63 | | |
64 | 3.25M | div = 1.0f / (fx1 - fx0); |
65 | 3.25M | mul = (x0 - fx0); |
66 | 13.5M | for (k = 0; k < n; k++) |
67 | 10.3M | { |
68 | 10.3M | dc[k] = (v1[k] - v0[k]) * div; |
69 | 10.3M | c[k] = v0[k] + dc[k] * mul; |
70 | 10.3M | } |
71 | | |
72 | 3.25M | p = pix->samples + ((x0 - pix->x) * pix->n) + ((y - pix->y) * pix->stride); |
73 | 3.25M | pa = pix->alpha; |
74 | 3.25M | do |
75 | 260M | { |
76 | 936M | for (k = 0; k < n; k++) |
77 | 676M | { |
78 | 676M | *p++ = c[k]>>16; |
79 | 676M | c[k] += dc[k]; |
80 | 676M | } |
81 | 260M | if (pa) |
82 | 75.9M | *p++ = 255; |
83 | 260M | } |
84 | 260M | while (--w); |
85 | 3.25M | } |
86 | | |
87 | | typedef struct |
88 | | { |
89 | | float x; |
90 | | float dx; |
91 | | int v[2*MAXN]; |
92 | | } edge_data; |
93 | | |
94 | | static inline void prepare_edge(const float *FZ_RESTRICT vtop, const float *FZ_RESTRICT vbot, edge_data *FZ_RESTRICT edge, float y, int n) |
95 | 3.50M | { |
96 | 3.50M | float r = 1.0f / (vbot[1] - vtop[1]); |
97 | 3.50M | float t = (y - vtop[1]) * r; |
98 | 3.50M | float diff = vbot[0] - vtop[0]; |
99 | 3.50M | int i; |
100 | | |
101 | 3.50M | edge->x = vtop[0] + diff * t; |
102 | 3.50M | edge->dx = diff * r; |
103 | | |
104 | 13.8M | for (i = 0; i < n; i++) |
105 | 10.3M | { |
106 | 10.3M | diff = vbot[i+2] - vtop[i+2]; |
107 | 10.3M | edge->v[i] = (int)(65536.0f * (vtop[i+2] + diff * t)); |
108 | 10.3M | edge->v[i+MAXN] = (int)(65536.0f * diff * r); |
109 | 10.3M | } |
110 | 3.50M | } |
111 | | |
112 | | static inline void step_edge(edge_data *edge, int n) |
113 | 15.9M | { |
114 | 15.9M | int i; |
115 | | |
116 | 15.9M | edge->x += edge->dx; |
117 | | |
118 | 63.1M | for (i = 0; i < n; i++) |
119 | 47.2M | { |
120 | 47.2M | edge->v[i] += edge->v[i + MAXN]; |
121 | 47.2M | } |
122 | 15.9M | } |
123 | | |
124 | | static void |
125 | | fz_paint_triangle(fz_pixmap *pix, float *v[3], int n, fz_irect bbox) |
126 | 2.24M | { |
127 | 2.24M | edge_data e0, e1; |
128 | 2.24M | int top, mid, bot; |
129 | 2.24M | float y, y1; |
130 | 2.24M | int minx, maxx; |
131 | | |
132 | 2.24M | top = bot = 0; |
133 | 2.24M | if (v[1][1] < v[0][1]) top = 1; else bot = 1; |
134 | 2.24M | if (v[2][1] < v[top][1]) top = 2; |
135 | 1.51M | else if (v[2][1] > v[bot][1]) bot = 2; |
136 | 2.24M | if (v[top][1] == v[bot][1]) return; |
137 | | |
138 | | /* Test if the triangle is completely outside the scissor rect */ |
139 | 1.93M | if (v[bot][1] < bbox.y0) return; |
140 | 1.89M | if (v[top][1] > bbox.y1) return; |
141 | | |
142 | | /* Magic! Ensure that mid/top/bot are all different */ |
143 | 1.86M | mid = 3^top^bot; |
144 | | |
145 | 1.86M | assert(top != bot && top != mid && mid != bot); |
146 | | |
147 | 1.86M | minx = fz_maxi(bbox.x0, pix->x); |
148 | 1.86M | maxx = fz_mini(bbox.x1, pix->x + pix->w); |
149 | | |
150 | 1.86M | y = ceilf(fz_max(bbox.y0, v[top][1])); |
151 | 1.86M | y1 = ceilf(fz_min(bbox.y1, v[mid][1])); |
152 | | |
153 | 1.86M | n -= 2; |
154 | 1.86M | prepare_edge(v[top], v[bot], &e0, y, n); |
155 | 1.86M | if (y < y1) |
156 | 820k | { |
157 | 820k | prepare_edge(v[top], v[mid], &e1, y, n); |
158 | | |
159 | 820k | do |
160 | 4.91M | { |
161 | 4.91M | paint_scan(pix, y, (int)e0.x, (int)e1.x, minx, maxx, &e0.v[0], &e1.v[0], n); |
162 | 4.91M | step_edge(&e0, n); |
163 | 4.91M | step_edge(&e1, n); |
164 | 4.91M | y ++; |
165 | 4.91M | } |
166 | 4.91M | while (y < y1); |
167 | 820k | } |
168 | | |
169 | 1.86M | y1 = ceilf(fz_min(bbox.y1, v[bot][1])); |
170 | 1.86M | if (y < y1) |
171 | 822k | { |
172 | 822k | prepare_edge(v[mid], v[bot], &e1, y, n); |
173 | | |
174 | 822k | do |
175 | 3.86M | { |
176 | 3.86M | paint_scan(pix, y, (int)e0.x, (int)e1.x, minx, maxx, &e0.v[0], &e1.v[0], n); |
177 | 3.86M | y ++; |
178 | 3.86M | if (y >= y1) |
179 | 822k | break; |
180 | 3.03M | step_edge(&e0, n); |
181 | 3.03M | step_edge(&e1, n); |
182 | 3.03M | } |
183 | 3.03M | while (1); |
184 | 822k | } |
185 | 1.86M | } |
186 | | |
187 | | struct paint_tri_data |
188 | | { |
189 | | const fz_shade *shade; |
190 | | fz_pixmap *dest; |
191 | | fz_irect bbox; |
192 | | fz_color_converter cc; |
193 | | }; |
194 | | |
195 | | static void |
196 | | prepare_mesh_vertex(fz_context *ctx, void *arg, fz_vertex *v, const float *input) |
197 | 3.90M | { |
198 | 3.90M | struct paint_tri_data *ptd = (struct paint_tri_data *)arg; |
199 | 3.90M | const fz_shade *shade = ptd->shade; |
200 | 3.90M | fz_pixmap *dest = ptd->dest; |
201 | 3.90M | float *output = v->c; |
202 | 3.90M | int i; |
203 | | |
204 | 3.90M | if (shade->use_function) |
205 | 656k | { |
206 | 656k | float f = input[0]; |
207 | 656k | if (shade->type >= 4 && shade->type <= 7) |
208 | 125k | f = (f - shade->u.m.c0[0]) / (shade->u.m.c1[0] - shade->u.m.c0[0]); |
209 | 656k | output[0] = f * 255; |
210 | 656k | } |
211 | 3.25M | else |
212 | 3.25M | { |
213 | 3.25M | int n = fz_colorspace_n(ctx, dest->colorspace); |
214 | 3.25M | int a = dest->alpha; |
215 | 3.25M | int m = dest->n - a; |
216 | 3.25M | if (ptd->cc.convert) |
217 | 3.25M | ptd->cc.convert(ctx, &ptd->cc, input, output); |
218 | 14.7M | for (i = 0; i < n; i++) |
219 | 11.4M | output[i] *= 255; |
220 | 3.25M | for (; i < m; i++) |
221 | 0 | output[i] = 0; |
222 | 3.25M | if (a) |
223 | 1.71M | output[i] = 255; |
224 | 3.25M | } |
225 | 3.90M | } |
226 | | |
227 | | static void |
228 | | do_paint_tri(fz_context *ctx, void *arg, fz_vertex *av, fz_vertex *bv, fz_vertex *cv) |
229 | 2.24M | { |
230 | 2.24M | struct paint_tri_data *ptd = (struct paint_tri_data *)arg; |
231 | 2.24M | float *vertices[3]; |
232 | 2.24M | fz_pixmap *dest; |
233 | | |
234 | 2.24M | vertices[0] = (float *)av; |
235 | 2.24M | vertices[1] = (float *)bv; |
236 | 2.24M | vertices[2] = (float *)cv; |
237 | | |
238 | 2.24M | dest = ptd->dest; |
239 | 2.24M | fz_paint_triangle(dest, vertices, 2 + dest->n - dest->alpha, ptd->bbox); |
240 | 2.24M | } |
241 | | |
242 | | struct fz_shade_color_cache |
243 | | { |
244 | | fz_colorspace *src; |
245 | | fz_colorspace *dst; |
246 | | fz_color_params params; |
247 | | int full; |
248 | | fz_color_converter cached; |
249 | | fz_colorspace *src2; |
250 | | fz_colorspace *dst2; |
251 | | fz_color_params params2; |
252 | | int full2; |
253 | | fz_color_converter cached2; |
254 | | }; |
255 | | |
256 | | void |
257 | | fz_drop_shade_color_cache(fz_context *ctx, fz_shade_color_cache *cache) |
258 | 18.2k | { |
259 | 18.2k | if (cache == NULL) |
260 | 17.9k | return; |
261 | | |
262 | 378 | fz_drop_colorspace(ctx, cache->src); |
263 | 378 | fz_drop_colorspace(ctx, cache->dst); |
264 | 378 | if (cache->full) |
265 | 378 | fz_fin_cached_color_converter(ctx, &cache->cached); |
266 | | |
267 | 378 | fz_drop_colorspace(ctx, cache->src2); |
268 | 378 | fz_drop_colorspace(ctx, cache->dst2); |
269 | 378 | if (cache->full2) |
270 | 166 | fz_drop_color_converter(ctx, &cache->cached2); |
271 | | |
272 | 378 | fz_free(ctx, cache); |
273 | 378 | } |
274 | | |
275 | | void |
276 | | fz_paint_shade(fz_context *ctx, fz_shade *shade, fz_colorspace *colorspace, fz_matrix ctm, fz_pixmap *dest, fz_color_params color_params, fz_irect bbox, const fz_overprint *eop, fz_shade_color_cache **color_cache) |
277 | 64.6k | { |
278 | 64.6k | unsigned char clut[256][FZ_MAX_COLORS]; |
279 | 64.6k | fz_pixmap *temp = NULL; |
280 | 64.6k | fz_pixmap *conv = NULL; |
281 | 64.6k | fz_color_converter cc = { 0 }; |
282 | 64.6k | float color[FZ_MAX_COLORS]; |
283 | 64.6k | struct paint_tri_data ptd = { 0 }; |
284 | 64.6k | int i, k; |
285 | 64.6k | fz_matrix local_ctm; |
286 | 64.6k | fz_shade_color_cache *cache = NULL; |
287 | 64.6k | int recache = 0; |
288 | 64.6k | int recache2 = 0; |
289 | | |
290 | 64.6k | fz_var(temp); |
291 | 64.6k | fz_var(conv); |
292 | 64.6k | fz_var(recache); |
293 | 64.6k | fz_var(recache2); |
294 | 64.6k | fz_var(cc); |
295 | | |
296 | 64.6k | if (colorspace == NULL) |
297 | 0 | colorspace = shade->colorspace; |
298 | | |
299 | 64.6k | if (color_cache) |
300 | 64.6k | { |
301 | 64.6k | cache = *color_cache; |
302 | 64.6k | if (cache == NULL) |
303 | 378 | *color_cache = cache = fz_malloc_struct(ctx, fz_shade_color_cache); |
304 | 64.6k | } |
305 | | |
306 | 129k | fz_try(ctx) |
307 | 129k | { |
308 | 64.6k | local_ctm = fz_concat(shade->matrix, ctm); |
309 | | |
310 | 64.6k | if (shade->use_function) |
311 | 64.3k | { |
312 | | /* We need to use alpha = 1 here, because the shade might not fill the bbox. */ |
313 | 64.3k | temp = fz_new_pixmap_with_bbox(ctx, fz_device_gray(ctx), bbox, NULL, 1); |
314 | 64.3k | fz_clear_pixmap(ctx, temp); |
315 | 64.3k | } |
316 | 296 | else |
317 | 296 | { |
318 | 296 | temp = dest; |
319 | 296 | } |
320 | | |
321 | 64.6k | ptd.dest = temp; |
322 | 64.6k | ptd.shade = shade; |
323 | 64.6k | ptd.bbox = bbox; |
324 | | |
325 | 64.6k | if (temp->colorspace) |
326 | 64.6k | { |
327 | 64.6k | if (cache && cache->full && cache->src == colorspace && cache->dst == temp->colorspace && |
328 | 64.6k | cache->params.op == color_params.op && |
329 | 64.6k | cache->params.opm == color_params.opm && |
330 | 64.6k | cache->params.ri == color_params.ri) |
331 | 1.28k | { |
332 | 1.28k | ptd.cc = cache->cached; |
333 | 1.28k | cache->full = 0; |
334 | 1.28k | } |
335 | 63.3k | else |
336 | 63.3k | fz_init_cached_color_converter(ctx, &ptd.cc, colorspace, temp->colorspace, NULL, color_params); |
337 | | |
338 | | /* Drop the existing contents of the cache. */ |
339 | 64.6k | if (cache) |
340 | 64.6k | { |
341 | 64.6k | fz_drop_colorspace(ctx, cache->src); |
342 | 64.6k | cache->src = NULL; |
343 | 64.6k | fz_drop_colorspace(ctx, cache->dst); |
344 | 64.6k | cache->dst = NULL; |
345 | 64.6k | if (cache->full) |
346 | 63.0k | fz_fin_cached_color_converter(ctx, &cache->cached); |
347 | 64.6k | cache->full = 0; |
348 | | |
349 | | /* Remember that we can put stuff back into the cache. */ |
350 | 64.6k | recache = 1; |
351 | 64.6k | } |
352 | 64.6k | } |
353 | | |
354 | 64.6k | fz_process_shade(ctx, shade, local_ctm, fz_rect_from_irect(bbox), prepare_mesh_vertex, &do_paint_tri, &ptd); |
355 | | |
356 | 64.6k | if (shade->use_function) |
357 | 64.3k | { |
358 | | /* If the shade is defined in a deviceN (or separation, |
359 | | * which is the same internally to MuPDF) space, then |
360 | | * we need to render it in deviceN before painting it |
361 | | * to the destination. If not, we are free to render it |
362 | | * direct to the target. */ |
363 | 64.3k | if (fz_colorspace_is_device_n(ctx, colorspace)) |
364 | 62.7k | { |
365 | | /* We've drawn it as greyscale, with the values being |
366 | | * the input to the function. Now make DevN version |
367 | | * by mapping that greyscale through the function. |
368 | | * This seems inefficient, but it's actually required, |
369 | | * because we need to apply the function lookup POST |
370 | | * interpolation in the do_paint_tri routines, not |
371 | | * before it to avoid problems with some test files |
372 | | * (tests/GhentV3.0/061_Shading_x1a.pdf for example). |
373 | | */ |
374 | 62.7k | unsigned char *s = temp->samples; |
375 | 62.7k | unsigned char *d; |
376 | 62.7k | int hh = temp->h; |
377 | 62.7k | int n = fz_colorspace_n(ctx, colorspace); |
378 | | |
379 | | /* alpha = 1 here for the same reason as earlier */ |
380 | 62.7k | conv = fz_new_pixmap_with_bbox(ctx, colorspace, bbox, NULL, 1); |
381 | 62.7k | d = conv->samples; |
382 | 259k | while (hh--) |
383 | 196k | { |
384 | 196k | int len = temp->w; |
385 | 42.6M | while (len--) |
386 | 42.4M | { |
387 | 42.4M | int v = *s++; |
388 | 42.4M | int a = *s++; |
389 | 42.4M | const float *f = shade->function[v]; |
390 | 86.5M | for (k = 0; k < n; k++) |
391 | 44.0M | *d++ = fz_clampi(255 * f[k], 0, 255); |
392 | 42.4M | *d++ = a; |
393 | 42.4M | } |
394 | 196k | d += conv->stride - conv->w * (size_t)conv->n; |
395 | 196k | s += temp->stride - temp->w * (size_t)temp->n; |
396 | 196k | } |
397 | 62.7k | fz_drop_pixmap(ctx, temp); |
398 | 62.7k | temp = conv; |
399 | 62.7k | conv = NULL; |
400 | | |
401 | | /* Now Change from our device_n colorspace into the target colorspace/spots. */ |
402 | 62.7k | conv = fz_clone_pixmap_area_with_different_seps(ctx, temp, NULL, dest->colorspace, dest->seps, color_params, NULL); |
403 | 62.7k | } |
404 | 1.62k | else |
405 | 1.62k | { |
406 | 1.62k | unsigned char *s = temp->samples; |
407 | 1.62k | unsigned char *d; |
408 | 1.62k | int da; |
409 | 1.62k | int sa = temp->alpha; |
410 | 1.62k | int hh = temp->h; |
411 | 1.62k | int cn = fz_colorspace_n(ctx, colorspace); |
412 | 1.62k | int m = dest->n - dest->alpha; |
413 | 1.62k | int n = fz_colorspace_n(ctx, dest->colorspace); |
414 | | |
415 | 1.62k | if (dest->colorspace) |
416 | 1.62k | { |
417 | 1.62k | if (cache && cache->full2 && cache->src2 == colorspace && cache->dst2 == dest->colorspace && |
418 | 1.62k | cache->params2.op == color_params.op && |
419 | 1.62k | cache->params2.opm == color_params.opm && |
420 | 1.62k | cache->params2.ri == color_params.ri) |
421 | 1.39k | { |
422 | 1.39k | cc = cache->cached2; |
423 | 1.39k | cache->full2 = 0; |
424 | 1.39k | } |
425 | 238 | else |
426 | 238 | fz_find_color_converter(ctx, &cc, colorspace, dest->colorspace, NULL, color_params); |
427 | | |
428 | | /* Drop the existing contents of the cache */ |
429 | 1.62k | if (cache) |
430 | 1.62k | { |
431 | 1.62k | fz_drop_colorspace(ctx, cache->src2); |
432 | 1.62k | cache->src2 = NULL; |
433 | 1.62k | fz_drop_colorspace(ctx, cache->dst2); |
434 | 1.62k | cache->dst2 = NULL; |
435 | 1.62k | if (cache->full2) |
436 | 72 | fz_drop_color_converter(ctx, &cache->cached2); |
437 | 1.62k | cache->full2 = 0; |
438 | | |
439 | | /* Remember that we can put stuff back into the cache. */ |
440 | 1.62k | recache2 = 1; |
441 | 1.62k | } |
442 | 418k | for (i = 0; i < 256; i++) |
443 | 416k | { |
444 | 416k | cc.convert(ctx, &cc, shade->function[i], color); |
445 | 1.77M | for (k = 0; k < n; k++) |
446 | 1.35M | clut[i][k] = color[k] * 255; |
447 | 416k | for (; k < m; k++) |
448 | 0 | clut[i][k] = 0; |
449 | 416k | clut[i][k] = shade->function[i][cn] * 255; |
450 | 416k | } |
451 | 1.62k | } |
452 | 1 | else |
453 | 1 | { |
454 | 257 | for (i = 0; i < 256; i++) |
455 | 256 | { |
456 | 256 | for (k = 0; k < m; k++) |
457 | 0 | clut[i][k] = 0; |
458 | 256 | clut[i][k] = shade->function[i][cn] * 255; |
459 | 256 | } |
460 | 1 | } |
461 | | |
462 | 1.62k | conv = fz_new_pixmap_with_bbox(ctx, dest->colorspace, bbox, dest->seps, 1); |
463 | 1.62k | d = conv->samples; |
464 | 1.62k | da = conv->alpha; |
465 | 67.8k | while (hh--) |
466 | 66.2k | { |
467 | 66.2k | int len = temp->w; |
468 | 12.9M | while (len--) |
469 | 12.8M | { |
470 | 12.8M | int v = *s++; |
471 | 12.8M | int a = (da ? clut[v][conv->n - 1] : 255); |
472 | 12.8M | if (sa) |
473 | 12.8M | a = fz_mul255(*s++, a); |
474 | 49.6M | for (k = 0; k < conv->n - da; k++) |
475 | 36.7M | *d++ = fz_mul255(clut[v][k], a); |
476 | 12.8M | if (da) |
477 | 12.8M | *d++ = a; |
478 | 12.8M | } |
479 | 66.2k | d += conv->stride - conv->w * (size_t)conv->n; |
480 | 66.2k | s += temp->stride - temp->w * (size_t)temp->n; |
481 | 66.2k | } |
482 | 1.62k | } |
483 | 64.3k | fz_paint_pixmap_with_overprint(dest, conv, eop); |
484 | 64.3k | } |
485 | 64.6k | } |
486 | 129k | fz_always(ctx) |
487 | 64.6k | { |
488 | 64.6k | if (recache) |
489 | 64.6k | { |
490 | 64.6k | cache->src = fz_keep_colorspace(ctx, colorspace); |
491 | 64.6k | cache->dst = fz_keep_colorspace(ctx, temp->colorspace); |
492 | 64.6k | cache->params = color_params; |
493 | 64.6k | cache->cached = ptd.cc; |
494 | 64.6k | cache->full = 1; |
495 | 64.6k | } |
496 | 0 | else |
497 | 0 | fz_fin_cached_color_converter(ctx, &ptd.cc); |
498 | 64.6k | if (shade->use_function) |
499 | 64.3k | { |
500 | 64.3k | if (recache2) |
501 | 1.62k | { |
502 | 1.62k | cache->src2 = fz_keep_colorspace(ctx, colorspace); |
503 | 1.62k | cache->dst2 = fz_keep_colorspace(ctx, dest->colorspace); |
504 | 1.62k | cache->params2 = color_params; |
505 | 1.62k | cache->cached2 = cc; |
506 | 1.62k | cache->full2 = 1; |
507 | 1.62k | } |
508 | 62.7k | else |
509 | 62.7k | fz_drop_color_converter(ctx, &cc); |
510 | 64.3k | fz_drop_pixmap(ctx, temp); |
511 | 64.3k | fz_drop_pixmap(ctx, conv); |
512 | 64.3k | } |
513 | 64.6k | } |
514 | 64.6k | fz_catch(ctx) |
515 | 0 | fz_rethrow(ctx); |
516 | 64.6k | } |