Beefy Boxes and Bandwidth Generously Provided by pair Networks
The stupid question is the question not asked
 
PerlMonks  

Re^2: GD colorAllocate not changing colour

by Bod (Parson)
on May 16, 2021 at 11:41 UTC ( [id://11132655]=note: print w/replies, xml ) Need Help??


in reply to Re: GD colorAllocate not changing colour
in thread GD colorAllocate not changing colour

So, you bought a can of white color and a brush, but for some strange reason, the walls of the room you are standing in still show a nasty 1960s style flower decor. What has gone wrong?

OK - so the handyman has been summoned and instructed to use the brush to put the paint on the wall:

my $white; # Create background my $image = new GD::Image(600, 450); $white = $image->colorAllocate(255, 255, 255); $image->filledRectangle(0, 0, 600, 450, $white);
The wall looks much better in white than it did in the 1960's flower decor. However, much to the handyman's frustration, I've decided that for testing purposes I don't want white or black and will have grey instead. Grey makes it easy to know the black has gone without the white blending into the background:
$white = $image->colorAllocate(127, 127, 127); $image->filledRectangle(0, 0, 600, 450, $white);
Calling the grey $white ensures that the handyman knows he has to return the grey wall back to white someday!

Now that there is a nice grey wall we can look at it and check it is indeed grey:

open my $fh, '>' ,"$root/images/property/unit/$filename.png"; binmode $fh; print $fh $image->png; close $fh;
And yes, it is grey as expected :)

Next we get the handyman to take the picture that was hanging on the wall and resize it to it is 600px wide. Being good with a tape measure and a saw, our handyman is able to resize the picture without altering it's aspect ratio:

# Resize uploaded image to 600 wide my $picture = GD::Image->new($file{'image', 'file'}); my ($srcw, $srch) = $picture->getBounds(); $newh = int ($srch * 600 / $srcw); my $resize = GD::Image->new(600, $newh); $resize->copyResized($picture, 0, 0, 0, 0, 600, $newh, $srcw, $srch);
Despite having lots of faith in our handyman it's still a good idea to check his work occasionally...
open my $fh, '>' ,"$root/images/property/unit/$filename.png"; binmode $fh; print $fh $resize->png; close $fh;
And sure enough his tape measure and sawing skills live up to expectations and he has created a perfect resized picture all ready for the newly painted grey wall.

Now for the final part of the redecoration. All that is left is to hang the picture of the wall and we are done.

# Copy onto background image offset to crop or center $image->copy($resize, 0, 0, 0, ($newh - 450) / 2, 600, 450);
All done but let's have a quick check again before the hammer is put away...
open my $fh, '>' ,"$root/images/property/unit/$filename.png"; binmode $fh; print $fh $image->png; close $fh;
Oh no!
What's happened...it must be alchemy...

As if by magic, the nice grey wall has turned into a black wall. Far better than the 1960's flower pattern but still not the lovely shade of grey that we tried so hard to use to paint the wall.

Replies are listed 'Best First'.
Re^3: GD colorAllocate not changing colour
by afoken (Chancellor) on May 16, 2021 at 16:53 UTC
    As if by magic, the nice grey wall has turned into a black wall.

    What image formats do you use? I see you are writing a PNG, that can be both a paletted image and a non-paletted image. What formats do you read?

    (On palettes: A paletted image has a small array of colors, usually 24 bit RGB colors, and usually not more than 256 color entries. Each pixel is stored as an array index, typically one byte. A non-paletted image stores the color information directly in the pixel data, using 3 or 4 bytes per pixel.)

    "Magic" color changes usually happen with paletted images, especially if the tool is too simple-minded, or when you run out of palette entries. What happens is that the palette is silently modified or the color allocation fails because the palette array is full. Try to use non-paletted images, i.e. make sure GD is in "true color" mode. Call isTrueColor() on your GD objects, should return true. Pass a true value for the optional truecolor parameter to the GD constructors. That way, paletted images are automatically upgraded to non-paletted mode (as far as I understand GD.)

    Alexander

    --
    Today I will gladly share my knowledge and experience, for there are no sweeter words than "I told you so". ;-)
      > Pass a true value for the optional truecolor parameter to the GD constructors..

      ..or simply force truecolor with the class method

      use GD 2.0.33; GD::Image->trueColor(1);

      Infact:

      > For backwards compatibility with scripts previous versions of GD, new images created from scratch (width, height) are palette based by default.

      L*

      There are no rules, there are no thumbs..
      Reinvent the wheel, then learn The Wheel; may be one day you reinvent one of THE WHEELS.
      What image formats do you use? I see you are writing a PNG, that can be both a paletted image and a non-paletted image. What formats do you read?

      I don't know why the output is PNG. As I said in the original question, this is old code that is being refactored. As the images are all real pictures of properties and the like, it would be much better if they were JPGs but that means changing lots of other code where they are read. I will be changing all the PNG files to JPG files, probably manually, and then updating the code that reads the files then revisiting this code that writes them to ensure in future everythings is JPG. But that's for another time.

      The input file is a stream from a website upload. The format could be any image format although practically it is likely to be a JPG as most of them will have originated from a digital camera which mostly produce JPG files.

      Call isTrueColor() on your GD objects, should return true

      A call of $image->isTrueColor() immediately before writing to the file does indeed return true.

        Please note that once a file is loaded inside a GD object, is no more a jpg nor a png: it is loaded into an internal GD format and it is up to you to write it to disk in the desired format.

        Also note that saving to png allows you to specify a compression in the range:

        > 0-9, where 0 means no compression (largest files, highest quality) and 9 means maximum compression (smallest files, worst quality). A compression level of -1 uses the default compression level selected when zlib was compiled on your system, and is the same as calling png() with no argument.

        L*

        There are no rules, there are no thumbs..
        Reinvent the wheel, then learn The Wheel; may be one day you reinvent one of THE WHEELS.
Re^3: GD colorAllocate not changing colour -- working example
by Discipulus (Canon) on May 16, 2021 at 19:05 UTC
    Hello Bod,

    letting apart the humor (which incidentally make your post harder to understand for non native english speakers.. :), you never set $resize background to white! I didnt follow all your geometry calculus, but be aware the the default background for a GD image is black:

    perl -MGD -e"$im = new GD::Image(100,100);open $fh,'>','out.jpg';binmo +de $f; print $fh $im->jpeg"

    The above print a nice black image.

    Simplfying the whole I think you can start from something like the following code, which does what you are looking for

    use strict; use warnings; use GD; GD::Image->trueColor(1); # gray image 100x100 my $im_gray = new GD::Image(100,100); my $gray = $im_gray->colorAllocate(127,127,127); $im_gray->filledRectangle(0, 0, 100,100, $gray); open my $fh_gray,'>','gray.jpg'; binmode $fh_gray; print $fh_gray $im_gray->jpeg; # red image 100x100 my $im_red = new GD::Image(100,100); my $red = $im_red->colorAllocate(255,0,0); my $black = $im_red->colorAllocate(0,0,0); $im_red->filledRectangle(0, 0, 100,100, $red); # with a black circle $im_red->ellipse(50,50,100,100,$black); open my $fh_red,'>','red.jpg'; binmode $fh_red; print $fh_red $im_red->jpeg; # copy resized red image scaled 50% and centered inside the gray one $im_gray->copyResized($im_red,25,25,0,0,50,50,100,100); open my $fh_both,'>','both.jpg'; binmode $fh_both; print $fh_both $im_gray->jpeg;

    L*

    There are no rules, there are no thumbs..
    Reinvent the wheel, then learn The Wheel; may be one day you reinvent one of THE WHEELS.
      make your post harder to understand for non native english speakers

      Sorry - so many of the non-English natives on this site use such good English that it is very, very easy to forget it's not your native tongue.

      you never set $resize background to white!

      No I don't. Why would I?
      $resize contains the picture, not the background. Setting the background of the picture turns it white which is not what I want.

      Thanks for the working example. It reinforces that I am (probaly) approaching the problem the right way. However, when I plug in a picture instead of a pattern build in GD it reverts to not setting the background. It seems to be a problem with actual pictures. Connecting that with what afoken has suggested, it seems likely that it is to do with the colour palette of the picture.

Re^3: GD colorAllocate not changing colour
by huck (Prior) on May 16, 2021 at 21:34 UTC

    The problem may be here

    $image->copy($resize, 0, 0, 0, ($newh - 450) / 2, 600, 450);

    gd does nice cropping to viewports but this one may be too much if $newh<450

    if ($newh<450) { $image->copy($resize, 0, (450-$newh ) / 2, 0,0, 600, $newh); } else { $image->copy($resize, 0, 0, 0, ($newh - 450) / 2, 600, 450); ]

    Trying to copy from outside the bounds of the src image may have introduced the black, just a guess

      Trying to copy from outside the bounds of the src image may have introduced the black, just a guess

      If that was just a guess, it was a very good guess...
      Although I suspect it was an educated guess at the very least :)

      Either way, that has worked!
      Thank you very much huck.

      Because the problem was only appearing with a real picture as the image and not a pattern created in GD, it seemed to be a palette issue. The effort had been looking there rather than the way the foreground image is placed on the background...

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: note [id://11132655]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others taking refuge in the Monastery: (4)
As of 2024-04-19 07:04 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found