CRIMP
Check-in [9989984bc5]
Not logged in

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Modified the 'alpha blend' operator to behave like the other binary operators in general. Updated and added demos.
Timelines: family | ancestors | descendants | both | infinite-plane
Files: files | file ages | folders
SHA1: 9989984bc5d4bdc0e98e60bf70cab54868e86b12
User & Date: andreask 2011-11-25 05:32:49.050
Context
2011-12-07
18:12
Pulled the PCX reader into this branch. Updated to insert the PCX location information into the generated image. check-in: b3a44f2371 user: andreask tags: infinite-plane
2011-11-25
05:32
Modified the 'alpha blend' operator to behave like the other binary operators in general. Updated and added demos. check-in: 9989984bc5 user: andreask tags: infinite-plane
05:14
Fix argument bug in one of the new macros. check-in: d2b58900a2 user: andreask tags: infinite-plane
Changes
Unified Diff Ignore Whitespace Patch
Changes to demos/blend_hsv.tcl.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
def op_alpha_blend_hsv {
    label {Blend HSV}
    active {
	expr {
	      ([bases] == 2) &&
	      ([crimp dimensions [base 0]] eq [crimp dimensions [base 1]])
	  }
    }
    setup {
	# We manage a cache of the blended images to make the
	# scrolling of the scale smoother over time. An improvement
	# would be to use timer events to precompute the various
	# blends.
	variable  cache
	array set cache {}


|
<
<
<
<
<







1
2
3





4
5
6
7
8
9
10
def op_alpha_blend_hsv {
    label {Blend HSV}
    active { expr { [bases] == 2 } }





    setup {
	# We manage a cache of the blended images to make the
	# scrolling of the scale smoother over time. An improvement
	# would be to use timer events to precompute the various
	# blends.
	variable  cache
	array set cache {}
Added demos/blend_hsv_translated.tcl.












































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
def op_alpha_blend_hsv_translated {
    label {Blend HSV/Translated}
    active { expr { [bases] == 2 } }
    setup {
	# We manage a cache of the blended images to make the
	# scrolling of the scale smoother over time. An improvement
	# would be to use timer events to precompute the various
	# blends.
	variable  cache
	array set cache {}
	set cache(255) [crimp place [base 0]  50  40]
	set cache(0)   [crimp place [base 1] -40 -50]
	variable fore  [crimp place [crimp convert 2hsv [base 0]]  50  40]
	variable back  [crimp place [crimp convert 2hsv [base 1]] -40 -50]
	variable alpha 255

	scale .left.s -variable DEMO::alpha \
	    -from 0 -to 255 \
	    -orient vertical \
	    -command [list ::apply {{thealpha} {
		variable cache
		variable fore
		variable back

		if {[info exists cache($thealpha)]} {
		    show_image  $cache($thealpha)
		    return
		}

		set theblend [crimp convert 2rgb [crimp alpha blend $fore $back $thealpha]]
		set cache($thealpha) $theblend
		show_image $theblend
		return
	    } ::DEMO}]

	pack .left.s -side left -fill both -expand 1
    }
}
Changes to demos/blend_rgb.tcl.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17


18
19
20
21
22
23
24


25
26
27
28
29
30
31
32
33
34
35
36
37
38
def op_alpha_blend_rgb {
    label {Blend RGB}
    active {
	expr {
	      ([bases] == 2) &&
	      ([crimp dimensions [base 0]] eq [crimp dimensions [base 1]])
	  }
    }
    setup {
	# We manage a cache of the blended images to make the
	# scrolling of the scale smoother over time. An improvement
	# would be to use timer events to precompute the various
	# blends.
	variable  cache
	array set cache {}
	set cache(255) [base 0]
	set cache(0)   [base 1]


	variable alpha 255

	scale .left.s -variable DEMO::alpha \
	    -from 0 -to 255 \
	    -orient vertical \
	    -command [list ::apply {{thealpha} {
		variable cache



		if {[info exists cache($thealpha)]} {
		    show_image  $cache($thealpha)
		    return
		}

		set theblend [crimp alpha blend [base 0] [base 1] $thealpha]
		set cache($thealpha) $theblend
		show_image $theblend
		return
	    } ::DEMO}]

	pack .left.s -side left -fill both -expand 1
    }


|
<
<
<
<
<









>
>







>
>






|







1
2
3





4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
def op_alpha_blend_rgb {
    label {Blend RGB}
    active { expr { [bases] == 2 } }





    setup {
	# We manage a cache of the blended images to make the
	# scrolling of the scale smoother over time. An improvement
	# would be to use timer events to precompute the various
	# blends.
	variable  cache
	array set cache {}
	set cache(255) [base 0]
	set cache(0)   [base 1]
	variable fore  $cache(255)
	variable back  $cache(0)
	variable alpha 255

	scale .left.s -variable DEMO::alpha \
	    -from 0 -to 255 \
	    -orient vertical \
	    -command [list ::apply {{thealpha} {
		variable cache
		variable fore
		variable back

		if {[info exists cache($thealpha)]} {
		    show_image  $cache($thealpha)
		    return
		}

		set theblend [crimp alpha blend $fore $back $thealpha]
		set cache($thealpha) $theblend
		show_image $theblend
		return
	    } ::DEMO}]

	pack .left.s -side left -fill both -expand 1
    }
Added demos/blend_rgb_translated.tcl.












































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
def op_alpha_blend_rgb_translated {
    label {Blend RGB/Translated}
    active { expr { [bases] == 2 } }
    setup {
	# We manage a cache of the blended images to make the
	# scrolling of the scale smoother over time. An improvement
	# would be to use timer events to precompute the various
	# blends.
	variable  cache
	array set cache {}
	set cache(255) [crimp place [base 0]  50  40]
	set cache(0)   [crimp place [base 1] -40 -50]
	variable fore  $cache(255)
	variable back  $cache(0)
	variable alpha 255

	scale .left.s -variable DEMO::alpha \
	    -from 0 -to 255 \
	    -orient vertical \
	    -command [list ::apply {{thealpha} {
		variable cache
		variable fore
		variable back

		if {[info exists cache($thealpha)]} {
		    show_image  $cache($thealpha)
		    return
		}

		set theblend [crimp alpha blend $fore $back $thealpha]
		set cache($thealpha) $theblend
		show_image $theblend
		return
	    } ::DEMO}]

	pack .left.s -side left -fill both -expand 1
    }
}
Added operator/alpha-blend-float-float.crimp.




























































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
alpha_blend_float_float
Tcl_Obj* imageForeObj
Tcl_Obj* imageBackObj
float alpha

/*
 * Alpha-based blending of two images, foreground, and background, controlled
 * by a scalar (and extern) alpha factor.
 *
 * alpha is Opacity
 * 255 <=> Fully opaque      <=> imageF
 * 0   <=> Fully transparent <=> imageB
 *
 * => OUT = F*alpha + B*(1-alpha)
 */

crimp_image*     result;
crimp_image*     imageF;
crimp_image*     imageB;
int ralpha, px, py, oxf, oyf, oxb, oyb;
crimp_geometry bb;

crimp_input (imageForeObj, imageF, float);
crimp_input (imageBackObj, imageB, float);

if (alpha == 255) {
    Tcl_SetObjResult(interp, imageForeObj);
    return TCL_OK;
} else if (alpha == 0) {
    Tcl_SetObjResult(interp, imageBackObj);
    return TCL_OK;
}

/*
 * True alpha mixture.
 */

ralpha = 255 - alpha;

crimp_rect_union (&imageF->geo, &imageB->geo, &bb);

result = crimp_new_float_at (bb.x, bb.y, bb.w, bb.h);
oxf = crimp_x (imageF);
oyf = crimp_y (imageF);
oxb = crimp_x (imageB);
oyb = crimp_y (imageB);

/*
 * px, py are physical coordinates in the result, starting from 0.
 * The associated logical coordinates in the 2D plane are
 *  lx = px + x(result)
 *  lx = py + y(result)
 * And when we are inside an input its physical coordinates, from the logical are
 *  px = lx - x(input)
 *  py = ly - y(input)
 */

#define MIX(fore,back) ((((fore)*alpha) + ((back)*ralpha))/255)

for (py = 0; py < bb.h; py++) {
    for (px = 0; px < bb.w; px++) {

        int lx = px + bb.x;
        int ly = py + bb.y;

	int inf = crimp_inside (imageF, lx, ly);
	int inb = crimp_inside (imageB, lx, ly);

	/*
	 * The result depends on where we are relative to both input.
	 * Inside of each input we take the respective value of the
	 * pixel. Outside of an input we take BLACK as the value
	 * instead, and TRANSPARENT for the ALPHA.
	 */

	float fore = inf ? FLOATP (imageF, lx - oxf, ly - oyf) : BLACK;
	float back = inb ? FLOATP (imageB, lx - oxb, ly - oyb) : BLACK;

	FLOATP (result, px, py) = MIX (fore, back);
    }
}

Tcl_SetObjResult(interp, crimp_new_image_obj (result));
return TCL_OK;
#undef MIX

/* vim: set sts=4 sw=4 tw=80 et ft=c: */
/*
 * Local Variables:
 * mode: c
 * c-basic-offset: 4
 * fill-column: 78
 * End:
 */
Added operator/alpha-blend-fpcomplex-fpcomplex.crimp.




































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
alpha_blend_fpcomplex_fpcomplex
Tcl_Obj* imageForeObj
Tcl_Obj* imageBackObj
float alpha

/*
 * Alpha-based blending of two images, foreground, and background, controlled
 * by a scalar (and extern) alpha factor.
 *
 * alpha is Opacity
 * 255 <=> Fully opaque      <=> imageF
 * 0   <=> Fully transparent <=> imageB
 *
 * => OUT = F*alpha + B*(1-alpha)
 */

crimp_image*     result;
crimp_image*     imageF;
crimp_image*     imageB;
int ralpha, px, py, oxf, oyf, oxb, oyb;
crimp_geometry bb;

crimp_input (imageForeObj, imageF, fpcomplex);
crimp_input (imageBackObj, imageB, fpcomplex);

if (alpha == 255) {
    Tcl_SetObjResult(interp, imageForeObj);
    return TCL_OK;
} else if (alpha == 0) {
    Tcl_SetObjResult(interp, imageBackObj);
    return TCL_OK;
}

/*
 * True alpha mixture.
 */

ralpha = 255 - alpha;

crimp_rect_union (&imageF->geo, &imageB->geo, &bb);

result = crimp_new_fpcomplex_at (bb.x, bb.y, bb.w, bb.h);
oxf = crimp_x (imageF);
oyf = crimp_y (imageF);
oxb = crimp_x (imageB);
oyb = crimp_y (imageB);

/*
 * px, py are physical coordinates in the result, starting from 0.
 * The associated logical coordinates in the 2D plane are
 *  lx = px + x(result)
 *  lx = py + y(result)
 * And when we are inside an input its physical coordinates, from the logical are
 *  px = lx - x(input)
 *  py = ly - y(input)
 */

#define MIX(fore,back) ((((fore)*alpha) + ((back)*ralpha))/255)

for (py = 0; py < bb.h; py++) {
    for (px = 0; px < bb.w; px++) {

        int lx = px + bb.x;
        int ly = py + bb.y;

	int inf = crimp_inside (imageF, lx, ly);
	int inb = crimp_inside (imageB, lx, ly);

	/*
	 * The result depends on where we are relative to both input.
	 * Inside of each input we take the respective value of the
	 * pixel. Outside of an input we take BLACK as the value
	 * instead, and TRANSPARENT for the ALPHA.
	 */

	float forer = inf ? RE (imageF, lx - oxf, ly - oyf) : BLACK;
	float forei = inf ? IM (imageF, lx - oxf, ly - oyf) : BLACK;

	float backr = inb ? RE (imageB, lx - oxb, ly - oyb) : BLACK;
	float backi = inb ? IM (imageB, lx - oxb, ly - oyb) : BLACK;

	RE (result, px, py) = MIX (forer, backr);
	IM (result, px, py) = MIX (forei, backi);
    }
}

Tcl_SetObjResult(interp, crimp_new_image_obj (result));
return TCL_OK;
#undef MIX

/* vim: set sts=4 sw=4 tw=80 et ft=c: */
/*
 * Local Variables:
 * mode: c
 * c-basic-offset: 4
 * fill-column: 78
 * End:
 */
Added operator/alpha-blend-grey16-grey16.crimp.




























































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
alpha_blend_grey16_grey16
Tcl_Obj* imageForeObj
Tcl_Obj* imageBackObj
int alpha

/*
 * Alpha-based blending of two images, foreground, and background, controlled
 * by a scalar (and extern) alpha factor.
 *
 * alpha is Opacity
 * 255 <=> Fully opaque      <=> imageF
 * 0   <=> Fully transparent <=> imageB
 *
 * => OUT = F*alpha + B*(1-alpha)
 */

crimp_image*     result;
crimp_image*     imageF;
crimp_image*     imageB;
int ralpha, px, py, oxf, oyf, oxb, oyb;
crimp_geometry bb;

crimp_input (imageForeObj, imageF, grey16);
crimp_input (imageBackObj, imageB, grey16);

if (alpha == 255) {
    Tcl_SetObjResult(interp, imageForeObj);
    return TCL_OK;
} else if (alpha == 0) {
    Tcl_SetObjResult(interp, imageBackObj);
    return TCL_OK;
}

/*
 * True alpha mixture.
 */

ralpha = 255 - alpha;

crimp_rect_union (&imageF->geo, &imageB->geo, &bb);

result = crimp_new_grey16_at (bb.x, bb.y, bb.w, bb.h);
oxf = crimp_x (imageF);
oyf = crimp_y (imageF);
oxb = crimp_x (imageB);
oyb = crimp_y (imageB);

/*
 * px, py are physical coordinates in the result, starting from 0.
 * The associated logical coordinates in the 2D plane are
 *  lx = px + x(result)
 *  lx = py + y(result)
 * And when we are inside an input its physical coordinates, from the logical are
 *  px = lx - x(input)
 *  py = ly - y(input)
 */

#define MIX(fore,back) ((((fore)*alpha) + ((back)*ralpha))/255)

for (py = 0; py < bb.h; py++) {
    for (px = 0; px < bb.w; px++) {

        int lx = px + bb.x;
        int ly = py + bb.y;

	int inf = crimp_inside (imageF, lx, ly);
	int inb = crimp_inside (imageB, lx, ly);

	/*
	 * The result depends on where we are relative to both input.
	 * Inside of each input we take the respective value of the
	 * pixel. Outside of an input we take BLACK as the value
	 * instead, and TRANSPARENT for the ALPHA.
	 */

	int fore = inf ? GREY16 (imageF, lx - oxf, ly - oyf) : BLACK;
	int back = inb ? GREY16 (imageB, lx - oxb, ly - oyb) : BLACK;

	GREY16 (result, px, py) = MIX (fore, back);
    }
}

Tcl_SetObjResult(interp, crimp_new_image_obj (result));
return TCL_OK;
#undef MIX

/* vim: set sts=4 sw=4 tw=80 et ft=c: */
/*
 * Local Variables:
 * mode: c
 * c-basic-offset: 4
 * fill-column: 78
 * End:
 */
Added operator/alpha-blend-grey32-grey32.crimp.




























































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
alpha_blend_grey32_grey32
Tcl_Obj* imageForeObj
Tcl_Obj* imageBackObj
int alpha

/*
 * Alpha-based blending of two images, foreground, and background, controlled
 * by a scalar (and extern) alpha factor.
 *
 * alpha is Opacity
 * 255 <=> Fully opaque      <=> imageF
 * 0   <=> Fully transparent <=> imageB
 *
 * => OUT = F*alpha + B*(1-alpha)
 */

crimp_image*     result;
crimp_image*     imageF;
crimp_image*     imageB;
int ralpha, px, py, oxf, oyf, oxb, oyb;
crimp_geometry bb;

crimp_input (imageForeObj, imageF, grey32);
crimp_input (imageBackObj, imageB, grey32);

if (alpha == 255) {
    Tcl_SetObjResult(interp, imageForeObj);
    return TCL_OK;
} else if (alpha == 0) {
    Tcl_SetObjResult(interp, imageBackObj);
    return TCL_OK;
}

/*
 * True alpha mixture.
 */

ralpha = 255 - alpha;

crimp_rect_union (&imageF->geo, &imageB->geo, &bb);

result = crimp_new_grey32_at (bb.x, bb.y, bb.w, bb.h);
oxf = crimp_x (imageF);
oyf = crimp_y (imageF);
oxb = crimp_x (imageB);
oyb = crimp_y (imageB);

/*
 * px, py are physical coordinates in the result, starting from 0.
 * The associated logical coordinates in the 2D plane are
 *  lx = px + x(result)
 *  lx = py + y(result)
 * And when we are inside an input its physical coordinates, from the logical are
 *  px = lx - x(input)
 *  py = ly - y(input)
 */

#define MIX(fore,back) ((((fore)*alpha) + ((back)*ralpha))/255)

for (py = 0; py < bb.h; py++) {
    for (px = 0; px < bb.w; px++) {

        int lx = px + bb.x;
        int ly = py + bb.y;

	int inf = crimp_inside (imageF, lx, ly);
	int inb = crimp_inside (imageB, lx, ly);

	/*
	 * The result depends on where we are relative to both input.
	 * Inside of each input we take the respective value of the
	 * pixel. Outside of an input we take BLACK as the value
	 * instead, and TRANSPARENT for the ALPHA.
	 */

	int fore = inf ? GREY32 (imageF, lx - oxf, ly - oyf) : BLACK;
	int back = inb ? GREY32 (imageB, lx - oxb, ly - oyb) : BLACK;

	GREY32 (result, px, py) = MIX (fore, back);
    }
}

Tcl_SetObjResult(interp, crimp_new_image_obj (result));
return TCL_OK;
#undef MIX

/* vim: set sts=4 sw=4 tw=80 et ft=c: */
/*
 * Local Variables:
 * mode: c
 * c-basic-offset: 4
 * fill-column: 78
 * End:
 */
Changes to operator/alpha-blend-grey8-grey8.crimp.
13
14
15
16
17
18
19
20

21
22
23
24

25


26
27
28
29



30
31
32


















33
34


35


36


37











38
39
40
41
42

43
44
45
46
47
48
49
 *
 * => OUT = F*alpha + B*(1-alpha)
 */

crimp_image*     result;
crimp_image*     imageF;
crimp_image*     imageB;
int x, y, ralpha;


crimp_input (imageForeObj, imageF, grey8);
crimp_input (imageBackObj, imageB, grey8);


if (!crimp_eq_dim (imageF, imageB)) {


    Tcl_SetResult(interp, "image dimensions do not match", TCL_STATIC);
    return TCL_ERROR;
}




result = crimp_new_like (imageF);
ralpha = 255 - alpha;



















#define MIX(fore,back) ((((fore)*alpha) + ((back)*ralpha))/255)



for (y = 0; y < crimp_h (result); y++) {


    for (x = 0; x < crimp_w (result); x++) {


	GREY8 (result, x, y) = MIX (GREY8 (imageF, x, y), GREY8 (imageB, x, y));











    }
}

Tcl_SetObjResult(interp, crimp_new_image_obj (result));
return TCL_OK;


/* vim: set sts=4 sw=4 tw=80 et ft=c: */
/*
 * Local Variables:
 * mode: c
 * c-basic-offset: 4
 * fill-column: 78







|
>




>
|
>
>
|
|


>
>
>
|


>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>


>
>
|
>
>
|
>
>
|
>
>
>
>
>
>
>
>
>
>
>





>







13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
 *
 * => OUT = F*alpha + B*(1-alpha)
 */

crimp_image*     result;
crimp_image*     imageF;
crimp_image*     imageB;
int ralpha, px, py, oxf, oyf, oxb, oyb;
crimp_geometry bb;

crimp_input (imageForeObj, imageF, grey8);
crimp_input (imageBackObj, imageB, grey8);

if (alpha == 255) {
    Tcl_SetObjResult(interp, imageForeObj);
    return TCL_OK;
} else if (alpha == 0) {
    Tcl_SetObjResult(interp, imageBackObj);
    return TCL_OK;
}

/*
 * True alpha mixture.
 */

ralpha = 255 - alpha;

crimp_rect_union (&imageF->geo, &imageB->geo, &bb);

result = crimp_new_grey8_at (bb.x, bb.y, bb.w, bb.h);
oxf = crimp_x (imageF);
oyf = crimp_y (imageF);
oxb = crimp_x (imageB);
oyb = crimp_y (imageB);

/*
 * px, py are physical coordinates in the result, starting from 0.
 * The associated logical coordinates in the 2D plane are
 *  lx = px + x(result)
 *  lx = py + y(result)
 * And when we are inside an input its physical coordinates, from the logical are
 *  px = lx - x(input)
 *  py = ly - y(input)
 */

#define MIX(fore,back) ((((fore)*alpha) + ((back)*ralpha))/255)

for (py = 0; py < bb.h; py++) {
    for (px = 0; px < bb.w; px++) {

        int lx = px + bb.x;
        int ly = py + bb.y;

	int inf = crimp_inside (imageF, lx, ly);
	int inb = crimp_inside (imageB, lx, ly);

	/*
	 * The result depends on where we are relative to both input.
	 * Inside of each input we take the respective value of the
	 * pixel. Outside of an input we take BLACK as the value
	 * instead, and TRANSPARENT for the ALPHA.
	 */

	int fore = inf ? GREY8 (imageF, lx - oxf, ly - oyf) : BLACK;
	int back = inb ? GREY8 (imageB, lx - oxb, ly - oyb) : BLACK;

	GREY8 (result, px, py) = MIX (fore, back);
    }
}

Tcl_SetObjResult(interp, crimp_new_image_obj (result));
return TCL_OK;
#undef MIX

/* vim: set sts=4 sw=4 tw=80 et ft=c: */
/*
 * Local Variables:
 * mode: c
 * c-basic-offset: 4
 * fill-column: 78
Changes to operator/alpha-blend-hsv-hsv.crimp.
14
15
16
17
18
19
20
21

22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43



44




45










46
47


48


49


50






51



52








53
54
55
56
57

58
59
60
61
62
63
64
 *
 * => OUT = F*alpha + B*(1-alpha)
 */

crimp_image*     result;
crimp_image*     imageF;
crimp_image*     imageB;
int x, y, ralpha;


crimp_input (imageForeObj, imageF, hsv);
crimp_input (imageBackObj, imageB, hsv);

if (!crimp_eq_dim (imageF, imageB)) {
    Tcl_SetResult(interp, "image dimensions do not match", TCL_STATIC);
    return TCL_ERROR;
}

if (alpha == 255) {
    Tcl_SetObjResult(interp, imageForeObj);
    return TCL_OK;
} else if (alpha == 0) {
    Tcl_SetObjResult(interp, imageBackObj);
    return TCL_OK;
}

/*
 * True alpha mixture.
 */

ralpha = 255 - alpha;



result = crimp_new_like (imageF);















#define MIX(fore,back) ((((fore)*alpha) + ((back)*ralpha))/255)



for (y = 0; y < crimp_h (result); y++) {


    for (x = 0; x < crimp_w (result); x++) {


	H (result, x, y) = MIX (H (imageF, x, y), H (imageB, x, y));






	S (result, x, y) = MIX (S (imageF, x, y), S (imageB, x, y));



	V (result, x, y) = MIX (V (imageF, x, y), V (imageB, x, y));








    }
}

Tcl_SetObjResult(interp, crimp_new_image_obj (result));
return TCL_OK;


/* vim: set sts=4 sw=4 tw=80 et ft=c: */
/*
 * Local Variables:
 * mode: c
 * c-basic-offset: 4
 * fill-column: 78







|
>




<
<
<
<
<













>
>
>
|
>
>
>
>

>
>
>
>
>
>
>
>
>
>


>
>
|
>
>
|
>
>
|
>
>
>
>
>
>
|
>
>
>
|
>
>
>
>
>
>
>
>





>







14
15
16
17
18
19
20
21
22
23
24
25
26





27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
 *
 * => OUT = F*alpha + B*(1-alpha)
 */

crimp_image*     result;
crimp_image*     imageF;
crimp_image*     imageB;
int ralpha, px, py, oxf, oyf, oxb, oyb;
crimp_geometry bb;

crimp_input (imageForeObj, imageF, hsv);
crimp_input (imageBackObj, imageB, hsv);






if (alpha == 255) {
    Tcl_SetObjResult(interp, imageForeObj);
    return TCL_OK;
} else if (alpha == 0) {
    Tcl_SetObjResult(interp, imageBackObj);
    return TCL_OK;
}

/*
 * True alpha mixture.
 */

ralpha = 255 - alpha;

crimp_rect_union (&imageF->geo, &imageB->geo, &bb);

result = crimp_new_hsv_at (bb.x, bb.y, bb.w, bb.h);
oxf = crimp_x (imageF);
oyf = crimp_y (imageF);
oxb = crimp_x (imageB);
oyb = crimp_y (imageB);

/*
 * px, py are physical coordinates in the result, starting from 0.
 * The associated logical coordinates in the 2D plane are
 *  lx = px + x(result)
 *  lx = py + y(result)
 * And when we are inside an input its physical coordinates, from the logical are
 *  px = lx - x(input)
 *  py = ly - y(input)
 */

#define MIX(fore,back) ((((fore)*alpha) + ((back)*ralpha))/255)

for (py = 0; py < bb.h; py++) {
    for (px = 0; px < bb.w; px++) {

        int lx = px + bb.x;
        int ly = py + bb.y;

	int inf = crimp_inside (imageF, lx, ly);
	int inb = crimp_inside (imageB, lx, ly);

	/*
	 * The result depends on where we are relative to both input.
	 * Inside of each input we take the respective value of the
	 * pixel. Outside of an input we take BLACK as the value
	 * instead, and TRANSPARENT for the ALPHA.
	 */

	int foreh = inf ? H (imageF, lx - oxf, ly - oyf) : BLACK;
	int fores = inf ? S (imageF, lx - oxf, ly - oyf) : BLACK;
	int forev = inf ? V (imageF, lx - oxf, ly - oyf) : BLACK;

	int backh = inb ? H (imageB, lx - oxb, ly - oyb) : BLACK;
	int backs = inb ? S (imageB, lx - oxb, ly - oyb) : BLACK;
	int backv = inb ? V (imageB, lx - oxb, ly - oyb) : BLACK;


	H (result, px, py) = MIX (foreh, backh);
	S (result, px, py) = MIX (fores, backs);
	V (result, px, py) = MIX (forev, backv);
    }
}

Tcl_SetObjResult(interp, crimp_new_image_obj (result));
return TCL_OK;
#undef MIX

/* vim: set sts=4 sw=4 tw=80 et ft=c: */
/*
 * Local Variables:
 * mode: c
 * c-basic-offset: 4
 * fill-column: 78
Changes to operator/alpha-blend-rgb-grey8.crimp.
1
2
3
4
5
6
7
8

9
10
11
12
13
14
15
16
17
18
19
20

21
22
23
24
25
26
27
28




29



30
31
32


















33
34


35


36


37






38



39





40
41
42
43
44

45
46
47
48
49
50
51
alpha_blend_rgb_grey8
Tcl_Obj* imageForeObj
Tcl_Obj* imageBackObj
int alpha

/*
 * Alpha-based blending of two images, foreground, and background, controlled
 * by a scalar (and extern) alpha factor.

 *
 * alpha is Opacity
 * 255 <=> Fully opaque      <=> imageF
 * 0   <=> Fully transparent <=> imageB
 *
 * => OUT = F*alpha + B*(1-alpha)
 */

crimp_image*     result;
crimp_image*     imageF;
crimp_image*     imageB;
int x, y, ralpha;


crimp_input (imageForeObj, imageF, rgb);
crimp_input (imageBackObj, imageB, grey8);

if (!crimp_eq_dim (imageF, imageB)) {
    Tcl_SetResult(interp, "image dimensions do not match", TCL_STATIC);
    return TCL_ERROR;
}








result = crimp_new_like (imageF);
ralpha = 255 - alpha;



















#define MIX(fore,back) ((((fore)*alpha) + ((back)*ralpha))/255)



for (y = 0; y < crimp_h (result); y++) {


    for (x = 0; x < crimp_w (result); x++) {


	R (result, x, y) = MIX (R (imageF, x, y), GREY8 (imageB, x, y));






	G (result, x, y) = MIX (G (imageF, x, y), GREY8 (imageB, x, y));



	B (result, x, y) = MIX (B (imageF, x, y), GREY8 (imageB, x, y));





    }
}

Tcl_SetObjResult(interp, crimp_new_image_obj (result));
return TCL_OK;


/* vim: set sts=4 sw=4 tw=80 et ft=c: */
/*
 * Local Variables:
 * mode: c
 * c-basic-offset: 4
 * fill-column: 78







|
>











|
>




|
|
|

>
>
>
>

>
>
>
|


>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>


>
>
|
>
>
|
>
>
|
>
>
>
>
>
>
|
>
>
>
|
>
>
>
>
>





>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
alpha_blend_rgb_grey8
Tcl_Obj* imageForeObj
Tcl_Obj* imageBackObj
int alpha

/*
 * Alpha-based blending of two images, foreground, and background, controlled
 * by a scalar (and extern) alpha factor. The result's alpha is the alpha
 * factor attenuated by the background's alpha.
 *
 * alpha is Opacity
 * 255 <=> Fully opaque      <=> imageF
 * 0   <=> Fully transparent <=> imageB
 *
 * => OUT = F*alpha + B*(1-alpha)
 */

crimp_image*     result;
crimp_image*     imageF;
crimp_image*     imageB;
int ralpha, px, py, oxf, oyf, oxb, oyb;
crimp_geometry bb;

crimp_input (imageForeObj, imageF, rgb);
crimp_input (imageBackObj, imageB, grey8);

if (alpha == 255) {
    Tcl_SetObjResult(interp, imageForeObj);
    return TCL_OK;
}
/* alpha == 0: Should return background, but have to return RGB, not GREY8.
 * Easiest handled by falling through into the actual mixer. Better would be
 * to have a loop specialized to the operation (clone the GREY8).
 */

/*
 * True alpha mixture.
 */

ralpha = 255 - alpha;

crimp_rect_union (&imageF->geo, &imageB->geo, &bb);

result = crimp_new_rgb_at (bb.x, bb.y, bb.w, bb.h);
oxf = crimp_x (imageF);
oyf = crimp_y (imageF);
oxb = crimp_x (imageB);
oyb = crimp_y (imageB);

/*
 * px, py are physical coordinates in the result, starting from 0.
 * The associated logical coordinates in the 2D plane are
 *  lx = px + x(result)
 *  lx = py + y(result)
 * And when we are inside an input its physical coordinates, from the logical are
 *  px = lx - x(input)
 *  py = ly - y(input)
 */

#define MIX(fore,back) ((((fore)*alpha) + ((back)*ralpha))/255)

for (py = 0; py < bb.h; py++) {
    for (px = 0; px < bb.w; px++) {

        int lx = px + bb.x;
        int ly = py + bb.y;

	int inf = crimp_inside (imageF, lx, ly);
	int inb = crimp_inside (imageB, lx, ly);

	/*
	 * The result depends on where we are relative to both input.
	 * Inside of each input we take the respective value of the
	 * pixel. Outside of an input we take BLACK as the value
	 * instead, and TRANSPARENT for the ALPHA.
	 */

	int forer = inf ? R (imageF, lx - oxf, ly - oyf) : BLACK;
	int foreg = inf ? G (imageF, lx - oxf, ly - oyf) : BLACK;
	int foreb = inf ? B (imageF, lx - oxf, ly - oyf) : BLACK;

	int backv = inb ? GREY8 (imageB, lx - oxb, ly - oyb) : BLACK;

	R (result, px, py) = MIX (forer, backv);
	G (result, px, py) = MIX (foreg, backv);
	B (result, px, py) = MIX (foreb, backv);
    }
}

Tcl_SetObjResult(interp, crimp_new_image_obj (result));
return TCL_OK;
#undef MIX

/* vim: set sts=4 sw=4 tw=80 et ft=c: */
/*
 * Local Variables:
 * mode: c
 * c-basic-offset: 4
 * fill-column: 78
Changes to operator/alpha-blend-rgb-rgb.crimp.
1
2
3
4
5
6
7
8

9
10
11
12
13
14
15
16
17
18
19
20

21
22
23
24

25


26
27
28
29



30
31
32


















33
34


35


36


37






38



39







40
41
42
43
44

45
46
47
48
49
50
51
alpha_blend_rgb_rgb
Tcl_Obj* imageForeObj
Tcl_Obj* imageBackObj
int alpha

/*
 * Alpha-based blending of two images, foreground, and background, controlled
 * by a scalar (and extern) alpha factor.

 *
 * alpha is Opacity
 * 255 <=> Fully opaque      <=> imageF
 * 0   <=> Fully transparent <=> imageB
 *
 * => OUT = F*alpha + B*(1-alpha)
 */

crimp_image*     result;
crimp_image*     imageF;
crimp_image*     imageB;
int x, y, ralpha;


crimp_input (imageForeObj, imageF, rgb);
crimp_input (imageBackObj, imageB, rgb);


if (!crimp_eq_dim (imageF, imageB)) {


    Tcl_SetResult(interp, "image dimensions do not match", TCL_STATIC);
    return TCL_ERROR;
}




result = crimp_new_like (imageF);
ralpha = 255 - alpha;



















#define MIX(fore,back) ((((fore)*alpha) + ((back)*ralpha))/255)



for (y = 0; y < crimp_h (result); y++) {


    for (x = 0; x < crimp_w (result); x++) {


	R (result, x, y) = MIX (R (imageF, x, y), R (imageB, x, y));






	G (result, x, y) = MIX (G (imageF, x, y), G (imageB, x, y));



	B (result, x, y) = MIX (B (imageF, x, y), B (imageB, x, y));







    }
}

Tcl_SetObjResult(interp, crimp_new_image_obj (result));
return TCL_OK;


/* vim: set sts=4 sw=4 tw=80 et ft=c: */
/*
 * Local Variables:
 * mode: c
 * c-basic-offset: 4
 * fill-column: 78







|
>











|
>




>
|
>
>
|
|


>
>
>
|


>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>


>
>
|
>
>
|
>
>
|
>
>
>
>
>
>
|
>
>
>
|
>
>
>
>
>
>
>





>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
alpha_blend_rgb_rgb
Tcl_Obj* imageForeObj
Tcl_Obj* imageBackObj
int alpha

/*
 * Alpha-based blending of two images, foreground, and background, controlled
 * by a scalar (and extern) alpha factor. The result's alpha is the alpha
 * factor attenuated by the background's alpha.
 *
 * alpha is Opacity
 * 255 <=> Fully opaque      <=> imageF
 * 0   <=> Fully transparent <=> imageB
 *
 * => OUT = F*alpha + B*(1-alpha)
 */

crimp_image*     result;
crimp_image*     imageF;
crimp_image*     imageB;
int ralpha, px, py, oxf, oyf, oxb, oyb;
crimp_geometry bb;

crimp_input (imageForeObj, imageF, rgb);
crimp_input (imageBackObj, imageB, rgb);

if (alpha == 255) {
    Tcl_SetObjResult(interp, imageForeObj);
    return TCL_OK;
} else if (alpha == 0) {
    Tcl_SetObjResult(interp, imageBackObj);
    return TCL_OK;
}

/*
 * True alpha mixture.
 */

ralpha = 255 - alpha;

crimp_rect_union (&imageF->geo, &imageB->geo, &bb);

result = crimp_new_rgb_at (bb.x, bb.y, bb.w, bb.h);
oxf = crimp_x (imageF);
oyf = crimp_y (imageF);
oxb = crimp_x (imageB);
oyb = crimp_y (imageB);

/*
 * px, py are physical coordinates in the result, starting from 0.
 * The associated logical coordinates in the 2D plane are
 *  lx = px + x(result)
 *  lx = py + y(result)
 * And when we are inside an input its physical coordinates, from the logical are
 *  px = lx - x(input)
 *  py = ly - y(input)
 */

#define MIX(fore,back) ((((fore)*alpha) + ((back)*ralpha))/255)

for (py = 0; py < bb.h; py++) {
    for (px = 0; px < bb.w; px++) {

        int lx = px + bb.x;
        int ly = py + bb.y;

	int inf = crimp_inside (imageF, lx, ly);
	int inb = crimp_inside (imageB, lx, ly);

	/*
	 * The result depends on where we are relative to both input.
	 * Inside of each input we take the respective value of the
	 * pixel. Outside of an input we take BLACK as the value
	 * instead, and TRANSPARENT for the ALPHA.
	 */

	int forer = inf ? R (imageF, lx - oxf, ly - oyf) : BLACK;
	int foreg = inf ? G (imageF, lx - oxf, ly - oyf) : BLACK;
	int foreb = inf ? B (imageF, lx - oxf, ly - oyf) : BLACK;

	int backr = inb ? R (imageB, lx - oxb, ly - oyb) : BLACK;
	int backg = inb ? G (imageB, lx - oxb, ly - oyb) : BLACK;
	int backb = inb ? B (imageB, lx - oxb, ly - oyb) : BLACK;

	R (result, px, py) = MIX (forer, backr);
	G (result, px, py) = MIX (foreg, backg);
	B (result, px, py) = MIX (foreb, backb);
    }
}

Tcl_SetObjResult(interp, crimp_new_image_obj (result));
return TCL_OK;
#undef MIX

/* vim: set sts=4 sw=4 tw=80 et ft=c: */
/*
 * Local Variables:
 * mode: c
 * c-basic-offset: 4
 * fill-column: 78
Changes to operator/alpha-blend-rgb-rgba.crimp.
1
2
3
4
5
6
7
8

9
10
11
12
13
14
15
16
17
18
19
20

21
22
23
24





25
26
27
28
29



30
31
32


















33
34


35


36


37






38



39







40
41
42
43
44

45
46
47
48
49
50
51
alpha_blend_rgb_rgba
Tcl_Obj* imageForeObj
Tcl_Obj* imageBackObj
int alpha

/*
 * Alpha-based blending of two images, foreground, and background, controlled
 * by a scalar (and extern) alpha factor.

 *
 * alpha is Opacity
 * 255 <=> Fully opaque      <=> imageF
 * 0   <=> Fully transparent <=> imageB
 *
 * => OUT = F*alpha + B*(1-alpha)
 */

crimp_image*     result;
crimp_image*     imageF;
crimp_image*     imageB;
int x, y, ralpha;


crimp_input (imageForeObj, imageF, rgb);
crimp_input (imageBackObj, imageB, rgba);






if (!crimp_eq_dim (imageF, imageB)) {
    Tcl_SetResult(interp, "image dimensions do not match", TCL_STATIC);
    return TCL_ERROR;
}




result = crimp_new_like (imageF);
ralpha = 255 - alpha;



















#define MIX(fore,back) ((((fore)*alpha) + ((back)*ralpha))/255)



for (y = 0; y < crimp_h (result); y++) {


    for (x = 0; x < crimp_w (result); x++) {


	R (result, x, y) = MIX (R (imageF, x, y), R (imageB, x, y));






	G (result, x, y) = MIX (G (imageF, x, y), G (imageB, x, y));



	B (result, x, y) = MIX (B (imageF, x, y), B (imageB, x, y));







    }
}

Tcl_SetObjResult(interp, crimp_new_image_obj (result));
return TCL_OK;


/* vim: set sts=4 sw=4 tw=80 et ft=c: */
/*
 * Local Variables:
 * mode: c
 * c-basic-offset: 4
 * fill-column: 78







|
>











|
>




>
>
>
>
>
|
|
|


>
>
>
|


>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>


>
>
|
>
>
|
>
>
|
>
>
>
>
>
>
|
>
>
>
|
>
>
>
>
>
>
>





>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
alpha_blend_rgb_rgba
Tcl_Obj* imageForeObj
Tcl_Obj* imageBackObj
int alpha

/*
 * Alpha-based blending of two images, foreground, and background, controlled
 * by a scalar (and extern) alpha factor. The result's alpha is the alpha
 * factor attenuated by the background's alpha.
 *
 * alpha is Opacity
 * 255 <=> Fully opaque      <=> imageF
 * 0   <=> Fully transparent <=> imageB
 *
 * => OUT = F*alpha + B*(1-alpha)
 */

crimp_image*     result;
crimp_image*     imageF;
crimp_image*     imageB;
int ralpha, px, py, oxf, oyf, oxb, oyb;
crimp_geometry bb;

crimp_input (imageForeObj, imageF, rgb);
crimp_input (imageBackObj, imageB, rgba);

/* alpha == 255: Should return foreground, but have to return RGBA, not RGB.
 * Easiest handled by falling through into the actual mixer. Better would be
 * to have a loop specialized to the operation (clone the RGB, and drop the
 * alpha).
 */
if (alpha == 0) {
    Tcl_SetObjResult(interp, imageBackObj);
    return TCL_OK;
}

/*
 * True alpha mixture.
 */

ralpha = 255 - alpha;

crimp_rect_union (&imageF->geo, &imageB->geo, &bb);

result = crimp_new_rgb_at (bb.x, bb.y, bb.w, bb.h);
oxf = crimp_x (imageF);
oyf = crimp_y (imageF);
oxb = crimp_x (imageB);
oyb = crimp_y (imageB);

/*
 * px, py are physical coordinates in the result, starting from 0.
 * The associated logical coordinates in the 2D plane are
 *  lx = px + x(result)
 *  lx = py + y(result)
 * And when we are inside an input its physical coordinates, from the logical are
 *  px = lx - x(input)
 *  py = ly - y(input)
 */

#define MIX(fore,back) ((((fore)*alpha) + ((back)*ralpha))/255)

for (py = 0; py < bb.h; py++) {
    for (px = 0; px < bb.w; px++) {

        int lx = px + bb.x;
        int ly = py + bb.y;

	int inf = crimp_inside (imageF, lx, ly);
	int inb = crimp_inside (imageB, lx, ly);

	/*
	 * The result depends on where we are relative to both input.
	 * Inside of each input we take the respective value of the
	 * pixel. Outside of an input we take BLACK as the value
	 * instead, and TRANSPARENT for the ALPHA.
	 */

	int forer = inf ? R (imageF, lx - oxf, ly - oyf) : BLACK;
	int foreg = inf ? G (imageF, lx - oxf, ly - oyf) : BLACK;
	int foreb = inf ? B (imageF, lx - oxf, ly - oyf) : BLACK;

	int backr = inb ? R (imageB, lx - oxb, ly - oyb) : BLACK;
	int backg = inb ? G (imageB, lx - oxb, ly - oyb) : BLACK;
	int backb = inb ? B (imageB, lx - oxb, ly - oyb) : BLACK;

	R (result, px, py) = MIX (forer, backr);
	G (result, px, py) = MIX (foreg, backg);
	B (result, px, py) = MIX (foreb, backb);
    }
}

Tcl_SetObjResult(interp, crimp_new_image_obj (result));
return TCL_OK;
#undef MIX

/* vim: set sts=4 sw=4 tw=80 et ft=c: */
/*
 * Local Variables:
 * mode: c
 * c-basic-offset: 4
 * fill-column: 78
Changes to operator/alpha-blend-rgba-grey8.crimp.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

23
24
25
26
27
28
29
30





31



32
33
34


















35
36


37


38


39






40




41






42
43
44
45
46
47

48
49
50
51
52
53
54
alpha_blend_rgba_grey8
Tcl_Obj* imageForeObj
Tcl_Obj* imageBackObj
int alpha

/*
 * Alpha-based blending of two images, foreground, and background, controlled
 * by a scalar (and extern) alpha factor. The result's alpha is the alpha
 * factor. No attenuation by the background's alpha, as such doesn't
 * exist. Presumed to be TRANSPARENT = No attenuation.
 *
 * alpha is Opacity
 * 255 <=> Fully opaque      <=> imageF
 * 0   <=> Fully transparent <=> imageB
 *
 * => OUT = F*alpha + B*(1-alpha)
 */

crimp_image*     result;
crimp_image*     imageF;
crimp_image*     imageB;
int x, y, ralpha;


crimp_input (imageForeObj, imageF, rgba);
crimp_input (imageBackObj, imageB, grey8);

if (!crimp_eq_dim (imageF, imageB)) {
    Tcl_SetResult(interp, "image dimensions do not match", TCL_STATIC);
    return TCL_ERROR;
}









result = crimp_new_like (imageF);
ralpha = 255 - alpha;



















#define MIX(fore,back) ((((fore)*alpha) + ((back)*ralpha))/255)



for (y = 0; y < crimp_h (result); y++) {


    for (x = 0; x < crimp_w (result); x++) {


	R (result, x, y) = MIX (R (imageF, x, y), GREY8 (imageB, x, y));






	G (result, x, y) = MIX (G (imageF, x, y), GREY8 (imageB, x, y));




	B (result, x, y) = MIX (B (imageF, x, y), GREY8 (imageB, x, y));






	A (result, x, y) = alpha;
    }
}

Tcl_SetObjResult(interp, crimp_new_image_obj (result));
return TCL_OK;


/* vim: set sts=4 sw=4 tw=80 et ft=c: */
/*
 * Local Variables:
 * mode: c
 * c-basic-offset: 4
 * fill-column: 78








|
<











|
>




|
|
|

>
>
>
>
>

>
>
>
|


>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>


>
>
|
>
>
|
>
>
|
>
>
>
>
>
>
|
>
>
>
>
|
>
>
>
>
>
>
|





>







1
2
3
4
5
6
7
8
9

10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
alpha_blend_rgba_grey8
Tcl_Obj* imageForeObj
Tcl_Obj* imageBackObj
int alpha

/*
 * Alpha-based blending of two images, foreground, and background, controlled
 * by a scalar (and extern) alpha factor. The result's alpha is the alpha
 * factor attenuated by the background's alpha.

 *
 * alpha is Opacity
 * 255 <=> Fully opaque      <=> imageF
 * 0   <=> Fully transparent <=> imageB
 *
 * => OUT = F*alpha + B*(1-alpha)
 */

crimp_image*     result;
crimp_image*     imageF;
crimp_image*     imageB;
int ralpha, px, py, oxf, oyf, oxb, oyb;
crimp_geometry bb;

crimp_input (imageForeObj, imageF, rgba);
crimp_input (imageBackObj, imageB, grey8);

if (alpha == 255) {
    Tcl_SetObjResult(interp, imageForeObj);
    return TCL_OK;
}
/* alpha == 0: Should return background, but have to return RGBA, not GREY8.
 * Easiest handled by falling through into the actual mixer. Better would be
 * to have a loop specialized to the operation (clone the GREY8, and add
 * constant opaque alpha).
 */

/*
 * True alpha mixture.
 */

ralpha = 255 - alpha;

crimp_rect_union (&imageF->geo, &imageB->geo, &bb);

result = crimp_new_rgba_at (bb.x, bb.y, bb.w, bb.h);
oxf = crimp_x (imageF);
oyf = crimp_y (imageF);
oxb = crimp_x (imageB);
oyb = crimp_y (imageB);

/*
 * px, py are physical coordinates in the result, starting from 0.
 * The associated logical coordinates in the 2D plane are
 *  lx = px + x(result)
 *  lx = py + y(result)
 * And when we are inside an input its physical coordinates, from the logical are
 *  px = lx - x(input)
 *  py = ly - y(input)
 */

#define MIX(fore,back) ((((fore)*alpha) + ((back)*ralpha))/255)

for (py = 0; py < bb.h; py++) {
    for (px = 0; px < bb.w; px++) {

        int lx = px + bb.x;
        int ly = py + bb.y;

	int inf = crimp_inside (imageF, lx, ly);
	int inb = crimp_inside (imageB, lx, ly);

	/*
	 * The result depends on where we are relative to both input.
	 * Inside of each input we take the respective value of the
	 * pixel. Outside of an input we take BLACK as the value
	 * instead, and TRANSPARENT for the ALPHA.
	 */

	int forer = inf ? R (imageF, lx - oxf, ly - oyf) : BLACK;
	int foreg = inf ? G (imageF, lx - oxf, ly - oyf) : BLACK;
	int foreb = inf ? B (imageF, lx - oxf, ly - oyf) : BLACK;
	int forea = inf ? A (imageF, lx - oxf, ly - oyf) : BLACK;

	int backv = inb ? GREY8 (imageB, lx - oxb, ly - oyb) : BLACK;
	int backa = inb ? OPAQUE : TRANSPARENT;

	R (result, px, py) = MIX (forer, backv);
	G (result, px, py) = MIX (foreg, backv);
	B (result, px, py) = MIX (foreb, backv);
	A (result, px, py) = MIX (forea, backa);
    }
}

Tcl_SetObjResult(interp, crimp_new_image_obj (result));
return TCL_OK;
#undef MIX

/* vim: set sts=4 sw=4 tw=80 et ft=c: */
/*
 * Local Variables:
 * mode: c
 * c-basic-offset: 4
 * fill-column: 78
Changes to operator/alpha-blend-rgba-rgb.crimp.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

23
24
25
26
27
28
29
30





31



32
33
34


















35
36


37


38


39






40




41








42
43
44
45
46
47

48
49
50
51
52
53
54
alpha_blend_rgba_rgb
Tcl_Obj* imageForeObj
Tcl_Obj* imageBackObj
int alpha

/*
 * Alpha-based blending of two images, foreground, and background, controlled
 * by a scalar (and extern) alpha factor. The result's alpha is the alpha
 * factor. No attenuation by the background's alpha, as such doesn't
 * exist. Presumed to be TRANSPARENT = No attenuation.
 *
 * alpha is Opacity
 * 255 <=> Fully opaque      <=> imageF
 * 0   <=> Fully transparent <=> imageB
 *
 * => OUT = F*alpha + B*(1-alpha)
 */

crimp_image*     result;
crimp_image*     imageF;
crimp_image*     imageB;
int x, y, ralpha;


crimp_input (imageForeObj, imageF, rgba);
crimp_input (imageBackObj, imageB, rgb);

if (!crimp_eq_dim (imageF, imageB)) {
    Tcl_SetResult(interp, "image dimensions do not match", TCL_STATIC);
    return TCL_ERROR;
}









result = crimp_new_like (imageF);
ralpha = 255 - alpha;



















#define MIX(fore,back) ((((fore)*alpha) + ((back)*ralpha))/255)



for (y = 0; y < crimp_h (result); y++) {


    for (x = 0; x < crimp_w (result); x++) {


	R (result, x, y) = MIX (R (imageF, x, y), R (imageB, x, y));






	G (result, x, y) = MIX (G (imageF, x, y), G (imageB, x, y));




	B (result, x, y) = MIX (B (imageF, x, y), B (imageB, x, y));








	A (result, x, y) = alpha;
    }
}

Tcl_SetObjResult(interp, crimp_new_image_obj (result));
return TCL_OK;


/* vim: set sts=4 sw=4 tw=80 et ft=c: */
/*
 * Local Variables:
 * mode: c
 * c-basic-offset: 4
 * fill-column: 78








|
<











|
>




|
|
|

>
>
>
>
>

>
>
>
|


>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>


>
>
|
>
>
|
>
>
|
>
>
>
>
>
>
|
>
>
>
>
|
>
>
>
>
>
>
>
>
|





>







1
2
3
4
5
6
7
8
9

10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
alpha_blend_rgba_rgb
Tcl_Obj* imageForeObj
Tcl_Obj* imageBackObj
int alpha

/*
 * Alpha-based blending of two images, foreground, and background, controlled
 * by a scalar (and extern) alpha factor. The result's alpha is the alpha
 * factor attenuated by the background's alpha.

 *
 * alpha is Opacity
 * 255 <=> Fully opaque      <=> imageF
 * 0   <=> Fully transparent <=> imageB
 *
 * => OUT = F*alpha + B*(1-alpha)
 */

crimp_image*     result;
crimp_image*     imageF;
crimp_image*     imageB;
int ralpha, px, py, oxf, oyf, oxb, oyb;
crimp_geometry bb;

crimp_input (imageForeObj, imageF, rgba);
crimp_input (imageBackObj, imageB, rgb);

if (alpha == 255) {
    Tcl_SetObjResult(interp, imageForeObj);
    return TCL_OK;
}
/* alpha == 0: Should return background, but have to return RGBA, not RGB.
 * Easiest handled by falling through into the actual mixer. Better would be
 * to have a loop specialized to the operation (clone the RGB, and add
 * constant opaque alpha).
 */

/*
 * True alpha mixture.
 */

ralpha = 255 - alpha;

crimp_rect_union (&imageF->geo, &imageB->geo, &bb);

result = crimp_new_rgba_at (bb.x, bb.y, bb.w, bb.h);
oxf = crimp_x (imageF);
oyf = crimp_y (imageF);
oxb = crimp_x (imageB);
oyb = crimp_y (imageB);

/*
 * px, py are physical coordinates in the result, starting from 0.
 * The associated logical coordinates in the 2D plane are
 *  lx = px + x(result)
 *  lx = py + y(result)
 * And when we are inside an input its physical coordinates, from the logical are
 *  px = lx - x(input)
 *  py = ly - y(input)
 */

#define MIX(fore,back) ((((fore)*alpha) + ((back)*ralpha))/255)

for (py = 0; py < bb.h; py++) {
    for (px = 0; px < bb.w; px++) {

        int lx = px + bb.x;
        int ly = py + bb.y;

	int inf = crimp_inside (imageF, lx, ly);
	int inb = crimp_inside (imageB, lx, ly);

	/*
	 * The result depends on where we are relative to both input.
	 * Inside of each input we take the respective value of the
	 * pixel. Outside of an input we take BLACK as the value
	 * instead, and TRANSPARENT for the ALPHA.
	 */

	int forer = inf ? R (imageF, lx - oxf, ly - oyf) : BLACK;
	int foreg = inf ? G (imageF, lx - oxf, ly - oyf) : BLACK;
	int foreb = inf ? B (imageF, lx - oxf, ly - oyf) : BLACK;
	int forea = inf ? A (imageF, lx - oxf, ly - oyf) : BLACK;

	int backr = inb ? R (imageB, lx - oxb, ly - oyb) : BLACK;
	int backg = inb ? G (imageB, lx - oxb, ly - oyb) : BLACK;
	int backb = inb ? B (imageB, lx - oxb, ly - oyb) : BLACK;
	int backa = inb ? OPAQUE : TRANSPARENT;

	R (result, px, py) = MIX (forer, backr);
	G (result, px, py) = MIX (foreg, backg);
	B (result, px, py) = MIX (foreb, backb);
	A (result, px, py) = MIX (forea, backa);
    }
}

Tcl_SetObjResult(interp, crimp_new_image_obj (result));
return TCL_OK;
#undef MIX

/* vim: set sts=4 sw=4 tw=80 et ft=c: */
/*
 * Local Variables:
 * mode: c
 * c-basic-offset: 4
 * fill-column: 78
Changes to operator/alpha-blend-rgba-rgba.crimp.
14
15
16
17
18
19
20
21

22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45


















46
47


48


49


50






51




52




53




54
55
56
57
58

59
60
61
62
63
64
65
 *
 * => OUT = F*alpha + B*(1-alpha)
 */

crimp_image*     result;
crimp_image*     imageF;
crimp_image*     imageB;
int x, y, ralpha;


crimp_input (imageForeObj, imageF, rgba);
crimp_input (imageBackObj, imageB, rgba);

if (!crimp_eq_dim (imageF, imageB)) {
    Tcl_SetResult(interp, "image dimensions do not match", TCL_STATIC);
    return TCL_ERROR;
}

if (alpha == 255) {
    Tcl_SetObjResult(interp, imageForeObj);
    return TCL_OK;
} else if (alpha == 0) {
    Tcl_SetObjResult(interp, imageBackObj);
    return TCL_OK;
}

/*
 * True alpha mixture.
 */

result = crimp_new_like (imageF);
ralpha = 255 - alpha;



















#define MIX(fore,back) ((((fore)*alpha) + ((back)*ralpha))/255)



for (y = 0; y < crimp_h (result); y++) {


    for (x = 0; x < crimp_w (result); x++) {


	R (result, x, y) = MIX (R (imageF, x, y), R (imageB, x, y));






	G (result, x, y) = MIX (G (imageF, x, y), G (imageB, x, y));




	B (result, x, y) = MIX (B (imageF, x, y), B (imageB, x, y));




	A (result, x, y) = MIX (alpha, A (imageB, x, y));




    }
}

Tcl_SetObjResult(interp, crimp_new_image_obj (result));
return TCL_OK;


/* vim: set sts=4 sw=4 tw=80 et ft=c: */
/*
 * Local Variables:
 * mode: c
 * c-basic-offset: 4
 * fill-column: 78







|
>




<
<
<
<
<












<


>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>


>
>
|
>
>
|
>
>
|
>
>
>
>
>
>
|
>
>
>
>
|
>
>
>
>
|
>
>
>
>





>







14
15
16
17
18
19
20
21
22
23
24
25
26





27
28
29
30
31
32
33
34
35
36
37
38

39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
 *
 * => OUT = F*alpha + B*(1-alpha)
 */

crimp_image*     result;
crimp_image*     imageF;
crimp_image*     imageB;
int ralpha, px, py, oxf, oyf, oxb, oyb;
crimp_geometry bb;

crimp_input (imageForeObj, imageF, rgba);
crimp_input (imageBackObj, imageB, rgba);






if (alpha == 255) {
    Tcl_SetObjResult(interp, imageForeObj);
    return TCL_OK;
} else if (alpha == 0) {
    Tcl_SetObjResult(interp, imageBackObj);
    return TCL_OK;
}

/*
 * True alpha mixture.
 */


ralpha = 255 - alpha;

crimp_rect_union (&imageF->geo, &imageB->geo, &bb);

result = crimp_new_rgba_at (bb.x, bb.y, bb.w, bb.h);
oxf = crimp_x (imageF);
oyf = crimp_y (imageF);
oxb = crimp_x (imageB);
oyb = crimp_y (imageB);

/*
 * px, py are physical coordinates in the result, starting from 0.
 * The associated logical coordinates in the 2D plane are
 *  lx = px + x(result)
 *  lx = py + y(result)
 * And when we are inside an input its physical coordinates, from the logical are
 *  px = lx - x(input)
 *  py = ly - y(input)
 */

#define MIX(fore,back) ((((fore)*alpha) + ((back)*ralpha))/255)

for (py = 0; py < bb.h; py++) {
    for (px = 0; px < bb.w; px++) {

        int lx = px + bb.x;
        int ly = py + bb.y;

	int inf = crimp_inside (imageF, lx, ly);
	int inb = crimp_inside (imageB, lx, ly);

	/*
	 * The result depends on where we are relative to both input.
	 * Inside of each input we take the respective value of the
	 * pixel. Outside of an input we take BLACK as the value
	 * instead, and TRANSPARENT for the ALPHA.
	 */

	int forer = inf ? R (imageF, lx - oxf, ly - oyf) : BLACK;
	int foreg = inf ? G (imageF, lx - oxf, ly - oyf) : BLACK;
	int foreb = inf ? B (imageF, lx - oxf, ly - oyf) : BLACK;
	int forea = inf ? A (imageF, lx - oxf, ly - oyf) : BLACK;

	int backr = inb ? R (imageB, lx - oxb, ly - oyb) : BLACK;
	int backg = inb ? G (imageB, lx - oxb, ly - oyb) : BLACK;
	int backb = inb ? B (imageB, lx - oxb, ly - oyb) : BLACK;
	int backa = inb ? A (imageB, lx - oxb, ly - oyb) : BLACK;

	R (result, px, py) = MIX (forer, backr);
	G (result, px, py) = MIX (foreg, backg);
	B (result, px, py) = MIX (foreb, backb);
	A (result, px, py) = MIX (forea, backa);
    }
}

Tcl_SetObjResult(interp, crimp_new_image_obj (result));
return TCL_OK;
#undef MIX

/* vim: set sts=4 sw=4 tw=80 et ft=c: */
/*
 * Local Variables:
 * mode: c
 * c-basic-offset: 4
 * fill-column: 78