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
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, int x, int y, i_color *pix);
38 static int i_ppixf_masked(i_img *im, int x, int y, i_fcolor *pix);
39 static int i_plin_masked(i_img *im, int l, int r, int y, i_color *vals);
40 static int i_plinf_masked(i_img *im, int l, int r, int y, i_fcolor *vals);
41 static int i_gpix_masked(i_img *im, int x, int y, i_color *pix);
42 static int i_gpixf_masked(i_img *im, int x, int y, i_fcolor *pix);
43 static int i_glin_masked(i_img *im, int l, int r, int y, i_color *vals);
44 static int i_glinf_masked(i_img *im, int l, int r, int y, i_fcolor *vals);
45 static int i_gsamp_masked(i_img *im, int l, int r, int y, i_sample_t *samp,
46 int const *chans, int chan_count);
47 static int i_gsampf_masked(i_img *im, int l, int r, int y, i_fsample_t *samp,
48 int const *chans, int chan_count);
49 static int i_gpal_masked(i_img *im, int l, int r, int y, i_palidx *vals);
50 static int i_ppal_masked(i_img *im, int l, int r, int y, i_palidx *vals);
55 The basic data we copy into a masked image.
59 static i_img IIM_base_masked =
62 0, 0, 0, /* xsize, ysize, bytes */
65 i_palette_type, /* type */
68 { 0, 0, NULL }, /* tags */
71 i_ppix_masked, /* i_f_ppix */
72 i_ppixf_masked, /* i_f_ppixf */
73 i_plin_masked, /* i_f_plin */
74 i_plinf_masked, /* i_f_plinf */
75 i_gpix_masked, /* i_f_gpix */
76 i_gpixf_masked, /* i_f_gpixf */
77 i_glin_masked, /* i_f_glin */
78 i_glinf_masked, /* i_f_glinf */
79 i_gsamp_masked, /* i_f_gsamp */
80 i_gsampf_masked, /* i_f_gsampf */
82 i_gpal_masked, /* i_f_gpal */
83 i_ppal_masked, /* i_f_ppal */
84 i_addcolors_forward, /* i_f_addcolors */
85 i_getcolors_forward, /* i_f_getcolors */
86 i_colorcount_forward, /* i_f_colorcount */
87 i_maxcolors_forward, /* i_f_maxcolors */
88 i_findcolor_forward, /* i_f_findcolor */
89 i_setcolors_forward, /* i_f_setcolors */
91 i_destroy_masked, /* i_f_destroy */
95 =item i_img_masked_new(i_img *targ, i_img *mask, int xbase, int ybase, int w, int h)
97 Create a new masked image.
99 The image mask is optional, in which case the image is just a view of
100 a rectangular portion of the image.
102 The mask only has an effect of writing to the image, the entire view
103 of the underlying image is readable.
105 pixel access to mimg(x,y) is translated to targ(x+xbase, y+ybase), as long
106 as (0 <= x < w) and (0 <= y < h).
108 For a pixel to be writable, the pixel mask(x,y) must have non-zero in
109 it's first channel. No scaling of the pixel is done, the channel
110 sample is treated as boolean.
115 i_img *i_img_masked_new(i_img *targ, i_img *mask, int x, int y, int w, int h) {
120 if (x >= targ->xsize || y >= targ->ysize) {
121 i_push_error(0, "subset outside of target image");
130 if (x+w > targ->xsize)
132 if (y+h > targ->ysize)
135 im = mymalloc(sizeof(i_img));
136 memcpy(im, &IIM_base_masked, sizeof(i_img));
139 im->channels = targ->channels;
140 im->bits = targ->bits;
141 im->type = targ->type;
142 ext = mymalloc(sizeof(*ext));
147 ext->samps = mymalloc(sizeof(i_sample_t) * im->xsize);
154 =item i_destroy_masked(i_img *im)
156 The destruction handler for masked images.
158 Releases the ext_data.
165 static void i_destroy_masked(i_img *im) {
166 myfree(MASKEXT(im)->samps);
167 myfree(im->ext_data);
171 =item i_ppix_masked(i_img *im, int x, int y, i_color *pix)
173 Write a pixel to a masked image.
179 static int i_ppix_masked(i_img *im, int x, int y, i_color *pix) {
180 i_img_mask_ext *ext = MASKEXT(im);
183 if (x < 0 || x >= im->xsize || y < 0 || y >= im->ysize)
188 if (i_gsamp(ext->mask, x, x+1, y, &samp, NULL, 1) && !samp)
189 return 0; /* pretend it was good */
191 result = i_ppix(ext->targ, x + ext->xbase, y + ext->ybase, pix);
192 im->type = ext->targ->type;
197 =item i_ppixf_masked(i_img *im, int x, int y, i_fcolor *pix)
199 Write a pixel to a masked image.
205 static int i_ppixf_masked(i_img *im, int x, int y, i_fcolor *pix) {
206 i_img_mask_ext *ext = MASKEXT(im);
209 if (x < 0 || x >= im->xsize || y < 0 || y >= im->ysize)
214 if (i_gsamp(ext->mask, x, x+1, y, &samp, NULL, 1) && !samp)
215 return 0; /* pretend it was good */
217 result = i_ppixf(ext->targ, x + ext->xbase, y + ext->ybase, pix);
218 im->type = ext->targ->type;
223 =item i_plin_masked(i_img *im, int l, int r, int y, i_color *vals)
225 Write a row of data to a masked image.
231 static int i_plin_masked(i_img *im, int l, int r, int y, i_color *vals) {
232 i_img_mask_ext *ext = MASKEXT(im);
234 if (y >= 0 && y < im->ysize && l < im->xsize && l >= 0) {
240 i_sample_t *samps = ext->samps;
243 i_gsamp(ext->mask, l, r, y, samps, NULL, 1);
247 /* the idea is to make a fast scan to see how often the state
250 for (i = 0; i < w-1; ++i)
251 if (!samps[i] != !samps[i+1])
253 if (changes > w/3) /* just rough */
257 /* we'd be calling a usually more complicated i_plin function
258 almost as often as the usually simple i_ppix(), so just
261 for (i = 0; i < w; ++i) {
263 i_ppix(ext->targ, l + i + ext->xbase, y + ext->ybase, vals + i);
265 im->type = ext->targ->type;
269 /* the scan above indicates there should be some contiguous
270 regions, look for them and render
275 while (i < w && !samps[i])
278 while (i < w && samps[i])
281 i_plin(ext->targ, l + start + ext->xbase, l + i + ext->xbase,
282 y + ext->ybase, vals + start);
284 im->type = ext->targ->type;
289 int result = i_plin(ext->targ, l + ext->xbase, r + ext->xbase,
290 y + ext->ybase, vals);
291 im->type = ext->targ->type;
301 =item i_plinf_masked(i_img *im, int l, int r, int y, i_fcolor *vals)
303 Write a row of data to a masked image.
309 static int i_plinf_masked(i_img *im, int l, int r, int y, i_fcolor *vals) {
310 i_img_mask_ext *ext = MASKEXT(im);
311 if (y >= 0 && y < im->ysize && l < im->xsize && l >= 0) {
317 i_sample_t *samps = ext->samps;
320 i_gsamp(ext->mask, l, r, y, samps, NULL, 1);
324 /* the idea is to make a fast scan to see how often the state
327 for (i = 0; i < w-1; ++i)
328 if (!samps[i] != !samps[i+1])
330 if (changes > w/3) /* just rough */
334 /* we'd be calling a usually more complicated i_plin function
335 almost as often as the usually simple i_ppix(), so just
338 for (i = 0; i < w; ++i) {
340 i_ppixf(ext->targ, l + i + ext->xbase, y + ext->ybase, vals+i);
342 im->type = ext->targ->type;
346 /* the scan above indicates there should be some contiguous
347 regions, look for them and render
352 while (i < w && !samps[i])
355 while (i < w && samps[i])
358 i_plinf(ext->targ, l + start + ext->xbase, l + i + ext->xbase,
359 y + ext->ybase, vals + start);
361 im->type = ext->targ->type;
366 int result = i_plinf(ext->targ, l + ext->xbase, r + ext->xbase,
367 y + ext->ybase, vals);
368 im->type = ext->targ->type;
378 =item i_gpix_masked(i_img *im, int x, int y, i_color *pix)
380 Read a pixel from a masked image.
386 static int i_gpix_masked(i_img *im, int x, int y, i_color *pix) {
387 i_img_mask_ext *ext = MASKEXT(im);
389 if (x < 0 || x >= im->xsize || y < 0 || y >= im->ysize)
392 return i_gpix(ext->targ, x + ext->xbase, y + ext->ybase, pix);
396 =item i_gpixf_masked(i_img *im, int x, int y, i_fcolor *pix)
398 Read a pixel from a masked image.
404 static int i_gpixf_masked(i_img *im, int x, int y, i_fcolor *pix) {
405 i_img_mask_ext *ext = MASKEXT(im);
407 if (x < 0 || x >= im->xsize || y < 0 || y >= im->ysize)
410 return i_gpixf(ext->targ, x + ext->xbase, y + ext->ybase, pix);
413 static int i_glin_masked(i_img *im, int l, int r, int y, i_color *vals) {
414 i_img_mask_ext *ext = MASKEXT(im);
415 if (y >= 0 && y < im->ysize && l < im->xsize && l >= 0) {
418 return i_glin(ext->targ, l + ext->xbase, r + ext->xbase,
419 y + ext->ybase, vals);
426 static int i_glinf_masked(i_img *im, int l, int r, int y, i_fcolor *vals) {
427 i_img_mask_ext *ext = MASKEXT(im);
428 if (y >= 0 && y < im->ysize && l < im->xsize && l >= 0) {
431 return i_glinf(ext->targ, l + ext->xbase, r + ext->xbase,
432 y + ext->ybase, vals);
439 static int i_gsamp_masked(i_img *im, int l, int r, int y, i_sample_t *samp,
440 int const *chans, int chan_count) {
441 i_img_mask_ext *ext = MASKEXT(im);
442 if (y >= 0 && y < im->ysize && l < im->xsize && l >= 0) {
445 return i_gsamp(ext->targ, l + ext->xbase, r + ext->xbase,
446 y + ext->ybase, samp, chans, chan_count);
453 static int i_gsampf_masked(i_img *im, int l, int r, int y, i_fsample_t *samp,
454 int const *chans, int chan_count) {
455 i_img_mask_ext *ext = MASKEXT(im);
456 if (y >= 0 && y < im->ysize && l < im->xsize && l >= 0) {
459 return i_gsampf(ext->targ, l + ext->xbase, r + ext->xbase,
460 y + ext->ybase, samp, chans, chan_count);
467 static int i_gpal_masked(i_img *im, int l, int r, int y, i_palidx *vals) {
468 i_img_mask_ext *ext = MASKEXT(im);
469 if (y >= 0 && y < im->ysize && l < im->xsize && l >= 0) {
472 return i_gpal(ext->targ, l + ext->xbase, r + ext->xbase,
473 y + ext->ybase, vals);
480 static int i_ppal_masked(i_img *im, int l, int r, int y, i_palidx *vals) {
481 i_img_mask_ext *ext = MASKEXT(im);
482 if (y >= 0 && y < im->ysize && l < im->xsize && l >= 0) {
487 i_sample_t *samps = ext->samps;
493 while (i < w && !samps[i])
496 while (i < w && samps[i])
499 i_ppal(ext->targ, l+start+ext->xbase, l+i+ext->xbase,
500 y+ext->ybase, vals+start);
505 return i_ppal(ext->targ, l + ext->xbase, r + ext->xbase,
506 y + ext->ybase, vals);
520 Tony Cook <tony@develop-help.com>