4 maskimg.c - implements masked images/image subsets
21 A pointer to this type of object is kept in the ext_data of a masked
30 i_img_dim xbase, ybase;
31 i_sample_t *samps; /* temp space */
34 #define MASKEXT(im) ((i_img_mask_ext *)((im)->ext_data))
36 static void i_destroy_masked(i_img *im);
37 static int i_ppix_masked(i_img *im, i_img_dim x, i_img_dim y, const i_color *pix);
38 static int i_ppixf_masked(i_img *im, i_img_dim x, i_img_dim y, const i_fcolor *pix);
39 static 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);
40 static 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);
41 static int i_gpix_masked(i_img *im, i_img_dim x, i_img_dim y, i_color *pix);
42 static int i_gpixf_masked(i_img *im, i_img_dim x, i_img_dim y, i_fcolor *pix);
43 static i_img_dim i_glin_masked(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, i_color *vals);
44 static i_img_dim i_glinf_masked(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, i_fcolor *vals);
45 static 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,
46 int const *chans, int chan_count);
47 static 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,
48 int const *chans, int chan_count);
49 static i_img_dim i_gpal_masked(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, i_palidx *vals);
50 static 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);
52 psamp_masked(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y,
53 const i_sample_t *samples, const int *chans, int chan_count);
55 psampf_masked(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y,
56 const i_fsample_t *samples, const int *chans, int chan_count);
61 The basic data we copy into a masked image.
65 static i_img IIM_base_masked =
68 0, 0, 0, /* xsize, ysize, bytes */
71 i_palette_type, /* type */
74 { 0, 0, NULL }, /* tags */
77 i_ppix_masked, /* i_f_ppix */
78 i_ppixf_masked, /* i_f_ppixf */
79 i_plin_masked, /* i_f_plin */
80 i_plinf_masked, /* i_f_plinf */
81 i_gpix_masked, /* i_f_gpix */
82 i_gpixf_masked, /* i_f_gpixf */
83 i_glin_masked, /* i_f_glin */
84 i_glinf_masked, /* i_f_glinf */
85 i_gsamp_masked, /* i_f_gsamp */
86 i_gsampf_masked, /* i_f_gsampf */
88 i_gpal_masked, /* i_f_gpal */
89 i_ppal_masked, /* i_f_ppal */
90 i_addcolors_forward, /* i_f_addcolors */
91 i_getcolors_forward, /* i_f_getcolors */
92 i_colorcount_forward, /* i_f_colorcount */
93 i_maxcolors_forward, /* i_f_maxcolors */
94 i_findcolor_forward, /* i_f_findcolor */
95 i_setcolors_forward, /* i_f_setcolors */
97 i_destroy_masked, /* i_f_destroy */
99 NULL, /* i_f_gsamp_bits */
100 NULL, /* i_f_psamp_bits */
102 psamp_masked, /* i_f_psamp */
103 psampf_masked /* i_f_psampf */
107 =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)
109 Create a new masked image.
111 The image mask is optional, in which case the image is just a view of
112 a rectangular portion of the image.
114 The mask only has an effect of writing to the image, the entire view
115 of the underlying image is readable.
117 pixel access to mimg(x,y) is translated to targ(x+xbase, y+ybase), as long
118 as (0 <= x < w) and (0 <= y < h).
120 For a pixel to be writable, the pixel mask(x,y) must have non-zero in
121 it's first channel. No scaling of the pixel is done, the channel
122 sample is treated as boolean.
127 i_img *i_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) {
132 if (x >= targ->xsize || y >= targ->ysize) {
133 i_push_error(0, "subset outside of target image");
142 if (x+w > targ->xsize)
144 if (y+h > targ->ysize)
147 im = mymalloc(sizeof(i_img));
148 memcpy(im, &IIM_base_masked, sizeof(i_img));
151 im->channels = targ->channels;
152 im->bits = targ->bits;
153 im->type = targ->type;
154 ext = mymalloc(sizeof(*ext));
159 ext->samps = mymalloc(sizeof(i_sample_t) * im->xsize);
166 =item i_destroy_masked(i_img *im)
168 The destruction handler for masked images.
170 Releases the ext_data.
177 static void i_destroy_masked(i_img *im) {
178 myfree(MASKEXT(im)->samps);
179 myfree(im->ext_data);
183 =item i_ppix_masked(i_img *im, i_img_dim x, i_img_dim y, const i_color *pix)
185 Write a pixel to a masked image.
191 static int i_ppix_masked(i_img *im, i_img_dim x, i_img_dim y, const i_color *pix) {
192 i_img_mask_ext *ext = MASKEXT(im);
195 if (x < 0 || x >= im->xsize || y < 0 || y >= im->ysize)
200 if (i_gsamp(ext->mask, x, x+1, y, &samp, NULL, 1) && !samp)
201 return 0; /* pretend it was good */
203 result = i_ppix(ext->targ, x + ext->xbase, y + ext->ybase, pix);
204 im->type = ext->targ->type;
209 =item i_ppixf_masked(i_img *im, i_img_dim x, i_img_dim y, const i_fcolor *pix)
211 Write a pixel to a masked image.
217 static int i_ppixf_masked(i_img *im, i_img_dim x, i_img_dim y, const i_fcolor *pix) {
218 i_img_mask_ext *ext = MASKEXT(im);
221 if (x < 0 || x >= im->xsize || y < 0 || y >= im->ysize)
226 if (i_gsamp(ext->mask, x, x+1, y, &samp, NULL, 1) && !samp)
227 return 0; /* pretend it was good */
229 result = i_ppixf(ext->targ, x + ext->xbase, y + ext->ybase, pix);
230 im->type = ext->targ->type;
235 =item i_plin_masked(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, const i_color *vals)
237 Write a row of data to a masked image.
243 static 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) {
244 i_img_mask_ext *ext = MASKEXT(im);
246 if (y >= 0 && y < im->ysize && l < im->xsize && l >= 0) {
252 i_sample_t *samps = ext->samps;
255 i_gsamp(ext->mask, l, r, y, samps, NULL, 1);
259 /* the idea is to make a fast scan to see how often the state
261 i_img_dim changes = 0;
262 for (i = 0; i < w-1; ++i)
263 if (!samps[i] != !samps[i+1])
265 if (changes > w/3) /* just rough */
269 /* we'd be calling a usually more complicated i_plin function
270 almost as often as the usually simple i_ppix(), so just
273 for (i = 0; i < w; ++i) {
275 i_ppix(ext->targ, l + i + ext->xbase, y + ext->ybase, vals + i);
277 im->type = ext->targ->type;
281 /* the scan above indicates there should be some contiguous
282 regions, look for them and render
287 while (i < w && !samps[i])
290 while (i < w && samps[i])
293 i_plin(ext->targ, l + start + ext->xbase, l + i + ext->xbase,
294 y + ext->ybase, vals + start);
296 im->type = ext->targ->type;
301 i_img_dim result = i_plin(ext->targ, l + ext->xbase, r + ext->xbase,
302 y + ext->ybase, vals);
303 im->type = ext->targ->type;
313 =item i_plinf_masked(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, const i_fcolor *vals)
315 Write a row of data to a masked image.
321 static 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) {
322 i_img_mask_ext *ext = MASKEXT(im);
323 if (y >= 0 && y < im->ysize && l < im->xsize && l >= 0) {
329 i_sample_t *samps = ext->samps;
332 i_gsamp(ext->mask, l, r, y, samps, NULL, 1);
336 /* the idea is to make a fast scan to see how often the state
338 i_img_dim changes = 0;
339 for (i = 0; i < w-1; ++i)
340 if (!samps[i] != !samps[i+1])
342 if (changes > w/3) /* just rough */
346 /* we'd be calling a usually more complicated i_plin function
347 almost as often as the usually simple i_ppix(), so just
350 for (i = 0; i < w; ++i) {
352 i_ppixf(ext->targ, l + i + ext->xbase, y + ext->ybase, vals+i);
354 im->type = ext->targ->type;
358 /* the scan above indicates there should be some contiguous
359 regions, look for them and render
364 while (i < w && !samps[i])
367 while (i < w && samps[i])
370 i_plinf(ext->targ, l + start + ext->xbase, l + i + ext->xbase,
371 y + ext->ybase, vals + start);
373 im->type = ext->targ->type;
378 i_img_dim result = i_plinf(ext->targ, l + ext->xbase, r + ext->xbase,
379 y + ext->ybase, vals);
380 im->type = ext->targ->type;
390 =item i_gpix_masked(i_img *im, i_img_dim x, i_img_dim y, i_color *pix)
392 Read a pixel from a masked image.
398 static int i_gpix_masked(i_img *im, i_img_dim x, i_img_dim y, i_color *pix) {
399 i_img_mask_ext *ext = MASKEXT(im);
401 if (x < 0 || x >= im->xsize || y < 0 || y >= im->ysize)
404 return i_gpix(ext->targ, x + ext->xbase, y + ext->ybase, pix);
408 =item i_gpixf_masked(i_img *im, i_img_dim x, i_img_dim y, i_fcolor *pix)
410 Read a pixel from a masked image.
416 static int i_gpixf_masked(i_img *im, i_img_dim x, i_img_dim y, i_fcolor *pix) {
417 i_img_mask_ext *ext = MASKEXT(im);
419 if (x < 0 || x >= im->xsize || y < 0 || y >= im->ysize)
422 return i_gpixf(ext->targ, x + ext->xbase, y + ext->ybase, pix);
425 static i_img_dim i_glin_masked(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, i_color *vals) {
426 i_img_mask_ext *ext = MASKEXT(im);
427 if (y >= 0 && y < im->ysize && l < im->xsize && l >= 0) {
430 return i_glin(ext->targ, l + ext->xbase, r + ext->xbase,
431 y + ext->ybase, vals);
438 static i_img_dim i_glinf_masked(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, i_fcolor *vals) {
439 i_img_mask_ext *ext = MASKEXT(im);
440 if (y >= 0 && y < im->ysize && l < im->xsize && l >= 0) {
443 return i_glinf(ext->targ, l + ext->xbase, r + ext->xbase,
444 y + ext->ybase, vals);
451 static 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,
452 int const *chans, int chan_count) {
453 i_img_mask_ext *ext = MASKEXT(im);
454 if (y >= 0 && y < im->ysize && l < im->xsize && l >= 0) {
457 return i_gsamp(ext->targ, l + ext->xbase, r + ext->xbase,
458 y + ext->ybase, samp, chans, chan_count);
465 static 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,
466 int const *chans, int chan_count) {
467 i_img_mask_ext *ext = MASKEXT(im);
468 if (y >= 0 && y < im->ysize && l < im->xsize && l >= 0) {
471 return i_gsampf(ext->targ, l + ext->xbase, r + ext->xbase,
472 y + ext->ybase, samp, chans, chan_count);
479 static i_img_dim i_gpal_masked(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, i_palidx *vals) {
480 i_img_mask_ext *ext = MASKEXT(im);
481 if (y >= 0 && y < im->ysize && l < im->xsize && l >= 0) {
484 return i_gpal(ext->targ, l + ext->xbase, r + ext->xbase,
485 y + ext->ybase, vals);
492 static 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) {
493 i_img_mask_ext *ext = MASKEXT(im);
494 if (y >= 0 && y < im->ysize && l < im->xsize && l >= 0) {
499 i_sample_t *samps = ext->samps;
503 i_gsamp(ext->mask, l, r, y, samps, NULL, 1);
506 while (i < w && !samps[i])
509 while (i < w && samps[i])
512 i_ppal(ext->targ, l+start+ext->xbase, l+i+ext->xbase,
513 y+ext->ybase, vals+start);
518 return i_ppal(ext->targ, l + ext->xbase, r + ext->xbase,
519 y + ext->ybase, vals);
530 i_psamp() implementation for masked images.
536 psamp_masked(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y,
537 const i_sample_t *samples, const int *chans, int chan_count) {
538 i_img_mask_ext *ext = MASKEXT(im);
540 if (y >= 0 && y < im->ysize && l < im->xsize && l >= 0) {
541 unsigned old_ch_mask = ext->targ->ch_mask;
542 i_img_dim result = 0;
543 ext->targ->ch_mask = im->ch_mask;
549 i_img_dim x = ext->xbase + l;
550 i_img_dim work_y = y + ext->ybase;
551 i_sample_t *mask_samps = ext->samps;
553 i_gsamp(ext->mask, l, r, y, mask_samps, NULL, 1);
554 /* not optimizing this yet */
557 /* found a set mask value, try to do a run */
558 i_img_dim run_left = x;
559 const i_sample_t *run_samps = samples;
562 samples += chan_count;
564 while (i < w && mask_samps[i]) {
567 samples += chan_count;
569 result += i_psamp(ext->targ, run_left, x, work_y, run_samps, chans, chan_count);
574 samples += chan_count;
575 result += chan_count; /* pretend we wrote masked off pixels */
580 result = i_psamp(ext->targ, l + ext->xbase, r + ext->xbase,
581 y + ext->ybase, samples, chans, chan_count);
582 im->type = ext->targ->type;
584 ext->targ->ch_mask = old_ch_mask;
588 i_push_error(0, "Image position outside of image");
594 =item psampf_masked()
596 i_psampf() implementation for masked images.
602 psampf_masked(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y,
603 const i_fsample_t *samples, const int *chans, int chan_count) {
604 i_img_mask_ext *ext = MASKEXT(im);
606 if (y >= 0 && y < im->ysize && l < im->xsize && l >= 0) {
607 i_img_dim result = 0;
608 unsigned old_ch_mask = ext->targ->ch_mask;
609 ext->targ->ch_mask = im->ch_mask;
615 i_img_dim x = ext->xbase + l;
616 i_img_dim work_y = y + ext->ybase;
617 i_sample_t *mask_samps = ext->samps;
619 i_gsamp(ext->mask, l, r, y, mask_samps, NULL, 1);
620 /* not optimizing this yet */
623 /* found a set mask value, try to do a run */
624 i_img_dim run_left = x;
625 const i_fsample_t *run_samps = samples;
628 samples += chan_count;
630 while (i < w && mask_samps[i]) {
633 samples += chan_count;
635 result += i_psampf(ext->targ, run_left, x, work_y, run_samps, chans, chan_count);
640 samples += chan_count;
641 result += chan_count; /* pretend we wrote masked off pixels */
646 result = i_psampf(ext->targ, l + ext->xbase, r + ext->xbase,
647 y + ext->ybase, samples,
649 im->type = ext->targ->type;
651 ext->targ->ch_mask = old_ch_mask;
655 i_push_error(0, "Image position outside of image");
666 Tony Cook <tony@develop-help.com>