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 *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 *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);
235 if (y >= 0 && y < im->ysize && l < im->xsize && l >= 0) {
241 i_sample_t *samps = ext->samps;
244 i_gsamp(ext->mask, l, r, y, samps, NULL, 1);
248 /* the idea is to make a fast scan to see how often the state
251 for (i = 0; i < w-1; ++i)
252 if (!samps[i] != !samps[i+1])
254 if (changes > w/3) /* just rough */
258 /* we'd be calling a usually more complicated i_plin function
259 almost as often as the usually simple i_ppix(), so just
262 for (i = 0; i < w; ++i) {
264 i_ppix(ext->targ, l + i + ext->xbase, y + ext->ybase, vals + i);
266 im->type = ext->targ->type;
270 /* the scan above indicates there should be some contiguous
271 regions, look for them and render
276 while (i < w && !samps[i])
279 while (i < w && samps[i])
282 i_plin(ext->targ, l + start + ext->xbase, l + i + ext->xbase,
283 y + ext->ybase, vals + start);
285 im->type = ext->targ->type;
290 int result = i_plin(ext->targ, l + ext->xbase, r + ext->xbase,
291 y + ext->ybase, vals);
292 im->type = ext->targ->type;
302 =item i_plinf_masked(i_img *im, int l, int r, int y, i_fcolor *vals)
304 Write a row of data to a masked image.
310 static int i_plinf_masked(i_img *im, int l, int r, int y, i_fcolor *vals) {
311 i_img_mask_ext *ext = MASKEXT(im);
312 if (y >= 0 && y < im->ysize && l < im->xsize && l >= 0) {
318 i_sample_t *samps = ext->samps;
321 i_gsamp(ext->mask, l, r, y, samps, NULL, 1);
325 /* the idea is to make a fast scan to see how often the state
328 for (i = 0; i < w-1; ++i)
329 if (!samps[i] != !samps[i+1])
331 if (changes > w/3) /* just rough */
335 /* we'd be calling a usually more complicated i_plin function
336 almost as often as the usually simple i_ppix(), so just
339 for (i = 0; i < w; ++i) {
341 i_ppixf(ext->targ, l + i + ext->xbase, y + ext->ybase, vals+i);
343 im->type = ext->targ->type;
347 /* the scan above indicates there should be some contiguous
348 regions, look for them and render
353 while (i < w && !samps[i])
356 while (i < w && samps[i])
359 i_plinf(ext->targ, l + start + ext->xbase, l + i + ext->xbase,
360 y + ext->ybase, vals + start);
362 im->type = ext->targ->type;
367 int result = i_plinf(ext->targ, l + ext->xbase, r + ext->xbase,
368 y + ext->ybase, vals);
369 im->type = ext->targ->type;
379 =item i_gpix_masked(i_img *im, int x, int y, i_color *pix)
381 Read a pixel from a masked image.
387 static int i_gpix_masked(i_img *im, int x, int y, i_color *pix) {
388 i_img_mask_ext *ext = MASKEXT(im);
390 if (x < 0 || x >= im->xsize || y < 0 || y >= im->ysize)
393 return i_gpix(ext->targ, x + ext->xbase, y + ext->ybase, pix);
397 =item i_gpixf_masked(i_img *im, int x, int y, i_fcolor *pix)
399 Read a pixel from a masked image.
405 static int i_gpixf_masked(i_img *im, int x, int y, i_fcolor *pix) {
406 i_img_mask_ext *ext = MASKEXT(im);
408 if (x < 0 || x >= im->xsize || y < 0 || y >= im->ysize)
411 return i_gpixf(ext->targ, x + ext->xbase, y + ext->ybase, pix);
414 static int i_glin_masked(i_img *im, int l, int r, int y, i_color *vals) {
415 i_img_mask_ext *ext = MASKEXT(im);
416 if (y >= 0 && y < im->ysize && l < im->xsize && l >= 0) {
419 return i_glin(ext->targ, l + ext->xbase, r + ext->xbase,
420 y + ext->ybase, vals);
427 static int i_glinf_masked(i_img *im, int l, int r, int y, i_fcolor *vals) {
428 i_img_mask_ext *ext = MASKEXT(im);
429 if (y >= 0 && y < im->ysize && l < im->xsize && l >= 0) {
432 return i_glinf(ext->targ, l + ext->xbase, r + ext->xbase,
433 y + ext->ybase, vals);
440 static int i_gsamp_masked(i_img *im, int l, int r, int y, i_sample_t *samp,
441 int *chans, int chan_count) {
442 i_img_mask_ext *ext = MASKEXT(im);
443 if (y >= 0 && y < im->ysize && l < im->xsize && l >= 0) {
446 return i_gsamp(ext->targ, l + ext->xbase, r + ext->xbase,
447 y + ext->ybase, samp, chans, chan_count);
454 static int i_gsampf_masked(i_img *im, int l, int r, int y, i_fsample_t *samp,
455 int *chans, int chan_count) {
456 i_img_mask_ext *ext = MASKEXT(im);
457 if (y >= 0 && y < im->ysize && l < im->xsize && l >= 0) {
460 return i_gsampf(ext->targ, l + ext->xbase, r + ext->xbase,
461 y + ext->ybase, samp, chans, chan_count);
468 static int i_gpal_masked(i_img *im, int l, int r, int y, i_palidx *vals) {
469 i_img_mask_ext *ext = MASKEXT(im);
470 if (y >= 0 && y < im->ysize && l < im->xsize && l >= 0) {
473 return i_gpal(ext->targ, l + ext->xbase, r + ext->xbase,
474 y + ext->ybase, vals);
481 static int i_ppal_masked(i_img *im, int l, int r, int y, i_palidx *vals) {
482 i_img_mask_ext *ext = MASKEXT(im);
483 if (y >= 0 && y < im->ysize && l < im->xsize && l >= 0) {
488 i_sample_t *samps = ext->samps;
494 while (i < w && !samps[i])
497 while (i < w && samps[i])
500 i_ppal(ext->targ, l+start+ext->xbase, l+i+ext->xbase,
501 y+ext->ybase, vals+start);
506 return i_ppal(ext->targ, l + ext->xbase, r + ext->xbase,
507 y + ext->ybase, vals);
521 Tony Cook <tony@develop-help.com>