semi-opacity with GD

Discussion in 'Perl Misc' started by Richard Bennett, May 18, 2005.

  1. 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
     
    Richard Bennett, May 18, 2005
    #1
    1. Advertising

  2. Richard Bennett

    Sisyphus Guest

    "Richard Bennett" <> 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
     
    Sisyphus, May 19, 2005
    #2
    1. Advertising

  3. Richard Bennett

    Sisyphus Guest

    "Sisyphus" <> wrote in message
    news:428c76b7$0$4655$...

    > 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
     
    Sisyphus, May 19, 2005
    #3
  4. 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/Themes/OldPhoto/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.
     
    Richard Bennett, May 20, 2005
    #4
  5. Richard Bennett

    Sisyphus Guest

    "Richard Bennett" <> wrote in message
    news:428d2890$0$16290$...
    > 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
     
    Sisyphus, May 20, 2005
    #5
  6. 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.
     
    Richard Bennett, May 20, 2005
    #6
  7. Richard Bennett

    Sisyphus Guest

    "Richard Bennett" <> 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
     
    Sisyphus, May 20, 2005
    #7
  8. Sisyphus wrote:

    >
    > "Richard Bennett" <> 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.
     
    Richard Bennett, May 20, 2005
    #8
  9. Richard Bennett

    Sisyphus Guest

    "Richard Bennett" <> wrote in message
    news:428dcfd6$0$21652$...
    > 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
     
    Sisyphus, May 21, 2005
    #9
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Nebojsa Dinic

    JPanel transparency (opacity)

    Nebojsa Dinic, Apr 16, 2004, in forum: Java
    Replies:
    0
    Views:
    3,377
    Nebojsa Dinic
    Apr 16, 2004
  2. DU
    Replies:
    13
    Views:
    962
  3. Sentient Fluid

    Opacity

    Sentient Fluid, Apr 22, 2005, in forum: HTML
    Replies:
    0
    Views:
    595
    Sentient Fluid
    Apr 22, 2005
  4. windandwaves

    opacity

    windandwaves, Feb 18, 2006, in forum: HTML
    Replies:
    10
    Views:
    2,308
    Jim Higson
    Feb 26, 2006
  5. James Stroud

    py2app semi-standalone semi-works

    James Stroud, Oct 4, 2006, in forum: Python
    Replies:
    2
    Views:
    737
    James Stroud
    Oct 4, 2006
Loading...

Share This Page