1#!/usr/bin/perl
2#
3# Demonstration of some of the fancier Image Composition Methods
4# including the 'rotate' parameter specific to PerlMagick Composite()
5#
6# NOTE: versions of IM older than IM v6.5.3-4 will need to rename the
7# parameter  "args=>"   to  the mis-named "blend=>" parameter.
8#
9# Also not that "composite -watermark" is actually known as the compose
10# method "Modulate".
11#
12# Essentually each image is equivelent to
13#   convert logo: -crop 80x80+140+60 +repage \
14#           -size 60x60 gradient:black-white \
15#           -alpha set miff:- |\
16#    composite -  -geometry +10+10 -virtual-pixel gray \
17#              -dissolve 70x30   show:
18# for various composition methods.
19#
20use strict;
21use Image::Magick;
22
23# Background or Destination image
24my $dest=Image::Magick->new();
25$dest->Read('logo:');
26$dest->Crop('100x100+400+100');  # wizards hat
27$dest->Set(page=>'0x0+0+0');
28$dest->Set(alpha=>'Set');
29
30# Source, Composite or Overlay image
31my $src=Image::Magick->new();
32$src->Set(size=>'80x80');
33$src->Read('gradient:black-white');
34$src->Set(alpha=>'Set');
35
36my $offset="+10+10";
37
38# Circle Mask Image (same size as Destination)
39my $circle=Image::Magick->new();
40$circle->Set(size=>'80x80');
41$circle->Read('xc:black');
42$circle->Draw(fill=>'white',primitive=>'circle',points=>'39.5,39.5 10,39.5');
43
44my $texture=Image::Magick->new();
45$texture->Read('pattern:checkerboard');
46
47# List of images generated
48my $results=Image::Magick->new();
49
50# Working copy of Destination Image
51my $clone;
52
53# ----------------------------------------
54# Normal Composition Methods
55
56$clone=$dest->Clone();
57$clone->Label('Over\n(normal compose)');
58$clone->Composite(
59  image=>$src,
60  compose=>'over',
61  geometry=>$offset,
62);
63push(@$results, $clone);
64
65$clone=$dest->Clone();
66$clone->Label('Multiply\n(add black)');
67$clone->Composite(
68  image=>$src,
69  compose=>'multiply',
70  geometry=>$offset,
71);
72push(@$results, $clone);
73
74$clone=$dest->Clone();
75$clone->Label('Screen\n(add white)');
76$clone->Composite(
77  image=>$src,
78  compose=>'screen',
79  geometry=>$offset,
80);
81push(@$results, $clone);
82
83$clone=$dest->Clone();
84$clone->Label('HardLight\n(light effects)');
85$clone->Composite(
86  image=>$src,
87  compose=>'hardlight',
88  geometry=>$offset,
89);
90push(@$results, $clone);
91
92# ---------------
93# Masked and Blending Demonstartion
94
95$clone=$dest->Clone();
96$clone->Label('Circle Masked\n(three image)');
97$clone->Composite(
98  image=>$src,
99  mask=>$circle,
100  compose=>'over',
101  geometry=>$offset,
102);
103push(@$results, $clone);
104
105$clone=$dest->Clone();
106$clone->Label('Blend 50x50\n(50% plus 50%)');
107$clone->Composite(
108  image=>$src,
109  compose=>'blend',
110  args=>'50x50',
111  geometry=>$offset,
112);
113push(@$results, $clone);
114
115$clone=$dest->Clone();
116$clone->Label('Dissolve 50x50\n(50% over 50%)');
117$clone->Composite(
118  image=>$src,
119  compose=>'dissolve',
120  args=>'50x50',
121  geometry=>$offset,
122);
123push(@$results, $clone);
124
125$clone=$dest->Clone();
126$clone->Label('Dissolve 50\n(50% over 100%)');
127$clone->Composite(
128  image=>$src,
129  compose=>'dissolve',
130  args=>'50',
131  geometry=>$offset,
132);
133push(@$results, $clone);
134
135# ---------------
136# Displacement Demonstartion
137
138$clone=$dest->Clone();
139$clone->Label('Displace 50x0\n(displace horiz)');
140$clone->Set('virtual-pixel'=>'gray');
141$clone->Composite(
142  image=>$src,
143  compose=>'displace',
144  args=>'50x0',
145  geometry=>$offset,
146);
147push(@$results, $clone);
148
149$clone=$dest->Clone();
150$clone->Label('Displace 0x50\n(compress vert)');
151$clone->Set('virtual-pixel'=>'gray');
152$clone->Composite(
153  image=>$src,
154  compose=>'displace',
155  args=>'0x50',
156  geometry=>$offset,
157);
158push(@$results, $clone);
159
160$clone=$dest->Clone();
161$clone->Label('Displace 50x50\n(diagonal)');
162$clone->Set('virtual-pixel'=>'gray');
163$clone->Composite(
164  image=>$src,
165  compose=>'displace',
166  args=>'50x50',
167  geometry=>$offset,
168);
169push(@$results, $clone);
170
171$clone=$dest->Clone();
172$clone->Label('Displace 0,-80\n(displace flip)');
173$clone->Set('virtual-pixel'=>'gray');
174$clone->Composite(
175  image=>$src,
176  compose=>'displace',
177  args=>'0,-80',
178  geometry=>$offset,
179);
180push(@$results, $clone);
181
182# ---------------
183# Demonstrate rotation
184# note that offset is automatically adjusted to keep rotated image
185# centered relative to its '0' rotation position
186
187$clone=$dest->Clone();
188$clone->Label('Rotate 0\n');
189$clone->Composite(
190  image=>$src,
191  compose=>'over',
192  rotate=>0,
193  background=>'none',
194  geometry=>$offset,
195);
196push(@$results, $clone);
197
198$clone=$dest->Clone();
199$clone->Label('Rotate 10\n');
200$clone->Composite(
201  image=>$src,
202  compose=>'over',
203  rotate=>10,
204  background=>'none',
205  geometry=>$offset,
206);
207push(@$results, $clone);
208
209$clone=$dest->Clone();
210$clone->Label('Rotate 45\n');
211$clone->Composite(
212  image=>$src,
213  compose=>'over',
214  rotate=>45,
215  background=>'none',
216  geometry=>$offset,
217);
218push(@$results, $clone);
219
220$clone=$dest->Clone();
221$clone->Label('Rotate 90\n');
222$clone->Composite(
223  image=>$src,
224  compose=>'over',
225  rotate=>90,
226  background=>'none',
227  geometry=>$offset,
228);
229push(@$results, $clone);
230
231# ----------------------------------------
232# Output the changed pixels
233
234# to every image underlay a checkboard pattern
235# so as to show if any transparency is present
236for my $image ( @$results ) {
237  $image->Composite(
238    image=>$texture,
239    tile=>'True',
240    compose=>'DstOver',
241  );
242}
243
244my $montage=$results->Montage(
245  geometry=>'+10+10',
246  tile=>'4x',
247  frame=>'6x6+2+2',
248  shadow=>'True',
249);
250$montage->Write('show:');
251$montage->Write('compose_specials.jpg');
252
253