Reputation: 63902
Have an background image. (for this example the mesh.png
)
To the image need add one circle, with blurred border. Currently have this:
use 5.014;
use warnings;
use Image::Magick;
my $bgimg = Image::Magick->new();
$bgimg->Read('png:mesh.png');
draw_my_circle($bgimg, 150, 150, 100); #img, center_x, center_y, radius
$bgimg->Write("win:"); #display
sub draw_my_circle {
my($img, $center_x, $center_y, $radius) = @_;
$img->Draw(
fill => 'black',
points => "$center_x,$center_y @{[$center_x + $radius]},$center_y",
primitive => 'circle',
);
}
This produces the next image:
but I need a circle with "blurred edge", like the next (created manually)
Can anyone help how to get a such blurred circle with Image::Magick?
If someone want the mesh.png
, it is created with the next script:
use 5.014;
use warnings;
use Image::Magick;
my $image=Image::Magick->new(size=>'300x300');
$image->Read('xc:white');
for( my $i=0; $i < 300; $i += 10 ) {
$image->Draw(primitive=>'line',points=>"$i,0 $i,300",stroke=>"#ccf");
$image->Draw(primitive=>'line',points=>"0,$i 300,$i",stroke=>"#ccf");
}
$image->Write('png:mesh.png');
Upvotes: 2
Views: 1480
Reputation: 431
This is a very old thread, but it's still useful.
A problem with Gaussian blur is it doesn't scale well to very high resolutions. For a high-resolution image I'm making I used concentric circles instead, of graded transparency. The challenge is I can't just linearly grade the transparency, since the inner circles are also overlapped by the outer circles. So I calculated the incremental transparency of each layer to increase the opacity of the region to the target relative to the opacity of the layer immediately larger.
The below code is written in the "wand" python library. Here "radius" is the desired outer radius of the blurred circle. The inner radius is set to half of this. "image" is the image object.
I can't vouch for this code as I'm a python newbie:
# background
nShades = 128
stderr.write(f"rendering {nShades} shaded background circles...\n")
bgMinR = 0.5 * radius
bgMaxR = radius
with Drawing() as draw:
draw.gravity= "center"
draw.stroke_color = "none"
draw.stroke_width= 0
draw.stroke_fill= "none"
draw.antialias = False
transparency = 1
for i in range(0, nShades, 1):
# target transparency for this line
t = (1 - cos(pi * (nShades - i) / nShades)) / 2
r = (bgMaxR * (nShades - 1 - i) + bgMinR * i) / (nShades - 1)
# target transparency for this line
# how much alpha we need to get this transparency
# transparency * (1 - alpha/0xff) = t
# (1 - alpha)/0xff = t/transparency
# alpha/0xff = 1 - t/transparency
# alpha = 0xff * (1 - t/transparency)
alpha = int(0xff * (1 - t/transparency))
transparency *= (1 - alpha / 0xff)
draw.fill_color = "#000000%02x" % alpha
draw.circle((xc, yc), (xc + r, yc))
draw(image)
Upvotes: 0
Reputation: 207455
You can use Gaussian blur, like this:
#!/usr/bin/perl
use 5.014;
use strict;
use warnings;
use Image::Magick;
my $x;
my $circle;
my $mesh;
$mesh=Image::Magick->new(size=>'300x300');
$mesh->Read('xc:white');
for( my $i=0; $i < 300; $i += 10 ) {
$mesh->Draw(primitive=>'line',points=>"$i,0 $i,300",stroke=>"#ccf");
$mesh->Draw(primitive=>'line',points=>"0,$i 300,$i",stroke=>"#ccf");
}
$mesh->Write(filename=>'mesh.png');
$circle=Image::Magick->new(size=>'300x300');
$circle->ReadImage('xc:transparent');
$circle->Draw(
fill => 'black',
points => "150,150 @{[250]},100",
primitive => 'circle',
);
$circle->GaussianBlur('10x50');
$circle->Write(filename=>'circle.png');
$mesh->Composite(image => $circle, qw(compose SrcAtop gravity Center));
$mesh->Write(filename=>'out.png');
Upvotes: 3