So I have a situtation with ImageMagick and php where I need to processes each of the RGB channels separately and then merge them back together into the final image. So in the code I have below, $red, $green and $blue are the channels (as gray scale images). The following code is what I have tried (and a couple variations) but each time I end up with an image that only has Cyan, Magenta or Yellow showing through. In this case, the resulting image is Cyan.
$im->removeImage();
$im->addImage($red);
$im->addImage($green);
$im->addImage($blue);
$img = $im->combineImages(self::CHANNEL_ALL);
$im->removeImage();
$im->removeImage();
$im->removeImage();
$im->addImage($img);
I think part of my problem is that the PHP documentation doesn't say much about how to use combineImages and there are no samples so far as I can find. So it's very likely that I'm using that particular method incorrectly, and I suspect it has to do with how I am combining the images in the single Imagick object to begin with.
EDIT
This question ultimately boils down to this: How do I recreate the following script using only php?
convert tmp_r.png tmp_g.png tmp_b.png -combine tmp_rgb.png
[EDIT]
I have to admit, looking further into the documentation, Im not sure what the constant CHANNEL_ALL does. They do state that you can concatenate channels by logically ORing them together. You might try:
$im->combineImages(imagick::CHANNEL_RED | imagick::CHANNEL_GREEN | imagick::CHANNEL_BLUE);
[ORIGINAL]
I've been looking into this API, and honestly what I think you are looking for is the convert function, NOT the combine function.
Look At the below provided link and click specifically on "Combining RGB Channel Images"
http://www.imagemagick.org/Usage/color_basics/
Try that, leave a comment if you need further help :-)
So I think I've figured out how to get this to work. The missing piece was a call to flattenImages(). I'm not exactly sure why this worked, but it seems to be what I was looking for. Here's the code (keep in mind that $this is in the context of a member method of a class that extends Imagick):
$this->removeImage(); // gets rid of the old, unprocessed image
$rgb = clone $this;
$rgb->addImage($red);
$rgb->addImage($green);
$rgb->addImage($blue);
$rgb->flattenImages(); // this is what was missing above
$rgb = $rgb->combineImages(self::CHANNEL_ALL);
$this->addImage($rgb);
Can anyone comment on why this might be? I expected flattenImages() to merge the three images into one and destroy some of the information, but it appears that it actually tells ImageMagick to process all of the contained images together whereas it was processing them independently previously.
Try this:
$im->addImage($red);
$im->addImage($green);
$im->addImage($blue);
$im->combineImages(imagick::CHANNEL_RED | imagick::CHANNEL_GREEN | imagick::CHANNEL_BLUE);
btw combineImages doesn't return imagick object, but true/false indicating success or failure, so $im will contain your combined image.
Edit:
Apparently combineImages sucks big time, so here's an alternative: imagick::compositeImage
$im->compositeImage($red, imagick::COMPOSITE_COPY, 0, 0, imagick::CHANNEL_RED);
$im->compositeImage($green, imagick::COMPOSITE_COPY, 0, 0, imagick::CHANNEL_GREEN);
$im->compositeImage($blue, imagick::COMPOSITE_COPY, 0, 0, imagick::CHANNEL_BLUE);
Related
I want to convert a given color to transparency with iMagick. I have found one way to do this, but it behaves like a paint bucket rather than examining the entire image.
For the following example, I'm using this:
$transparentColor = new ImagickPixel('transparent');
$image->floodFillPaintImage($transparentColor, 20000, "#0009c5", 0, 0, false, Imagick::CHANNEL_ALPHA);
This is the input image
This is the output image
The result I'd like to see is all the blue areas turned to transparency. Unfortunately, it seems that "fill" is the key point in this function and hence stops when confronted with non-"target" colors.
Does anyone know how to accomplish turning all the blue areas to transparent using iMagick (not command line imageMagick)?
Thanks in advance!
Try:
$image->transparentPaintImage($targetColor, $alphaLevel, $fuzz, false);
If the transparent areas are "messy", it may help to despeckle:
$image->despeckleimage();
Doc: http://php.net/manual/en/imagick.transparentpaintimage.php
My goal
I have an existing PNG. It currently has anti-aliasing, or in other words, shades of gray. I want the image to be 1 bit, or in other words, only using the colors black and white. My aim is to do this with PHP GD. I have to do this with an existing image, and can not create the image from scratch using imagecreatetruecolor.
What I'm trying
The function I've found that seems best for the job is imagetruecolortopalette
http://php.net/manual/en/function.imagetruecolortopalette.php
Here is a simple version of what I'm trying to do
$user_design = base64_decode($_POST['input']);
$design_file = fopen('path/filename.png', 'w') or die("Unable to open file!");
imagetruecolortopalette($design_file, false, 1);
fwrite($design_file, $user_design);
fclose($design_file);
With this being the key line. The 1 being the "maximum number of colors that should be retained in the palette."
imagetruecolortopalette($design_file, false, 1);
Behavior I'm getting
The image appears unchanged. I'm not sure if I'm using PHP GD correctly, or if this function doesn't do what I think it does.
Other ideas
These also seem promising.
imagecolordeallocate seems like I may be able to use it to deallocate colors, but not sure how to do this without calling it 254 times.
http://php.net/manual/en/function.imagecolordeallocate.php
imagecolorset seems like I may be able to use it to set the palette, but I'm not sure how to do this for existing images.
http://php.net/manual/en/function.imagecolorset.php
Mostly I suspect imagetruecolortopallette is the best bet, but any and all ideas welcome.
$im = imagecreatefromstring($user_design);
imagefilter($im, IMG_FILTER_GRAYSCALE);
imagefilter($im, IMG_FILTER_CONTRAST, -1000);
imagepng($im, 'path/filename.png');
imagedestroy($im);
How do you convert an image to black and white in PHP
My code is as follows:
<?php
session_start();
$img=imagecreatetruecolor(150,50);
$white=imagecolorallocate($img,255,255,255);
$black=imagecolorallocate($img,0,0,0);
$red=imagecolorallocate($img,255,0,0);
$pink=imagecolorallocate($img,200,0,150);
$grey=imagecolorallocate($img,150,150,150);
$blue=imagecolorallocate($img,0,204,255);
$redd=imagecolorallocate($img, 153, 0,0);
function randomString($length){
$chars="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ023456789";
srand((double)microtime()*1000000);
$str="";
while($i<=$length){
$num=rand() % 33;
$tmp=substr($chars,$num,1);
$str.=$tmp;
$i++;
}
return $str;
}
for($i=0;$i<=rand(1,5);$i++)
{
$color=(rand(1,2)==1)? $grey:$white;
imageline($img, rand(5,50),rand(5,50),rand(50,150) , rand(5,50), $color);
}
$ran=randomString(rand(3,6));
$_SESSION['captcha']=$ran;
imagefill($img,0,0,$redd);
imagettftext($img,14,7,23,27,$black,"fonts/times_new_yorker.ttf",$ran);
imagettftext($img,16,10,18,30,$white,"fonts/times_new_yorker.ttf",$ran);
header("Content-type:image/png");
imagepng($img);
imagedestroy($img);
?>
Yesterday this worked as expected. But now Firefox is showing a message:
This image cannot be displayed, because this contains error.
When I searched for any solutions, it seems everyone is saying something about enabling GD. But in my code GD is enabled, and this very code worked perfectly up until this morning.
Can anyone help me to get a solution for this?
The image cannot be displayed, because PHP reports an error, and the header('Content-Type: image/png') tells it to show the page as an image.
To see the error, you should remove the following part:
header("Content-type:image/png");
imagepng($img);
imagedestroy($img);
or better yet, surround it with if (!isset($_GET['debug'])) statement. That way you can append ?debug=1 to your URL and see all possible PHP errors, while the image stills display normally.
There are a few possible solutions why your code might have stopped working without changing it. My guess is that you tampered with environment somehow.
session_start() needs to store session data in a directory on your local drive. Does your PHP have access to that directory?
The font fonts/times_new_yorker.ttf could disappear.
You could have moved the script to Linux machine, where letter casing matters. Are you sure the path to the font shouldn't have uppercase characters anywhere in it?
Also, just a couple of tips:
You don't need to call srand(), it's initialized automatically. (I assume you come from C/C++ background).
Instead of using rand(), you should use mt_rand() as it's faster and provides better randomness.
Instead of using magic numbers, you should use meaningful expressions (for example, replace % 33 with % strlen($chars)).
Since you seem to display a captcha, consider matching 0 and O, 1 and l as the same "character", so that reasonable user mistakes are forgiven. (Pardon if you do it already.)
I've been bashing my head agains something simple..
// ....all prev code is fine....
$pasteboard =imagecreatetruecolor($imgs['bg']["width"],$imgs['bg']["height"]);
imagealphablending($pasteboard, false);
imagecopyresampled($pasteboard, $imgs['bg']["img"],0,0,0,0,$imgs['bg']["width"],$imgs['bg']["width"],imagesx($imgs['bg']["img"]),imagesy($imgs['bg']["img"]));
imagecopyresampled($pasteboard, $imgs['photo']["img"],20,20,0,0,$imgs['photo']["width"],$imgs['photo']["width"],imagesx($imgs['photo']["img"]),imagesy($imgs['photo']["img"]));
imagesavealpha($pasteboard,true);
//send it out
$out = $pasteboard;
header('Content-type: image/png');
imagepng($out);
//then garbage collection
gives me this:
HORAY!
perfect alpha png composite...
Now I want to rotate it, so instead of the $out=$pasteboard i do this:
imagesavealpha($pasteboard,true);
//rotate it
$out = imagerotate($pasteboard,5,imagecolorexactalpha($pasteboard,255,255,255,50),0);
header('Content-type: image/png');
imagepng($out);
which sadly gives me this:
BOOOO!
Ive tried setting the color like:
imagerotate($pasteboard,5,0x00000000,0);
also the last attr like:
imagerotate($pasteboard,5,0x00000000,1);
new empty images sampled etc etc...
no dice....
Can anyone help?
I'm answering my question simply because I've tried 10-15 suggestions i've seen allover the web all of which offering 'nearly' right solutions but nothing exact, Also I've seen this question posted a few places now, and hopefully if anyone reaches this page in future it would be best to show the solution as the direct answer.
MASSIVE thanks to #cristobal for the help and efforts, if I could vote you up any more I would !
The knack seems to be:
//rotate it
$pasteboard = imagerotate($pasteboard,5,0XFFFFFF00,0); //<-- here must be RRGGBBAA, also last attr set to 0
imagesavealpha($pasteboard, true); // <-- then to save it... dont ask me why..
//send it out
header('Content-type: image/png');
imagepng($pasteboard);
produces this (it has a perfect alpha even though you cant see against the white page):
REALLY not the most fun 5 hrs of my life... hopefully it will stop someone else going through the same pain..
Using the same code above and using a blue color for the third parameter in the imagerotate operation, which will be it used to fill the uncovered zone after the rotation i.e.:
imagerotate($pasteboard, 5, 255);
We get the following image
we see the blue area is the uncovered zone which it fills, while the black color is the to be the border shadow from the image which GD does not seem to handle well along the interpolation used in the rotation.
The same image rotated using the convert for imagemagick. commmand i.e. $> convert -rotate 5 image.png image_rotated.png results in the image below
Clearly GD does not handle alpha colors well when rotating.
If you have access to use the convert commmand using exec or process, you should pipe those image operation to imagemagick instead. GD is a simple image library which has not been updated much the latest years. Otherwise try Imagemagick, Cairo or Gmagick which there are pecl plugins for too http://php.net/manual/en/book.image.php.
Last resort somebody made a function that which uses GD http://www.exorithm.com/algorithm/view/rotate_image_alpha for what you are looking after but the result is not pretty since its a simple linear interpolation:
taken from How to rotate an image in GD Image Library while keeping transparency?. Perhaps if you convert the linear interpolation function to a Bicubic or Quad it will look better.
Note these answers did not work for me but this did.
$destimg = imagecreatefromjpeg("image.png");
$rotatedImage = imagerotate($destimg, 200, 0);
imagesavealpha($rotatedImage, true);
imagepng($rotatedImage,"rotated.png");
I've run into another problem with GD and PHP.
I'm successfully writing text to an image.
However, I've encountered a case where it would be beneficial to place the text - instead of directly on the image - on a rectangle (or any shape) to create a solid background for the text where the image it's being placed on might not allow the text to be read very easily.
My two ideas are, in order of preference:
Fill the background with the color as it writes the text
Write the text to an appropriately sized image with a solid background, and then overlay the image onto the target
I can't figure out how to do #1 and #2 seems overly complex and I don't know how to determine the dimensions of the text so that I can create a new image for it.
For clarity, here is the output that isn't very good:
And here's how I'd like it to look, with a tight box behind the text of any color:
I'm open to any suggestions, but drawing the color on the fly without any other images or hackiness would obviously be my first choice.
Update:
After #Dan suggested using `imagettftext', I decided that it was high time I added support for that function to my library. Everything is working as would be expected except for one major issue.
The text that's written to the image is still transparent, even when written to a solid background (0 transparency).
Here's a script I wrote to test:
<?php
set_include_path('backbone:global:jquery');
require_once('Image.php');
$scout = new Image();
$scout->source = "scout.jpg";
$result = $scout->Write->Font(25, 25, "A Fairly Long String", 12, "#FF0000", 0, "LiberationSans-Regular.ttf", 1, "#FFFF00", .4, 4);
if( !isset($_GET['dev']) )
{
header("Content-Type: " . $scout->contentType());
}
if( $result )
{
$scout->output();
}
?>
The files I used/required:
1. scout
2. liberation font
3. Image Manipulation Library
- Image
- ImageBase
- ImageCombine
- ImageDraw
- ImageManipulate
- ImageWrite
I apologize about all the files, it really only uses Image, ImageBase, ImageCombine, and ImageWrite, but the others are require_onceed by the loader.
Here's a sample of the output from the script above:
And here's output with zero transparency (fully opaque):
$result = $scout->Write->Font(25, 25, "A Fairly Long String", 12, "#FF0000", 0, "LiberationSans-Regular.ttf", 1, "#FFFF00", 1, 4);
Any ideas what could be causing this? It's EXTREMELY possible that it's my code somewhere, but it seems strange that it would work exactly as I thought it should except for this one bug.
In searching desperately for the answer to this problem, I stumbled upon this SO question that's tangentially related to my problem, and contains the answer.
I've never fully understood why you tell imagealphablending false when you want transparency, so I guess my failure to properly understand the code I'm using has led to this issue.
In any case, the following modified code works like a charm in my one single test case.
To write text to a background without forced 100% transparency for the character boxes, you must turn alpha blending ON while writing the text:
imagealphablending($text->handle, true);
$bool = imagettftext($text->handle, $textSize, $angle, $padding, abs($size[5]) + $padding, $this->AllocateColor($rgba[0]['r'], $rgba[0]['g'], $rgba[0]['b'], $rgba[0]['alpha']), $font, $string);
imagealphablending($text->handle, false);
Maybe this will do the job for you if you switch to ttf. http://php.net/manual/en/function.imagettfbbox.php