skip to Main Content

I need to change each hue of yellow to blue, and each hue of dark gray to light gray in PNG images with transparency.

The problem is:

I can’t use Photoshop, because I have 100 images, and I need to change hues many time.
I can’t use Image Magick, because I need more sophisticated calculations, than ‘-fx’ can do.
I can’t use PHP imagefrompng(), because this nasty crap not works with a lot of my images,
even with all suggested fixes like:

$background = imagecolorallocate($png, 255, 255, 255);
// removing the black from the placeholder
imagecolortransparent($png, $background);
// turning off alpha blending (to ensure alpha channel information is preserved, rather than removed (blending with the rest of the image in the form of black))
imagealphablending($png, true);
// turning on alpha channel information saving (to ensure the full range of transparency is preserved)
imagesavealpha($png, true);

and so on. It works with some images, but not with others.

All I need is a PNG library (maybe not in PHP), that can give me red, green, blue and alpha component of a pixel at coordinates x, y, and then set this pixel after my calculations, eg:

$rgba = getrgba($image, $x, $y);
$rgba = my_function($rgba);
setrgba($image, $x, $y, $rgba);

Maybe you can suggest libraries in other languages, not only PHP?

2

Answers


  1. If you don’t mind using Python check out Pillow, specifically its PixelAccess class. These threads (1, 2) should be helpful and have some code examples.

    Login or Signup to reply.
  2. Method 1

    If you just want to get at the raw pixel values of R,G,B and Alpha without worrying about compression and encoding, use ImageMagick to convert your image to plain, uncompressed, unencoded binary and read it and process it to your heart’s content.

    So, if we make a 1×1 pixel PNG file with RGBA(0,64,255,0.5) to test with:

    convert -size 1x1 xc:"rgba(0,64,255,0.5)" a.png
    

    Now we can get ImageMagick to make a raw, RGBA file that you can read and process as you wish with whatever language you wish at whatever level of complexity that you wish:

    convert a.png rgba:data.bin
    

    and now we can look in that file:

    xxd data.bin
    

    Result

    0000000: 0040 ff80                                .@..
    

    There you can see and read all the RGBA pixels. When you are finished, just do the opposite to get back a PNG – note that you must tell ImageMagick the size first since it cannot know this:

    convert -size 1x1 rgba:data.bin new.png
    

    Note that ImageMagick is quite a large package to install, and you can achieve much the same as the above with the much lighter-weight vips package:

    vips VipsForeignSaveRaw a.png data.rgb
    

    Method 2

    Alternatively, if you want your data as uncompressed, human-readable ASCII, use the venerable NetPBM formats of PPM (Portable Pixmap) and PGM (Portable Greymap) – see NetPBM on Wikipedia.

    Make a 4×1 image and write as PPM:

    convert -size 4x1 xc:"rgba(0,64,255,0.1)" -compress none ppm:-
    P3
    4 1
    65535
    0 16448 65535 0 16448 65535 0 16448 65535 0 16448 65535
    

    You can see the 4 repeated RGB values there hopefully. If you want it as a file, just change the ppm:- at the end with someFile.ppm.

    Make same image again and extract Alpha channel to separate file:

    convert -size 4x1 xc:"rgba(0,64,255,0.1)" -alpha extract -compress none pgm:-
    P2
    4 1
    65535
    6554 6554 6554 6554 
    

    Hopefully you can see that 6554 is 0.1 on a scale of 0-65535.

    If you just want 8-bit data on any of the above, add in -depth 8.

    Method 3

    As Glenn suggests in the comments, another option is to omit the -compress none on Option 2 which will give you a very similar file format except the pixel data will be in binary, after the header which remains in ASCII. This is generally faster and smaller.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search