PHP Imagick stroke appears over fill - php

Attempting to do a simple watermark consisting of white text with black outline on top of an image. Problem is that the stroke color is appearing over (or at least affecting) the fill color. What I mean by "affecting" is that, for example, when I try a red stroke color the fill color becomes a slightly lighter red (ie red + white) because I have a fill color of white.
Image
Code:
$watermark_text = new ImagickDraw();
$watermark_text->setFont($font);
$watermark_text->setFontSize(25);
$watermark_text->setFillColor('white');
$watermark_text->setStrokeColor('#000000');
$watermark_text->setStrokeWidth(3);
$watermark_text->setStrokeOpacity(0.4);
$watermark_text->setStrokeAntialias(false);
$watermark_text->setGravity(Imagick::GRAVITY_SOUTHEAST);
I specified .4 opacity to see/show that the fill and solid are actually there, just not fully in the way I expect.
I am expecting the fill color to be 100% white, any ideas why it's not please?
Thank you
Edit
I see what's happening. The stroke width is such that it overlaps the fill internally. Is there a way to ensure that the fill color appears on top of the stroke so that the white is 100% white?

Looks like your point size is to small for stroke width of 3. The effects your experiencing can be demonstrated with the following example.
foreach(range(1,5) as $strokeWidth) {
// ... your example here ...
$watermark_text->setStrokeWidth($strokeWidth);
$watermark_text->annotation(0, 0, 'Font Width ' . $strokeWidth);
}
The easiest solution would be to clone your ImagickDraw, and draw the same text twice. First being only the outline w/out fill, and the actual filled text over the top of the first. If your not working with vectors, you can also drop the opacity steps in favor of rgba color.
// Create white text w/ common options
$font = 'Helvetica-Neue-Bold';
$watermark_text = new ImagickDraw();
$watermark_text->setFillColor('white');
$watermark_text->setFont($font);
$watermark_text->setFontSize(25);
$watermark_text->setStrokeAntialias(false);
$watermark_text->setStrokeColor('none');
$watermark_text->setStrokeWidth(0);
$watermark_text->setGravity(Imagick::GRAVITY_SOUTHEAST);
// Clone & set stroke attributes
$watermark_outline = clone $watermark_text;
$watermark_outline->setFillColor('none');
$watermark_outline->setStrokeColor('rgba(0,0,0, 0.4)');
$watermark_outline->setStrokeWidth(3);
// Set the text for both, and offset one to match stroke width
$watermark_outline->annotation(0, 0, 'Draw On Top');
$watermark_text->annotation(3, 0, 'Draw On Top');
// Draw stroke, then text
$image = new Imagick();
$image->setSize(200, 35);
$image->readImage('XC:LightGoldenrod');
$image->drawImage($watermark_outline);
$image->drawImage($watermark_text);
$image->writeImage('out.png');

Related

How to add a transparent rectangle to PNG file in php WITHOUT a border

I can successfully add a transparent rectangle to an area of a saved PNG file, but it has a faint border around it, which can be seen on the final image. I want to remove this.
The code I use to add the rectangle is:
$dest=imagecreatefrompng("originalFilename.png");
$red = imagecolorallocate($dest, 255, 0, 0);
imagecolortransparent($dest, $red);
imagefilledrectangle($dest, 0, 0, 50, 25, $red);
imagepng($dest, "newFilename.png");
and the result looks like this:
Image showing rectangle outline
The transparency works fine, showing in this example a white background behind... but you can see that in the top left there's the faint outline of the transparent rectangle. This is what I want to remove.
I've since tried putting a box over the edge (it would be white to match the background of the image, but using green for display purposes here), but that box gets a slightly red huhe around it too!?!? Really strange.
Like this
red hue
Grateful for any clues. This is not the same as the suggested duplicate as it deals specifically with the hue that's left around the border of the transparent area and also any object made to go in that area.

Imagecolortransparent() for multiple colors

I use this code to make all white pixels transparent:
$img = imagecreatefromjpeg('test.jpg');
$remove = imagecolorallocate($img, 255, 255, 255);
imagecolortransparent($img, $remove);
imagepng($img, 'bla.png');
But I also want some "almost white" pixels to be transparent like 254, 255, 255 etc. How could I add that?
If your question is how to remove a contiguous area with similar color range; I must say that it's hard using PHP's GD library. You should take a look at ImageMagick which is a much more powerful image processing library and has PHP integration.
If you choose to use ImageMagick instead, you'll have access to a lot of third-party scripts that does amazing image processings. One of which is Fred Weinhaus' MagicWand. It does what you're looking for.
You seed it with an x and y coordinate, it can extract the color of that coordinate and make it transparent with a configurable color dissimilarity threshold (fuzz factor). Have a look how it can match a gradient of blue:
I had the same problem. With a black and white image. But white was not very white. So before to set transparency, I do a filter to increase the contrast. And I have an image with real black and real white. And when I use transparency on white color, it's works fine.
Filter's example :
imagefilter($src,IMG_FILTER_CONTRAST,-50);

ImageMagick / Imagick: Convert a PNG with Alpha channel into a 2 color image (Color, Transparent)

I would like to know and find out, how I can colorize/replace any pixel of an image, that is not (fully) transparent with an opaque pixel.
For example, having a multicolored Logo with transparent pixels, I would like to convert it in to a logo with only the color #ff0000, and not change the transparent background.
I want to achieve this with the PHP Imagick Library. I cannot find any good documentation.
I thought that Imagick::thresholdImage would be a helper, but there is no documentation about the threshold parameter.
Best results are achieved with this fragment of code. But still not working perfectly. Some pixels - i guess those with alpha > 0 and < 1 are not replaced.
$image = new \Imagick($source);
$image->setImageFormat('png');
$fill = new \ImagickPixel('#ff0000');
$image->thresholdImage(0);
$image->paintOpaqueImage('#ffffff', $fill, 1);
$image->writeImage($destination);
I would like to know and find out, how I can colorize/replace any pixel of an image, that is not (fully) transparent with an opaque pixel.
You almost certainly don't.
The code below does what you are asking (I think) and the output looks terrible. Perhaps you should give an example input image, and a hoped for example output image, that you have edited in Photoshop, to show what you were hoping for.
Input image:
Output image:
$imagick = new Imagick("fnord.png");
// Get the alpha channel of the original image.
$imagick->separateImageChannel(\Imagick::CHANNEL_ALPHA);
// Make all the colors above this pure white.
$imagick->whiteThresholdImage("rgb(254, 254, 254)");
// Make all the colors below this pure black.
$imagick->blackThresholdImage("rgb(254, 254, 254)");
// We want the mask the other way round
$imagick->negateImage(false);
$imagickCanvas = new \Imagick();
$imagickCanvas->newPseudoImage(
$imagick->getImageWidth(),
$imagick->getImageHeight(),
"xc:rgb(255, 0, 0)"
);
// Copy the mask back as the alpha channel.
$imagickCanvas->compositeImage($imagick, \Imagick::COMPOSITE_COPYOPACITY, 0, 0);
// Write out the image.
$imagickCanvas->setImageFormat('png');
$imagickCanvas->writeImage("./output.png");

How to remove png image white background color using php?

I have to remove image background color and make that transparent. I am using below code to make image transparent but that is not working.
function transparent_background($filename, $color)
{
$img = imagecreatefrompng('image.png'); //or whatever loading function you need
$colors = explode(',', $color);
$remove = imagecolorallocate($img, $colors[0], $colors[1], $colors[2]);
imagecolortransparent($img, $remove);
imagepng($img, $_SERVER['DOCUMENT_ROOT'].'/'.$filename);
}
transparent_background('logo_100x100.png', '255,255,255');
Please see screenshot for better understanding that what I am trying to do.
Thanks in advance...
Actual color inside the box (around puma's face) is not 255:255:255 its 252:254:251. at least for most of it.
I set that color as input to your function "transparent_background" and set HTML background color to maroon color, result is
http://www.photojoiner.net/view/?fid=LpEajVuDhXT7yqH6WBBuhJtT0m9I4NnY.jpeg
You can create a loop and try making range of colors transparent. ie from 251:251:251 to 255:255:255. Not sure about the perfomance though.
Just giving you a wiled idea since your screenshot shows a web browser assuming its a web application, you can do the same using HTML5 context, You can select a region on the canvas and edit its imageData on that region. I.e select the white square with puma and set alpha setting of all white (or range of colors) pixels' to 0. More reading on HTML5 canvas pixel manipulation https://dev.opera.com/articles/html5-canvas-basics/#pixelbasedmanipulation

PHP Imagemagick convert greyscale to RGB

I made a tool where people can upload photos and modify them, including desaturation, resulting in a greyscale image.
I generate the final image using PHP's GD library.
When printing these images the colors appear wrong so using Image Magick I add a color profile.
This works great except for images that have been greyscaled. The color profile gets added, but when I open the image in Photoshop, it says "The embedded ICC profile cannot be used because the ICC profile is invalid. Ignoring the profile".
In Photoshop the image is set to Greyscale rather than RGB, hence the attached RGB profile is wrong. I need it to be RGB.
I'm using the following code to add all the possible information in an attempt to make the image RGB:
<?php
$i = new Imagick();
$i->readimage('image.jpg');
$i->setimagetype(Imagick::IMGTYPE_TRUECOLOR);
$i->setimagecolorspace(Imagick::COLORSPACE_RGB);
$i->profileimage('icc', file_get_contents('AdobeRGB1998.icc'));
$i->writeimage($d);
$i->destroy();
?>
Does anyone know how to successfully set the image to RGB and attach the profile?
I did try the different methods and combinations for 'setImageProfile' and 'profileImage', also for colorspace and imagetype, but the result is always the same.
#a34z says in a comment:
"Somehow I must let PS know it is an RGB image with only grey pixels in it or something like that."
It is a fundamental error to assume that an RGB image could even contain 'gray' pixels as such!
RGB images do have pixels that are always composed of a mix of 3 colors: R ed + G reen + B lue. These are the 3 channels which are available, no more. There is no such thing as a gray channel in RGB.
What makes an RGB image look gray to our eyes is the fact that each of the 3 numerical channel values are equal or less strictly speaking, at least 'similar enough'. Of course, there is also software that can analyze the color values of the 3 channels and tell you which pixels are 'gray'. ImageMagick's histogram output would happily tell you which shades of gray you would say and use different names for those Grays. But don't be fooled by that color name: the pixel will still be composed from 3 colors with the same (or very similar) intensities, and ImageMagick will also report these values.
If you really need a pure grayscale image (that uses only one channel for the level of gray, not three), then you have to convert it to such an image type.
The two images may still look the same (if the conversion was done correctly, and if your monitor is calibrated, and if your not red-green-blind) -- but their internal file structure is different.
RGB images need ICC profiles that deal with RGB (if any), such as sRGB. For grayscale you cannot use sRGB, there you may want to use DeviceGray or something...
This worked for me to have it recognized as a truecolor image. Assuming $img is the Imagick object containing the greyscaled image, I check if it is indeed greyscale and then edit 1 random pixel and modify its red value by adding or substracting 5 values, depending on red being greater than 5 or not.
<?php
if ($img->getImageType() == Imagick::IMGTYPE_GRAYSCALE)
{
// Get the image dimensions
$dim = $img->getimagegeometry();
// Pick a random pixel
$x = rand(0, $dim['width']-1);
$y = rand(0, $dim['height']-1);
// Define our marge
$marge = 5;
//$x = 0;
//$y = 0;
// Debug info
echo "\r\nTransform greyscale to true color\r\n";
echo "Pixel [$x,$y]\n";
// Get the pixel from the image and get its color value
$pixel = $img->getimagepixelcolor($x, $x);
$color = $pixel->getcolor();
array_pop($color); // remove alpha value
// Determine old color for debug
$oldColor = 'rgb(' . implode(',',$color) . ')';
// Set new red value
$color['r'] = $color['r'] >= $marge ? $color['r']-$marge : $color['r'] + $marge;
// Build new color string
$newColor = 'rgb(' . implode(',',$color) . ')';
// Set the pixel's new color value
$pixel->setcolor($newColor);
echo "$oldColor -> $newColor\r\n\r\n";
// Draw the pixel on the image using an ImagickDraw object on the given coordinates
$draw = new ImagickDraw();
$draw->setfillcolor($pixel);
$draw->point($x, $y);
$img->drawimage($draw);
// Done,
unset($draw, $pixel);
}
// Do other stuff with $img here
?>
Hope this helps anyone in the future.

Categories