In Imagick (PHP), how can i negate without changing the alpha (transparent)? - php

In Imagick, when i use "negateImage" in images with alpha channel (png), the transparency is not well handled by imagick. I want to keep the transparency, only negate the "colored" pixels.
Origin image
Desired image
How can i do it?

Try specifying the specific channels that you want to negate:
$imagick->negateImage(false, imagick::CHANNEL_RED | imagick::CHANNEL_GREEN | imagick::CHANNEL_BLUE);
The above assumes an RGB image.

Related

PHP Imagick (ImageMagick) RGB > CMYK with Flat Black

I'm using PHP Imagick to convert PNG images generated in PhantomJS to TIF CMYK,
for print purposes I need a flat Black (cmyk - 0,0,0,100) - the conversion generates blacks like (cmyk - 58,49,44,89).
I'm converting the images using color profile (section of my code below) -> the code is based on Convert image from RGB to CMYK with Imagick
is it possible to force a flat black with Imagick ? do you know any other tools that might help ?
thanks,
if ($has_icc_profile === false) {
$icc_rgb = file_get_contents( '/srgb_profiles' . '/sRGB.icc');
$image->profileImage('icc', $icc_rgb);
unset($icc_rgb);
}
// then we add an CMYK profile
$icc_cmyk = file_get_contents( '/cmyk_profiles'.'/JapanColor2002Newspaper.icc');
$image->profileImage('icc', $icc_cmyk);
UPDATE :
after checking online I think I'm looking for a UCR en.wikipedia.org/wiki/Under_color_removal method for ImageMagick - I found that convert old versions supported under color removal
-undercolor <undercolor factor>x<black-generation factor>
control undercolor removal and black generation on CMYK images.
This option enables you to perform undercolor removal and black generation on CMYK images-- images to be printed on a four-color printing system. You can con- trol how much cyan, magenta, and yellow to remove from your image and how much black to add to it. The standard undercolor removal is 1.0x1.0. You'll frequently get better results, though, if the percentage of black you add to your image is slightly higher than the percentage of C, M, and Y you remove from it. For example you might try 0.5x0.7. (http://www.chemie.fu-berlin.de/chemnet/use/suppl/imagemagick/www/convert.html) -
apparently the option is not supported anymore, I'm interested if anyone knows if UCR is the solution I'm looking for and if anyone knows if it's supported or if I'm supposed to use a different method to get the same result.
If you use ImageMagick's convert at the command line like this to generate a grayscale ramp, 1 pixel wide and 256 pixels tall, going from white to black and convert it to CMYK colorspace and then show it as text, you get what you want:
convert -size 1x256 'gradient:rgb(255,255,255)-rgb(0,0,0)' -colorspace cmyk txt:
# ImageMagick pixel enumeration: 1,256,65535,cmyk
0,0: (0%,0%,0%,0%) #0000000000000000 cmyk(0,0,0,0)
0,1: (0%,0%,0%,0.392157%) #0000000000000101 cmyk(0,0,0,1)
0,2: (0%,0%,0%,0.784314%) #0000000000000202 cmyk(0,0,0,2)
0,3: (0%,0%,0%,1.17647%) #0000000000000303 cmyk(0,0,0,3)
0,4: (0%,0%,0%,1.56863%) #0000000000000404 cmyk(0,0,0,4)
0,5: (0%,0%,0%,1.96078%) #0000000000000505 cmyk(0,0,0,5)
0,6: (0%,0%,0%,2.35294%) #0000000000000606 cmyk(0,0,0,6)
0,7: (0%,0%,0%,2.7451%) #0000000000000707 cmyk(0,0,0,7)
0,8: (0%,0%,0%,3.13725%) #0000000000000808 cmyk(0,0,0,8)
0,9: (0%,0%,0%,3.52941%) #0000000000000909 cmyk(0,0,0,9)
0,10: (0%,0%,0%,3.92157%) #0000000000000A0A cmyk(0,0,0,10)
...
...
0,249: (0%,0%,0%,97.6471%) #000000000000F9F9 cmyk(0,0,0,249)
0,250: (0%,0%,0%,98.0392%) #000000000000FAFA cmyk(0,0,0,250)
0,251: (0%,0%,0%,98.4314%) #000000000000FBFB cmyk(0,0,0,251)
0,252: (0%,0%,0%,98.8235%) #000000000000FCFC cmyk(0,0,0,252)
0,253: (0%,0%,0%,99.2157%) #000000000000FDFD cmyk(0,0,0,253)
0,254: (0%,0%,0%,99.6078%) #000000000000FEFE cmyk(0,0,0,254)
0,255: (0%,0%,0%,100%) #000000000000FFFF cmyk(0,0,0,255)
You must be doing something different - maybe this will help you work it out. I am guessing it is your ICC profiles but you can experiment with the above command.
If you just want to experiment with spot values, you can just have IM translate a single pixel like this:
convert -size 1x1 xc:#000000 -colorspace cmyk txt:
# ImageMagick pixel enumeration: 1,1,65535,cmyk
0,0: (0%,0%,0%,100%) #000000000000FFFF cmyk(0,0,0,255)
or maybe more simply like this:
convert -size 1x1 xc:#000000 -depth 8 -colorspace cmyk txt:
# ImageMagick pixel enumeration: 1,1,255,cmyk
0,0: (0,0,0,255) #000000FF cmyk(0,0,0,255)
Note the following though:
You must put profiles between input image and output image names on the command line.
If your image has no embedded profile, the first profile you give is applied to the input image and the second to the output image. If your input image does have a profile, the first profile you give is applied to the output image.

Partial black background when watermarking PNG image with GD PHP

I have pieced together a PHP class to perform various image related functions using GD functions of PHP.
It works great for all image types. Rotate, flip, resize, crop and to a lesser extent, watermark.
All but the latter work perfectly. For example after a few changes, rotated PNG images retained their transparency whereas before they were losing that and the background turning black. Common problem, it appears. But all working now.
Where I'm still getting stuck is watermarking a PNG image with another PNG image. It appears to work fine with JPG and other images. This is the code (simplified):
public function writeWatermarkSimple()
{
$watermarkFile = 'watermark.png';
$watermarkImage = imagecreatefrompng($watermarkFile);
imagealphablending($watermarkImage, false);
imagesavealpha($watermarkImage, true);
$imageFile = 'image.png';
$baseImage = imagecreatefrompng($imageFile);
imagealphablending($baseImage, false);
imagesavealpha($baseImage, true);
$marginH = imagesx($baseImage) - imagesx($watermarkImage);
$marginV = imagesy($baseImage) - imagesy($watermarkImage);
$cut = imagecreatetruecolor(imagesx($watermarkImage), imagesy($watermarkImage));
imagecopy($cut, $baseImage, 0, 0, $marginH, $marginV, imagesx($watermarkImage), imagesy($watermarkImage));
imagecopy($cut, $watermarkImage, 0, 0, 0, 0, imagesx($watermarkImage), imagesy($watermarkImage));
imagecopymerge($baseImage, $cut, $marginH, $marginV, 0, 0, imagesx($watermarkImage), imagesy($watermarkImage), 80);
if (!imagepng($baseImage, 'watermarked_image.png'))
{
return false;
}
return true;
}
This has been pieced together with various guides and advice people have given based on a similar issue. Again, working perfectly with JPG images and PNG watermarks, but not PNG & PNG.
Some example images:
http://i.imgur.com/hHRWinj.png - This is the watermark I'm using.
http://i.imgur.com/6sy8Ncs.png - This is the image I'm applying the watermark to.
http://i.imgur.com/ghovYLm.png - This is the end result.
The bit I find interesting is that any part of the watermark that is overlaid on a non-transparent portion of the image is working fine. Just the rest of it has the black background.
This leads me to believe I'm close, and I hope that the expertise of you fine people may lead me to the solution.
Thanks ever so for reading.
So, I'm not giving up on finding the correct answer to do this using GD. However, I was overjoyed to find that what needed up to 30 lines of code with GD can be achieved using much less with ImageMagick:
$image = new Imagick();
$image->readimage($this->_image);
$watermark = new Imagick();
$watermark->readimage($this->_watermark->_getImage());
$watermark->evaluateImage(Imagick::EVALUATE_DIVIDE, 2, Imagick::CHANNEL_ALPHA);
$image->compositeImage($watermark, imagick::COMPOSITE_OVER, $marginH, $marginV);
So this is before (with GD):
http://i.imgur.com/AlS0TcO.png
And after (with ImageMagick and the code above):
http://i.imgur.com/zBxlC3R.png
If anyone has an answer that is purely GD then I'd be immensely grateful.
Ran into some similar issues recently and while this may not exactly solve your problem, these were some useful discoveries that I made.
In my case, I have an original .jpg image and a watermark .png image. The watermark image has a fully transparent background. I wanted to specify the opacity in my script and have it change the watermark opacity before placing it on top of the origina image. Most posts out there regarding PHP watermarking assume that the original watermark .png file already has the solid watermark portion set to the correct opacity rather than changing it via the script.
gd didn't like a 24 bit .png and caused some goofy issues. Switching to 8 bit resolved that with gd. On the other hand, imagick works very well with a 24 bit .png and the final result seems to be better.
For me, using gd worked just fine if I was opening the original watermark .png and using imagecopymerge() to set the watermark transparency. If however I tried to scale the original watermark .png (which has transparent background) first, then I would get similar results as you with black or white background portion of where watermark image is. See How do I resize pngs with transparency in PHP? for a partial solution by filling the new wm image with transparent rectangle first. For me this still produced an opaque white background on the final result no matter what I tried.
I switched to imagick and was using setImageOpacity() to change the transparency of my watermark .png before applying it on top of my original image and I was still getting the same effect with a black background. Finally read in the PHP doc for setImageOpacity() that if the original .png has any transparent pixels and you try to lower the opacity, those pixels become opaque (black) with the new transparency applied. Instead, need to use the evaluateImage() function. This will instead evaluate each pixel's alpha channel only and divide by the specifid number.
I assume the black / white background issue with gd is likely due to similar ways that it treats alpha channels when scaling / combining as compared to imagick and if you want to do it all in gd you just need to find some similar way to evaluate and manipulate the alpha channel per-pixel because the "easy" ways seem to take an already transparent background and make it opaque.
So, the solution:
Assuming you want to apply your watermark at an opacity of 45% and you're using imagick, then instead of this:
$watermark->setImageOpacity(.45);
do this
$watermark->evaluateImage(Imagick::EVALUATE_DIVIDE, (1/.45), Imagick::CHANNEL_ALPHA);
You need to divide 1 by your opacity to get the demoninator by which the function will divide the alpha channel value for each pixel. In this case, 1/.45 = 2.2222, so then the function will divide the alpha channel of each pixel by 2.2222. This means a solid pixel (alpha of 1) would result in 1/2.2222 or .45 alpha or transparency when finished. Any pixels that were already transparent (alpha 0) would stay transparent because 0 divided by anything is always what? Zero!
After you change the watermark transparency then you can use compositeImage() to merge the watermark onto the original image.

How to white pad/border an image with magickwand?

I have an image that is 180x240 and I want to pad/border it with white until it fits the size 360x240, so the original content from image won't get distort.
http://www.magickwand.org/ - I can't find any suggestive function in the documentation
I do not use Magickwand but with Imagemagick there is an operator called extent which does what you want. But I can not see any mention of extent in the documentation you linked.
You may have to create a white canvas of 360x240 and composite your image onto it.
Alternativly could you use MagickBorderImage and have the border set to 0 or 1 on the height and 90 on the width?

How to rotate an image in GD Image Library while keeping transparency?

I'm making a skin previewer for my site; I need to rotate parts of an image to create a representation of this for my users to see.
The skin is a PNG file, and all parts of it may have transparency or even none at all.
I need to be able to rotate this image while keeping any transparency inside the image transparent, while also having the extended borders (You know, the area that wasn't part of the image before it was rotated) transparent.
All of my attempts have left a black border around the image itself.
Any help?
Cut out the piece of the image you want to rotate
Rotate preserving alpha using something like this http://www.exorithm.com/algorithm/view/rotate_image_alpha
Merge back in preserving alpha using the following:
-
imagesetbrush($destimg, $srcimg);
// x, y are the center of target paste location
imageline($destimg, $x, $y, $x, $y, IMG_COLOR_BRUSHED);
I use that to rotate a PNG and preserve transparency color. Works like a charm. It's "basic GD".
$rotation = 135;
$handle_rotated = imagerotate($handle_not_rotated,$rotation,0);
imagealphablending($handle_rotated, true);
imagesavealpha($handle_rotated, true);
Don't know if it's what you're looking for?
You may want to check here for some uses for libpng (which will need zlib). If you are on linux you can write something in perl. CPAN GD module might be your ticket.

PHP: Merging images into an alpha translucent image with GD

I'm trying to create an image with varying level of transparency, using GD. But I can get only fully transparent or fully opaque pixels in the image.
What I want to get: What I actually get:
(source: bx.at.ua)
(source: bx.at.ua)
(source: bx.at.ua)
(source: bx.at.ua)
Here's a piece of the code I used to create images like this one ▲ fixed code:
$im=imagecreatetruecolor($sx,$sy);
imageantialias($im,true);
imagesavealpha($im,true);
$c00FF00=imagecolorallocate($im,0,255,0);
$cFFFFFF=imagecolorallocate($im,255,255,255);
$cFFFFFF_00=imagecolorallocatealpha($im,255,255,255,127);
imagecolortransparent($im,$cFFFFFF);
imagefilledrectangle($im,0,0,$sx,$sy,$cFFFFFF$cFFFFFF_00);
$sim=imagecreatefrompng('gradient.png');
imagecopy($im,$sim,$dest_x,$dest_y,0,0,imagesx($sim),imagesy($sim));
imagedestroy($sim);
imagettftext($im,$size,0,$text_x,$text_y,$c00FF00,$font,'Test');
header('Content-type: image/png');
imagepng($im);
imagedestroy($im);
What can I do to get the desired (translucent) result?
You need to call imagesavealpha() against your imported PNG ($sim) before merging, as well as against the final image.
What you are looking for is not transparency but alpha. Alpha is another color channel that goes along with the red, green and blue colors to determine the transparency level (just transparent is visible or not as opposed to being able to set the level of transparency). Check out imagecolorallocatealpha

Categories