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 # 20 use strict; 21 use Image::Magick; 22 23 # Background or Destination image 24 my $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 31 my $src=Image::Magick->new(); 32 $src->Set(size=>'80x80'); 33 $src->Read('gradient:black-white'); 34 $src->Set(alpha=>'Set'); 35 36 my $offset="+10+10"; 37 38 # Circle Mask Image (same size as Destination) 39 my $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 44 my $texture=Image::Magick->new(); 45 $texture->Read('pattern:checkerboard'); 46 47 # List of images generated 48 my $results=Image::Magick->new(); 49 50 # Working copy of Destination Image 51 my $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 ); 63 push(@$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 ); 72 push(@$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 ); 81 push(@$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 ); 90 push(@$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 ); 103 push(@$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 ); 113 push(@$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 ); 123 push(@$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 ); 133 push(@$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 ); 147 push(@$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 ); 158 push(@$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 ); 169 push(@$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 ); 180 push(@$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 ); 196 push(@$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 ); 207 push(@$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 ); 218 push(@$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 ); 229 push(@$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 236 for my $image ( @$results ) { 237 $image->Composite( 238 image=>$texture, 239 tile=>'True', 240 compose=>'DstOver', 241 ); 242 } 243 244 my $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