Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > Perl > Perl Misc > semi-opacity with GD

Reply
Thread Tools

semi-opacity with GD

 
 
Richard Bennett
Guest
Posts: n/a
 
      05-18-2005
Hi,
i tried this question in comp.lang.perl.modules without any luck - maybe
someone here has an idea about it? :

I have GD2.0.33, and the most recent GD.pm on Linux.
I want to write a script that will load a PNG image, and make the image
semi-transparent.
I want to show this image over another one in the browser, and be able to
see the background image through the top one.
(I know this can be done in CSS, but am looking for a Firefox-only solution
using PNG alpha-channel)

I can make an image which does the right thing when I create a new image
like this:

#!/usr/bin/perl -w
use GD;
my $im; # The Image object
my $xsize = 160; my $ysize = 160;
my $bgcol = colourARGB( 70, 100, 255, 255 );
$im = new GD::Image->newTrueColor( $xsize, $ysize )
|| die "$0: Failed to create image -- $!\n";
$im->saveAlpha(1);
$im->alphaBlending(0);
$im->filledRectangle( 0, 0, $xsize - 1, $ysize - 1, $bgcol );
$im->alphaBlending(1);

binmode STDOUT;
print "Content-type: image/png\n\n";
print $im->png;

sub colourARGB($$$$) {
my $alpha = shift; my $red = shift;
my $green = shift; my $blue = shift;
# Alpha is in range 0 (opaque) to 127 (fully transparent),
# R, G, B in range 0 .. 255. Force values into range.
$alpha &= 0x7f; $red &= 0xff;
$green &= 0xff; $blue &= 0xff;
return $alpha << 24 | $red << 16 | $green << 8 | $blue;
}


But I cannot seem to find out how to manipulate an existing image to make it
semi-opaic. I tried like this:

#!/usr/bin/perl -w
use GD;
my $im; # The Image object
my $bgcol = colourARGB( 50, 200, 200, 200 );
$im = newFromPng GD::Image('top.png');
$im->saveAlpha(1);
$im->alphaBlending(0);
binmode STDOUT;
print "Content-type: image/png\n\n";
print $im->png;

sub colourARGB($$$$) {
my $alpha = shift; my $red = shift; my $green = shift; my $blue =
shift;
# Alpha is in range 0 (opaque) to 127 (fully transparent),
# R, G, B in range 0 .. 255. Force values into range.
$alpha &= 0x7f; $red &= 0xff; $green &= 0xff; $blue &= 0xff;
return $alpha << 24 | $red << 16 | $green << 8 | $blue;
}


The image displays ok, but I can't see how to add the opacity in.
Thanks for any tips,

richard
 
Reply With Quote
 
 
 
 
Sisyphus
Guest
Posts: n/a
 
      05-19-2005

"Richard Bennett" <(E-Mail Removed)> wrote

>
> I can make an image which does the right thing when I create a new image
> like this:
>
> #!/usr/bin/perl -w
> use GD;
> my $im; # The Image object
> my $xsize = 160; my $ysize = 160;
> my $bgcol = colourARGB( 70, 100, 255, 255 );
> $im = new GD::Image->newTrueColor( $xsize, $ysize )
> || die "$0: Failed to create image -- $!\n";
> $im->saveAlpha(1);
> $im->alphaBlending(0);
> $im->filledRectangle( 0, 0, $xsize - 1, $ysize - 1, $bgcol );
> $im->alphaBlending(1);
>
> binmode STDOUT;
> print "Content-type: image/png\n\n";
> print $im->png;
>
> sub colourARGB($$$$) {
> my $alpha = shift; my $red = shift;
> my $green = shift; my $blue = shift;
> # Alpha is in range 0 (opaque) to 127 (fully transparent),
> # R, G, B in range 0 .. 255. Force values into range.
> $alpha &= 0x7f; $red &= 0xff;
> $green &= 0xff; $blue &= 0xff;
> return $alpha << 24 | $red << 16 | $green << 8 | $blue;
> }
>
>
> But I cannot seem to find out how to manipulate an existing image to make

it
> semi-opaic. I tried like this:
>
> #!/usr/bin/perl -w
> use GD;
> my $im; # The Image object
> my $bgcol = colourARGB( 50, 200, 200, 200 );
> $im = newFromPng GD::Image('top.png');
> $im->saveAlpha(1);
> $im->alphaBlending(0);
> binmode STDOUT;
> print "Content-type: image/png\n\n";
> print $im->png;
>
> sub colourARGB($$$$) {
> my $alpha = shift; my $red = shift; my $green = shift; my $blue =
> shift;
> # Alpha is in range 0 (opaque) to 127 (fully transparent),
> # R, G, B in range 0 .. 255. Force values into range.
> $alpha &= 0x7f; $red &= 0xff; $green &= 0xff; $blue &= 0xff;
> return $alpha << 24 | $red << 16 | $green << 8 | $blue;
> }
>


In the second script you set $bgcol to a value ...... but then, afaict,
$bgcol doesn't get used. Why is that variable (and the subroutine that sets
its value) included in the script ? Didn't you get a warning that $bgcol was
used only once in the script ?

I don't know much about GD and opacity - perhaps those questions are totally
irrelevant to the problem. I wondered about that when I saw your post on
c.l.p.modules .... and I'm still wondering

Do you have a demo script that demonstrates the effect you're after - only
it prints the result to a png file rather than to stdout ? (I really don't
want to be stuffing around with demos that require a web server to view -
which is another reason that I didn't look too hard at your c.l.p.modules
post.) I tried modifying the first of the 2 scripts that you provided so
that it printed to a png file, but all I see is a pale blue square - and
that doesn't tell me much about the effect that you're seeking.

Cheers,
Rob


 
Reply With Quote
 
 
 
 
Sisyphus
Guest
Posts: n/a
 
      05-19-2005

"Sisyphus" <(E-Mail Removed)> wrote in message
news:428c76b7$0$4655$(E-Mail Removed) ...

> I tried modifying the first of the 2 scripts that you provided so
> that it printed to a png file, but all I see is a pale blue square - and
> that doesn't tell me much about the effect that you're seeking.
>


I think I finally worked out what you're after - not entirely your fault
that it required effort on my part
The following script seems to do the job for me. It prints to file
(opacity2.png) rather than stdout and it uses the same value for $alpha as
was used in your original posting.

use warnings;
my $im2 = newFromPng GD::Image('top.png', 1);
$im2->saveAlpha(1);
$im2->alphaBlending(0);

my $alpha_val = (70 & 0x7f) << 24;
for my $x(0..$xsize-1) {
for my $y(0..$ysize-1) {
$index = $im2->getPixel($x,$y);
$index |= $alpha_val;
$im2->setPixel($x,$y,$index);
}
}

open(PNG2, ">opacity2.png") or die "Can't open opacity2.png for writing:
$!";
binmode PNG2;
print PNG2 $im2->png;
close(PNG2) or die "Can't close opacity2.png after writing: $!";

__END__

Cheers,
Rob


 
Reply With Quote
 
Richard Bennett
Guest
Posts: n/a
 
      05-20-2005
Sisyphus wrote:

> use warnings;
> my $im2 = newFromPng GD::Image('top.png', 1);
> $im2->saveAlpha(1);
> $im2->alphaBlending(0);
>
> my $alpha_val = (70 & 0x7f) << 24;
> for my $x(0..$xsize-1) {
> for my $y(0..$ysize-1) {
> $index = $im2->getPixel($x,$y);
> $index |= $alpha_val;
> $im2->setPixel($x,$y,$index);
> }
> }
>
> open(PNG2, ">opacity2.png") or die "Can't open opacity2.png for writing:
> $!";
> binmode PNG2;
> print PNG2 $im2->png;
> close(PNG2) or die "Can't close opacity2.png after writing: $!";
>
> __END__


Hi,
Thanks a lot for that. It looks like your code should work, but it doesn't
for me...
Firstly it seems that $xsize and $ysize are not actually being set
anywhere... I added:
($xsize,$ysize) = $im2->getBounds();

but it still didn't work...
The PNG is being output OK, it's not translucent though.
The idea is that this PNG is positioned over another image in an HTML page,
and the other image will show through the translucent PNG.
This is a test.html page:
<html><body>
<img style="position:absolute;left:0px;top:0px;" src="/map.png" />
<img style="position:absolute;left:0px;top:0px;" src="opacity2.png" />
</body></html>

if you use the original light-blue square I had, you will see map.png (or
any image you put in as background) will show through the blue square
faintly.

Here's an example of a translucent PNG:
http://marginalhacks.com/Hacks/album.../Overlay.1.png

It looks like your code does what I want, but it doesn't seems to work...

Thanks again for your help,

Richard.








 
Reply With Quote
 
Sisyphus
Guest
Posts: n/a
 
      05-20-2005

"Richard Bennett" <(E-Mail Removed)> wrote in message
news:428d2890$0$16290$(E-Mail Removed)...
> Sisyphus wrote:
>
> > use warnings;
> > my $im2 = newFromPng GD::Image('top.png', 1);
> > $im2->saveAlpha(1);
> > $im2->alphaBlending(0);
> >
> > my $alpha_val = (70 & 0x7f) << 24;
> > for my $x(0..$xsize-1) {
> > for my $y(0..$ysize-1) {
> > $index = $im2->getPixel($x,$y);
> > $index |= $alpha_val;
> > $im2->setPixel($x,$y,$index);
> > }
> > }
> >
> > open(PNG2, ">opacity2.png") or die "Can't open opacity2.png for writing:
> > $!";
> > binmode PNG2;
> > print PNG2 $im2->png;
> > close(PNG2) or die "Can't close opacity2.png after writing: $!";
> >
> > __END__

>
> Hi,
> Thanks a lot for that. It looks like your code should work, but it doesn't
> for me...
> Firstly it seems that $xsize and $ysize are not actually being set
> anywhere... I added:
> ($xsize,$ysize) = $im2->getBounds();
>


Serves me right for cutting and pasting .... and *then* altering. I always
think that I can do that correctly .... but I often fail. (Sorry 'bout
that - I should know better.)

> but it still didn't work...
> The PNG is being output OK, it's not translucent though.
> The idea is that this PNG is positioned over another image in an HTML

page,
> and the other image will show through the translucent PNG.
> This is a test.html page:
> <html><body>
> <img style="position:absolute;left:0px;top:0px;" src="/map.png" />
> <img style="position:absolute;left:0px;top:0px;" src="opacity2.png" />
> </body></html>
>


How about, instead of creating the overlay as a file, you create it on the
fly - which, I think, is what you wanted to do anyway:

use warnings;
my $im2 = newFromPng GD::Image('top.png', 1);
$im2->saveAlpha(1);
$im2->alphaBlending(0);

($xsize,$ysize) = $im2->getBounds();

my $alpha_val = (70 & 0x7f) << 24;
for my $x(0..$xsize-1) {
for my $y(0..$ysize-1) {
$index = $im2->getPixel($x,$y);
$index |= $alpha_val;
$im2->setPixel($x,$y,$index);
}
}

binmode STDOUT;
print "Content-type: image/png\n\n";
print $im2->png;
__END__

The aim, as I now understand it, is to display top.png as a translucent
overlay. You probably can't do that by using "opacity2.png" - instead you
need to create the image on the fly (as per your original script). Hopefully
the above does that ... I'm curious now ... so I'll probably get around to
firing up my web server so that I can see for myself.

Cheers,
Rob


 
Reply With Quote
 
Richard Bennett
Guest
Posts: n/a
 
      05-20-2005
Sisyphus wrote:
> use warnings;
> my $im2 = newFromPng GD::Image('top.png', 1);
> $im2->saveAlpha(1);
> $im2->alphaBlending(0);
>
> ($xsize,$ysize) = $im2->getBounds();
>
> my $alpha_val = (70 & 0x7f) << 24;
> for my $x(0..$xsize-1) {
> for my $y(0..$ysize-1) {
> $index = $im2->getPixel($x,$y);
> $index |= $alpha_val;
> $im2->setPixel($x,$y,$index);
> }
> }
>
> binmode STDOUT;
> print "Content-type: image/png\n\n";
> print $im2->png;
> __END__
>
> The aim, as I now understand it, is to display top.png as a translucent
> overlay. You probably can't do that by using "opacity2.png" - instead you
> need to create the image on the fly (as per your original script).
> Hopefully the above does that ... I'm curious now ... so I'll probably get
> around to firing up my web server so that I can see for myself.


hi,
Yep, it works. In fact, you can also output to file - that works too. The
only thing I was still doing wrong was to load an 8bit PNG. The script only
works if you load a 24bit image.
That's fine for me, as the images I want to process are fullcolor, but a
possible improvement would be to resample the image as fullcolor.
The 1 or 0 flag in newFromPng does prevent a 24bit image from working, when
set to 0, but doesn't convert an 8bit image to fullcolor when set to 1.

Anyway, you helped me a lot with that double loop, there's so little example
code for gd.pm, I doubt I would have found that myself.

Richard.











 
Reply With Quote
 
Sisyphus
Guest
Posts: n/a
 
      05-20-2005

"Richard Bennett" <(E-Mail Removed)> wrote
> hi,
> Yep, it works. In fact, you can also output to file - that works too.


Heh .... I eventually got round to starting Apache and writing a cgi script
so that I could view these images that were created on the fly. I ran the
first of the 2 scripts that you posted, and I can see that the image gets
paler as $alpha is increased, but there's definitely no translucence there
for me. It is definitely opaque. Anyway ... the aim was to get it working
for you, and I can live without finding out the whole story

> The only thing I was still doing wrong was to load an 8bit PNG. The script

only
> works if you load a 24bit image.
> That's fine for me, as the images I want to process are fullcolor, but a
> possible improvement would be to resample the image as fullcolor.
> The 1 or 0 flag in newFromPng does prevent a 24bit image from working,

when
> set to 0, but doesn't convert an 8bit image to fullcolor when set to 1.
>
> Anyway, you helped me a lot with that double loop, there's so little

example
> code for gd.pm, I doubt I would have found that myself.
>


It may well be that the double loop can be replaced by something a little
neater - that was just the first way I found of giving every pixel that
additional aplha value.

Cheers,
Rob


 
Reply With Quote
 
Richard Bennett
Guest
Posts: n/a
 
      05-20-2005
Sisyphus wrote:

>
> "Richard Bennett" <(E-Mail Removed)> wrote
>> hi,
>> Yep, it works. In fact, you can also output to file - that works too.

>
> Heh .... I eventually got round to starting Apache and writing a cgi
> script so that I could view these images that were created on the fly. I
> ran the first of the 2 scripts that you posted, and I can see that the
> image gets paler as $alpha is increased, but there's definitely no
> translucence there for me. It is definitely opaque.

You are testing with a browser like Firefox? IE doesn't support this effect.
Also, you have to layer the generated image over another one, to see it
showing through.

here's an example of the output of the last version of the script;
http://212.23.52.148/cgi-bin/img4.pl

of course it just looks pale, but if you display it over something else the
background shows through.

Thanks again,

richard.



 
Reply With Quote
 
Sisyphus
Guest
Posts: n/a
 
      05-21-2005

"Richard Bennett" <(E-Mail Removed)> wrote in message
news:428dcfd6$0$21652$(E-Mail Removed)...
> Sisyphus wrote:


> > Heh .... I eventually got round to starting Apache and writing a cgi
> > script so that I could view these images that were created on the fly. I
> > ran the first of the 2 scripts that you posted, and I can see that the
> > image gets paler as $alpha is increased, but there's definitely no
> > translucence there for me. It is definitely opaque.

> You are testing with a browser like Firefox? IE doesn't support this

effect.
> Also, you have to layer the generated image over another one, to see it
> showing through.
>


Aaah - I was layering the generated image over another one ... but looking
at it with IE

Cheers,
Rob


 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off




Advertisments