handle failure to clone the log filehandle when cloning the Imager context
[imager.git] / maskimg.c
CommitLineData
faa9b3e7
TC
1/*
2=head1 NAME
3
4maskimg.c - implements masked images/image subsets
5
6=head1 SYNOPSIS
7
8=head1 DESCRIPTION
9
10=over
11=cut
12*/
13
3cb06f59
TC
14#define IMAGER_NO_CONTEXT
15
92bda632
TC
16#include "imager.h"
17#include "imageri.h"
faa9b3e7
TC
18
19#include <stdio.h>
20/*
21=item i_img_mask_ext
22
23A pointer to this type of object is kept in the ext_data of a masked
24image.
25
26=cut
27*/
28
29typedef struct {
30 i_img *targ;
31 i_img *mask;
8d14daab 32 i_img_dim xbase, ybase;
faa9b3e7
TC
33 i_sample_t *samps; /* temp space */
34} i_img_mask_ext;
35
36#define MASKEXT(im) ((i_img_mask_ext *)((im)->ext_data))
37
38static void i_destroy_masked(i_img *im);
8d14daab
TC
39static int i_ppix_masked(i_img *im, i_img_dim x, i_img_dim y, const i_color *pix);
40static int i_ppixf_masked(i_img *im, i_img_dim x, i_img_dim y, const i_fcolor *pix);
41static i_img_dim i_plin_masked(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, const i_color *vals);
42static i_img_dim i_plinf_masked(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, const i_fcolor *vals);
43static int i_gpix_masked(i_img *im, i_img_dim x, i_img_dim y, i_color *pix);
44static int i_gpixf_masked(i_img *im, i_img_dim x, i_img_dim y, i_fcolor *pix);
45static i_img_dim i_glin_masked(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, i_color *vals);
46static i_img_dim i_glinf_masked(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, i_fcolor *vals);
47static i_img_dim i_gsamp_masked(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, i_sample_t *samp,
18accb2a 48 int const *chans, int chan_count);
8d14daab 49static i_img_dim i_gsampf_masked(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, i_fsample_t *samp,
18accb2a 50 int const *chans, int chan_count);
8d14daab
TC
51static i_img_dim i_gpal_masked(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, i_palidx *vals);
52static i_img_dim i_ppal_masked(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, const i_palidx *vals);
836d9f54
TC
53static i_img_dim
54psamp_masked(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y,
55 const i_sample_t *samples, const int *chans, int chan_count);
56static i_img_dim
57psampf_masked(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y,
58 const i_fsample_t *samples, const int *chans, int chan_count);
faa9b3e7
TC
59
60/*
61=item IIM_base_masked
62
63The basic data we copy into a masked image.
64
65=cut
66*/
67static i_img IIM_base_masked =
68{
69 0, /* channels set */
70 0, 0, 0, /* xsize, ysize, bytes */
9a88a5e6 71 ~0U, /* ch_mask */
faa9b3e7
TC
72 i_8_bits, /* bits */
73 i_palette_type, /* type */
74 1, /* virtual */
75 NULL, /* idata */
76 { 0, 0, NULL }, /* tags */
77 NULL, /* ext_data */
78
79 i_ppix_masked, /* i_f_ppix */
80 i_ppixf_masked, /* i_f_ppixf */
81 i_plin_masked, /* i_f_plin */
82 i_plinf_masked, /* i_f_plinf */
83 i_gpix_masked, /* i_f_gpix */
84 i_gpixf_masked, /* i_f_gpixf */
85 i_glin_masked, /* i_f_glin */
86 i_glinf_masked, /* i_f_glinf */
87 i_gsamp_masked, /* i_f_gsamp */
88 i_gsampf_masked, /* i_f_gsampf */
89
90 i_gpal_masked, /* i_f_gpal */
91 i_ppal_masked, /* i_f_ppal */
92 i_addcolors_forward, /* i_f_addcolors */
93 i_getcolors_forward, /* i_f_getcolors */
94 i_colorcount_forward, /* i_f_colorcount */
95 i_maxcolors_forward, /* i_f_maxcolors */
96 i_findcolor_forward, /* i_f_findcolor */
97 i_setcolors_forward, /* i_f_setcolors */
98
99 i_destroy_masked, /* i_f_destroy */
836d9f54
TC
100
101 NULL, /* i_f_gsamp_bits */
102 NULL, /* i_f_psamp_bits */
103
104 psamp_masked, /* i_f_psamp */
105 psampf_masked /* i_f_psampf */
faa9b3e7
TC
106};
107
108/*
8d14daab 109=item i_img_masked_new(i_img *targ, i_img *mask, i_img_dim xbase, i_img_dim ybase, i_img_dim w, i_img_dim h)
faa9b3e7
TC
110
111Create a new masked image.
112
113The image mask is optional, in which case the image is just a view of
114a rectangular portion of the image.
115
116The mask only has an effect of writing to the image, the entire view
117of the underlying image is readable.
118
119pixel access to mimg(x,y) is translated to targ(x+xbase, y+ybase), as long
120as (0 <= x < w) and (0 <= y < h).
121
122For a pixel to be writable, the pixel mask(x,y) must have non-zero in
123it's first channel. No scaling of the pixel is done, the channel
124sample is treated as boolean.
125
126=cut
127*/
128
3cb06f59
TC
129i_img *
130i_img_masked_new(i_img *targ, i_img *mask, i_img_dim x, i_img_dim y, i_img_dim w, i_img_dim h) {
faa9b3e7
TC
131 i_img *im;
132 i_img_mask_ext *ext;
3cb06f59 133 dIMCTXim(targ);
faa9b3e7 134
3cb06f59 135 im_clear_error(aIMCTX);
faa9b3e7 136 if (x >= targ->xsize || y >= targ->ysize) {
3cb06f59 137 im_push_error(aIMCTX, 0, "subset outside of target image");
faa9b3e7
TC
138 return NULL;
139 }
140 if (mask) {
141 if (w > mask->xsize)
142 w = mask->xsize;
143 if (h > mask->ysize)
144 h = mask->ysize;
145 }
146 if (x+w > targ->xsize)
147 w = targ->xsize - x;
148 if (y+h > targ->ysize)
149 h = targ->ysize - y;
150
3cb06f59
TC
151 im = im_img_alloc(aIMCTX);
152
faa9b3e7 153 memcpy(im, &IIM_base_masked, sizeof(i_img));
3cb06f59 154 i_tags_new(&im->tags);
faa9b3e7
TC
155 im->xsize = w;
156 im->ysize = h;
157 im->channels = targ->channels;
158 im->bits = targ->bits;
159 im->type = targ->type;
160 ext = mymalloc(sizeof(*ext));
161 ext->targ = targ;
162 ext->mask = mask;
163 ext->xbase = x;
164 ext->ybase = y;
165 ext->samps = mymalloc(sizeof(i_sample_t) * im->xsize);
166 im->ext_data = ext;
167
3cb06f59
TC
168 im_img_init(aIMCTX, im);
169
faa9b3e7
TC
170 return im;
171}
172
173/*
174=item i_destroy_masked(i_img *im)
175
176The destruction handler for masked images.
177
178Releases the ext_data.
179
180Internal function.
181
182=cut
183*/
184
185static void i_destroy_masked(i_img *im) {
186 myfree(MASKEXT(im)->samps);
187 myfree(im->ext_data);
188}
189
190/*
8d14daab 191=item i_ppix_masked(i_img *im, i_img_dim x, i_img_dim y, const i_color *pix)
faa9b3e7
TC
192
193Write a pixel to a masked image.
194
195Internal function.
196
197=cut
198*/
8d14daab 199static int i_ppix_masked(i_img *im, i_img_dim x, i_img_dim y, const i_color *pix) {
faa9b3e7
TC
200 i_img_mask_ext *ext = MASKEXT(im);
201 int result;
202
203 if (x < 0 || x >= im->xsize || y < 0 || y >= im->ysize)
204 return -1;
205 if (ext->mask) {
206 i_sample_t samp;
207
208 if (i_gsamp(ext->mask, x, x+1, y, &samp, NULL, 1) && !samp)
209 return 0; /* pretend it was good */
210 }
211 result = i_ppix(ext->targ, x + ext->xbase, y + ext->ybase, pix);
212 im->type = ext->targ->type;
213 return result;
214}
215
216/*
8d14daab 217=item i_ppixf_masked(i_img *im, i_img_dim x, i_img_dim y, const i_fcolor *pix)
faa9b3e7
TC
218
219Write a pixel to a masked image.
220
221Internal function.
222
223=cut
224*/
8d14daab 225static int i_ppixf_masked(i_img *im, i_img_dim x, i_img_dim y, const i_fcolor *pix) {
faa9b3e7
TC
226 i_img_mask_ext *ext = MASKEXT(im);
227 int result;
228
229 if (x < 0 || x >= im->xsize || y < 0 || y >= im->ysize)
230 return -1;
231 if (ext->mask) {
232 i_sample_t samp;
233
234 if (i_gsamp(ext->mask, x, x+1, y, &samp, NULL, 1) && !samp)
235 return 0; /* pretend it was good */
236 }
237 result = i_ppixf(ext->targ, x + ext->xbase, y + ext->ybase, pix);
238 im->type = ext->targ->type;
239 return result;
240}
241
242/*
8d14daab 243=item i_plin_masked(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, const i_color *vals)
faa9b3e7
TC
244
245Write a row of data to a masked image.
246
247Internal function.
248
249=cut
250*/
8d14daab 251static i_img_dim i_plin_masked(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, const i_color *vals) {
faa9b3e7 252 i_img_mask_ext *ext = MASKEXT(im);
faa9b3e7
TC
253
254 if (y >= 0 && y < im->ysize && l < im->xsize && l >= 0) {
255 if (r > im->xsize)
256 r = im->xsize;
257 if (ext->mask) {
8d14daab 258 i_img_dim i;
faa9b3e7
TC
259 int simple = 0;
260 i_sample_t *samps = ext->samps;
8d14daab 261 i_img_dim w = r - l;
faa9b3e7
TC
262
263 i_gsamp(ext->mask, l, r, y, samps, NULL, 1);
264 if (w < 10)
416e9814 265 simple = 1;
faa9b3e7
TC
266 else {
267 /* the idea is to make a fast scan to see how often the state
268 changes */
8d14daab 269 i_img_dim changes = 0;
faa9b3e7
TC
270 for (i = 0; i < w-1; ++i)
271 if (!samps[i] != !samps[i+1])
272 ++changes;
273 if (changes > w/3) /* just rough */
274 simple = 1;
275 }
276 if (simple) {
277 /* we'd be calling a usually more complicated i_plin function
278 almost as often as the usually simple i_ppix(), so just
279 do a simple scan
280 */
281 for (i = 0; i < w; ++i) {
282 if (samps[i])
283 i_ppix(ext->targ, l + i + ext->xbase, y + ext->ybase, vals + i);
284 }
285 im->type = ext->targ->type;
286 return r-l;
287 }
288 else {
289 /* the scan above indicates there should be some contiguous
290 regions, look for them and render
291 */
8d14daab 292 i_img_dim start;
faa9b3e7
TC
293 i = 0;
294 while (i < w) {
295 while (i < w && !samps[i])
296 ++i;
297 start = i;
298 while (i < w && samps[i])
299 ++i;
300 if (i != start)
301 i_plin(ext->targ, l + start + ext->xbase, l + i + ext->xbase,
302 y + ext->ybase, vals + start);
303 }
304 im->type = ext->targ->type;
305 return w;
306 }
307 }
308 else {
8d14daab 309 i_img_dim result = i_plin(ext->targ, l + ext->xbase, r + ext->xbase,
faa9b3e7
TC
310 y + ext->ybase, vals);
311 im->type = ext->targ->type;
312 return result;
313 }
314 }
315 else {
316 return 0;
317 }
318}
319
320/*
8d14daab 321=item i_plinf_masked(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, const i_fcolor *vals)
faa9b3e7
TC
322
323Write a row of data to a masked image.
324
325Internal function.
326
327=cut
328*/
8d14daab 329static i_img_dim i_plinf_masked(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, const i_fcolor *vals) {
faa9b3e7
TC
330 i_img_mask_ext *ext = MASKEXT(im);
331 if (y >= 0 && y < im->ysize && l < im->xsize && l >= 0) {
332 if (r > im->xsize)
333 r = im->xsize;
334 if (ext->mask) {
8d14daab 335 i_img_dim i;
faa9b3e7
TC
336 int simple = 0;
337 i_sample_t *samps = ext->samps;
8d14daab 338 i_img_dim w = r - l;
faa9b3e7
TC
339
340 i_gsamp(ext->mask, l, r, y, samps, NULL, 1);
341 if (w < 10)
416e9814 342 simple = 1;
faa9b3e7
TC
343 else {
344 /* the idea is to make a fast scan to see how often the state
345 changes */
8d14daab 346 i_img_dim changes = 0;
faa9b3e7
TC
347 for (i = 0; i < w-1; ++i)
348 if (!samps[i] != !samps[i+1])
349 ++changes;
350 if (changes > w/3) /* just rough */
351 simple = 1;
352 }
353 if (simple) {
354 /* we'd be calling a usually more complicated i_plin function
355 almost as often as the usually simple i_ppix(), so just
356 do a simple scan
357 */
358 for (i = 0; i < w; ++i) {
359 if (samps[i])
360 i_ppixf(ext->targ, l + i + ext->xbase, y + ext->ybase, vals+i);
361 }
362 im->type = ext->targ->type;
363 return r-l;
364 }
365 else {
366 /* the scan above indicates there should be some contiguous
367 regions, look for them and render
368 */
8d14daab 369 i_img_dim start;
faa9b3e7
TC
370 i = 0;
371 while (i < w) {
372 while (i < w && !samps[i])
373 ++i;
374 start = i;
375 while (i < w && samps[i])
376 ++i;
377 if (i != start)
378 i_plinf(ext->targ, l + start + ext->xbase, l + i + ext->xbase,
379 y + ext->ybase, vals + start);
380 }
381 im->type = ext->targ->type;
382 return w;
383 }
384 }
385 else {
8d14daab 386 i_img_dim result = i_plinf(ext->targ, l + ext->xbase, r + ext->xbase,
faa9b3e7
TC
387 y + ext->ybase, vals);
388 im->type = ext->targ->type;
389 return result;
390 }
391 }
392 else {
393 return 0;
394 }
395}
396
397/*
8d14daab 398=item i_gpix_masked(i_img *im, i_img_dim x, i_img_dim y, i_color *pix)
faa9b3e7
TC
399
400Read a pixel from a masked image.
401
402Internal.
403
404=cut
405*/
8d14daab 406static int i_gpix_masked(i_img *im, i_img_dim x, i_img_dim y, i_color *pix) {
faa9b3e7
TC
407 i_img_mask_ext *ext = MASKEXT(im);
408
409 if (x < 0 || x >= im->xsize || y < 0 || y >= im->ysize)
410 return -1;
411
412 return i_gpix(ext->targ, x + ext->xbase, y + ext->ybase, pix);
413}
414
415/*
8d14daab 416=item i_gpixf_masked(i_img *im, i_img_dim x, i_img_dim y, i_fcolor *pix)
faa9b3e7
TC
417
418Read a pixel from a masked image.
419
420Internal.
421
422=cut
423*/
8d14daab 424static int i_gpixf_masked(i_img *im, i_img_dim x, i_img_dim y, i_fcolor *pix) {
faa9b3e7
TC
425 i_img_mask_ext *ext = MASKEXT(im);
426
427 if (x < 0 || x >= im->xsize || y < 0 || y >= im->ysize)
428 return -1;
429
430 return i_gpixf(ext->targ, x + ext->xbase, y + ext->ybase, pix);
431}
432
8d14daab 433static i_img_dim i_glin_masked(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, i_color *vals) {
faa9b3e7
TC
434 i_img_mask_ext *ext = MASKEXT(im);
435 if (y >= 0 && y < im->ysize && l < im->xsize && l >= 0) {
436 if (r > im->xsize)
437 r = im->xsize;
438 return i_glin(ext->targ, l + ext->xbase, r + ext->xbase,
439 y + ext->ybase, vals);
440 }
441 else {
442 return 0;
443 }
444}
445
8d14daab 446static i_img_dim i_glinf_masked(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, i_fcolor *vals) {
faa9b3e7
TC
447 i_img_mask_ext *ext = MASKEXT(im);
448 if (y >= 0 && y < im->ysize && l < im->xsize && l >= 0) {
449 if (r > im->xsize)
450 r = im->xsize;
451 return i_glinf(ext->targ, l + ext->xbase, r + ext->xbase,
452 y + ext->ybase, vals);
453 }
454 else {
455 return 0;
456 }
457}
458
8d14daab 459static i_img_dim i_gsamp_masked(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, i_sample_t *samp,
18accb2a 460 int const *chans, int chan_count) {
faa9b3e7
TC
461 i_img_mask_ext *ext = MASKEXT(im);
462 if (y >= 0 && y < im->ysize && l < im->xsize && l >= 0) {
463 if (r > im->xsize)
464 r = im->xsize;
465 return i_gsamp(ext->targ, l + ext->xbase, r + ext->xbase,
466 y + ext->ybase, samp, chans, chan_count);
467 }
468 else {
469 return 0;
470 }
471}
472
8d14daab 473static i_img_dim i_gsampf_masked(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, i_fsample_t *samp,
18accb2a 474 int const *chans, int chan_count) {
faa9b3e7
TC
475 i_img_mask_ext *ext = MASKEXT(im);
476 if (y >= 0 && y < im->ysize && l < im->xsize && l >= 0) {
477 if (r > im->xsize)
478 r = im->xsize;
479 return i_gsampf(ext->targ, l + ext->xbase, r + ext->xbase,
480 y + ext->ybase, samp, chans, chan_count);
481 }
482 else {
483 return 0;
484 }
485}
486
8d14daab 487static i_img_dim i_gpal_masked(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, i_palidx *vals) {
faa9b3e7
TC
488 i_img_mask_ext *ext = MASKEXT(im);
489 if (y >= 0 && y < im->ysize && l < im->xsize && l >= 0) {
490 if (r > im->xsize)
491 r = im->xsize;
492 return i_gpal(ext->targ, l + ext->xbase, r + ext->xbase,
493 y + ext->ybase, vals);
494 }
495 else {
496 return 0;
497 }
498}
499
8d14daab 500static i_img_dim i_ppal_masked(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, const i_palidx *vals) {
faa9b3e7
TC
501 i_img_mask_ext *ext = MASKEXT(im);
502 if (y >= 0 && y < im->ysize && l < im->xsize && l >= 0) {
503 if (r > im->xsize)
504 r = im->xsize;
505 if (ext->mask) {
8d14daab 506 i_img_dim i;
faa9b3e7 507 i_sample_t *samps = ext->samps;
8d14daab
TC
508 i_img_dim w = r - l;
509 i_img_dim start;
faa9b3e7 510
416e9814 511 i_gsamp(ext->mask, l, r, y, samps, NULL, 1);
faa9b3e7
TC
512 i = 0;
513 while (i < w) {
514 while (i < w && !samps[i])
515 ++i;
516 start = i;
517 while (i < w && samps[i])
518 ++i;
519 if (i != start)
520 i_ppal(ext->targ, l+start+ext->xbase, l+i+ext->xbase,
521 y+ext->ybase, vals+start);
522 }
523 return w;
524 }
525 else {
526 return i_ppal(ext->targ, l + ext->xbase, r + ext->xbase,
527 y + ext->ybase, vals);
528 }
529 }
530 else {
531 return 0;
532 }
533}
534
836d9f54
TC
535/*
536=item psamp_masked()
537
538i_psamp() implementation for masked images.
539
540=cut
541*/
542
543static i_img_dim
544psamp_masked(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y,
545 const i_sample_t *samples, const int *chans, int chan_count) {
546 i_img_mask_ext *ext = MASKEXT(im);
547
548 if (y >= 0 && y < im->ysize && l < im->xsize && l >= 0) {
549 unsigned old_ch_mask = ext->targ->ch_mask;
550 i_img_dim result = 0;
551 ext->targ->ch_mask = im->ch_mask;
552 if (r > im->xsize)
553 r = im->xsize;
554 if (ext->mask) {
555 i_img_dim w = r - l;
556 i_img_dim i = 0;
557 i_img_dim x = ext->xbase + l;
558 i_img_dim work_y = y + ext->ybase;
559 i_sample_t *mask_samps = ext->samps;
560
561 i_gsamp(ext->mask, l, r, y, mask_samps, NULL, 1);
562 /* not optimizing this yet */
563 while (i < w) {
564 if (mask_samps[i]) {
565 /* found a set mask value, try to do a run */
566 i_img_dim run_left = x;
567 const i_sample_t *run_samps = samples;
568 ++i;
569 ++x;
570 samples += chan_count;
571
572 while (i < w && mask_samps[i]) {
573 ++i;
574 ++x;
575 samples += chan_count;
576 }
577 result += i_psamp(ext->targ, run_left, x, work_y, run_samps, chans, chan_count);
578 }
579 else {
580 ++i;
581 ++x;
582 samples += chan_count;
583 result += chan_count; /* pretend we wrote masked off pixels */
584 }
585 }
586 }
587 else {
588 result = i_psamp(ext->targ, l + ext->xbase, r + ext->xbase,
589 y + ext->ybase, samples, chans, chan_count);
590 im->type = ext->targ->type;
591 }
592 ext->targ->ch_mask = old_ch_mask;
593 return result;
594 }
595 else {
3cb06f59 596 dIMCTXim(im);
836d9f54
TC
597 i_push_error(0, "Image position outside of image");
598 return -1;
599 }
600}
601
602/*
603=item psampf_masked()
604
605i_psampf() implementation for masked images.
606
607=cut
608*/
609
610static i_img_dim
611psampf_masked(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y,
612 const i_fsample_t *samples, const int *chans, int chan_count) {
613 i_img_mask_ext *ext = MASKEXT(im);
614
615 if (y >= 0 && y < im->ysize && l < im->xsize && l >= 0) {
616 i_img_dim result = 0;
617 unsigned old_ch_mask = ext->targ->ch_mask;
618 ext->targ->ch_mask = im->ch_mask;
619 if (r > im->xsize)
620 r = im->xsize;
621 if (ext->mask) {
622 i_img_dim w = r - l;
623 i_img_dim i = 0;
624 i_img_dim x = ext->xbase + l;
625 i_img_dim work_y = y + ext->ybase;
626 i_sample_t *mask_samps = ext->samps;
627
628 i_gsamp(ext->mask, l, r, y, mask_samps, NULL, 1);
629 /* not optimizing this yet */
630 while (i < w) {
631 if (mask_samps[i]) {
632 /* found a set mask value, try to do a run */
633 i_img_dim run_left = x;
634 const i_fsample_t *run_samps = samples;
635 ++i;
636 ++x;
637 samples += chan_count;
638
639 while (i < w && mask_samps[i]) {
640 ++i;
641 ++x;
642 samples += chan_count;
643 }
644 result += i_psampf(ext->targ, run_left, x, work_y, run_samps, chans, chan_count);
645 }
646 else {
647 ++i;
648 ++x;
649 samples += chan_count;
650 result += chan_count; /* pretend we wrote masked off pixels */
651 }
652 }
653 }
654 else {
655 result = i_psampf(ext->targ, l + ext->xbase, r + ext->xbase,
656 y + ext->ybase, samples,
657 chans, chan_count);
658 im->type = ext->targ->type;
659 }
660 ext->targ->ch_mask = old_ch_mask;
661 return result;
662 }
663 else {
3cb06f59 664 dIMCTXim(im);
836d9f54
TC
665 i_push_error(0, "Image position outside of image");
666 return -1;
667 }
668}
669
b8c2033e
AMH
670
671/*
672=back
673
674=head1 AUTHOR
675
676Tony Cook <tony@develop-help.com>
677
678=head1 SEE ALSO
679
680Imager(3)
681
682=cut
683*/