Opacity effect using PHP GD extension - php

I wonder if it is possible to have "opacity" effect when drawing images on top of other images with the PHP GD extension? Are there any built-in functions that can get the results I want or do I have to go for my own implementation using imagesetpixel way?
A pseudo-code to illustrate what I am trying to do right now:
// Background image
$image_bg = imagecreatetruecolor(100, 100);
imagesavealpha($image_bg, true);
// Making background image fully transparent
imagefill($image_bg, 0, 0, imagecolorallocatealpha($image_bg, 0, 0, 0, 127));
// Now the actual image I want to draw with opacity (true color PNG)
$image = imagecreatefrompng(...);
// Drawing with 50 "merge" value
imagecopymerge($image_bg, $image, ..., 50);
The trouble with above code is that imagecopymerge will not respect background image alpha value and will merge the image with the background as if it was opaque black color (the resulting image will not be 50% transparent).
Edit: I ended up implementing my own function using imagecolorat and imagesetpixel way.

Take a look at imagecolortransparent() and imagealphablending() (or this question).

Related

Load transparent png into gd php but don't make it's background transparent

I'm trying to create images from dynamic text data in GD and put a logo in the top corner. The background color of the image will change based on the data passed in so I can't just save the logo as an image with no alpha channel.
I create the image, fill it with the dynamic background color using imagefill(), then add the text using imagettftext() and then load my logo in. I'm having a problem getting the logo into the image without it keeping its background color of 'transparent'. So I would like it to have the dynamic background color behind it that is set with imagefill(). However, it keeps the transparency background it was loaded in with and so writes this part of the png as transparent. I tried calling imagefill() on the logo after it had been loaded in (using the same rgb that sets the background of the destination image) but this didn't do anything.
Below is my code:
$background = $_GET['background'];
$data1 = $_GET['data1'];
$data2 = $_GET['data2'];
$r = $_GET['r'];
$g = $_GET['g'];
$b = $_GET['b'];
$png_image = imagecreate(400, 200);
$gd_text_color = imagecolorallocate($png_image, 255, 255, 255);
$gd_background_color = imagecolorallocate($png_image, $r, $g, $b);
imagefill($png_image, 0, 0, $gd_background);
$text1 = "test test $data1";
$text2 = "test test again $data2";
$font = 'Lato-regular.ttf';
imagettftext($png_image, 18, 0, 20, 20, $gd_text_color, $font, $text1);
imagettftext($png_image, 18, 0, 20, 50, $gd_text_color, $font, $text2);
//trying to get this logo and place it in the corner.
$logo = imagecreatefrompng("images/logo.png");
imagecopy($png_image, $logo, 10, 10, 0, 0, 100, 30);
header('Content-type: image/png');
imagepng($png_image, $filename);
imagedestroy($png_image);
Here's the output of that code: http://i.imgur.com/n25h9Js.png
And here's what the image looks like when loaded into a program that accepts an alpha channel: http://i.imgur.com/3OIRupN.png
Does anyone know how I'd achieve what I'm attempting?
Thanks for your time.
EDIT
To try and explain what I want here's another image. The top image is what I currently get, and the bottom image is what I want. I'm simply trying to load in a transparent PNG that can sit ontop of different colored backgrounds. However I either get it like how it is shown here (transparent background) or as a black background (because I guess the alpha channel isn't being looked at?). Hope this helps. Image:
Edit 2
As per the comment below, I changed it from imagecreate() to imagecreatetruecolor() and now it works fine! I would love an explanation why this solved it if anyone has the time but for now, thank you all who commented or even spent your time looking at this question.
I suspect your imagecreate() may be causing you problems as it creates a palettised image which doesn't have the flexibility or breadth of expression of a true-colour image.
I suggest you replace it with imagecreatetruecolor().

PHP GD imagecopymerge php with transparency

I'm trying to draw a partially transparent PNG image on another image I created in my script, but it behaves really strange. I'm using imagecopymerge because I want to use different opacity values, but when I do this, the output looks like this:
There must be some problem when processing the image. the yellow parts aren't even visible in the png file. Everything but the black parts are transparent.
I saved the image in photoshop and it looks ok when I just use imagecopy or something.
here are the relevant parts of the script:
$imgLogoBg = file_exists($logoBgImgFile)?imagecreatefrompng($logoBgImgFile):null;
$image = imagecreatetruecolor(imagesx($imgBase), imagesy($imgBase));
imagefill($image, 0,0, imagecolorat($imgBase,0,0));
imagecopymerge( $image, $imgLogoBg,
0,0,
0,0, imagesx($imgLogoBg), imagesy($imgLogoBg),50);
imagepng($image);
I can't figure out what the problem is. when I use another image the result is similar.

Resizing images with `imagecopyresampled` from PHP GD

Using the PHP GD library, I generate image resource that is opaque white, with some "holes" here and there, which are fully transparent disk shapes. I've attached it bellow, although you'll need to first save it and open it (in Windows) with the Image Preview application in order to see the holes in it, due to the blue-ish background. Otherwise you'll only see white.
The original image:
From that image resource, which is 2550 x 3000px, I need to create a smaller version. I do so using imagecopyresampled(). All is fine with the resulting image, with one exception: here and there, it contains grey pixels (RGB: 254,254,254):
The resized image:
Part of the code I use is bellow:
$previewPxWidth = $this->viewportWidth_;
$previewPxHeight = round($this->viewportWidth_ / $schematic['paper.aspect.ratio']);
$preview = imagecreatetruecolor($previewPxWidth, $previewPxHeight);
$noColor = imagecolorallocatealpha($preview, 255, 255, 255, 127);
imagesavealpha($preview,true);
imagefill($preview, 0, 0, $noColor);
imagecopyresampled($preview, $sheet, 0, 0, 0, 0, $previewPxWidth, $previewPxHeight, $sheetPxWidth, $sheetPxHeight);
imagedestroy($sheet);
header("Content-type: image/png");
header("Content-disposition: inline; filename=image.png");
imagepng($preview);
Where are those very light and (apparently) randomly positioned grey pixels coming from and how can I get rid of them?
Try imageAlphaBlending(), but ImageMagic is best way.

Merging multiple transparent PNGs into one

I am framing ads with a curved border.
Here is a sample ad: http://imageshack.us/f/20/4e5f5fe94b327new60seciq.png/
I am trying to replicate what would be done in Photoshop, place one on top of the other. Here is the code I'm using:
// create destination canvas
$dest_img = imagecreatetruecolor(176, 75);
// Make the background transparent
$black = imagecolorallocate($dest_img, 0, 0, 0);
imagecolortransparent($dest_img, $black);
imageAlphaBlending($dest_img, false);
imageSaveAlpha($dest_img, true);
// copy ad into destination
imagecopy($dest_img, $ad_image, 0, 0, 0, 0, 176, 75);
// copy frame onto first half of image
imagecopy($dest_img, $curve_image, 0, 0, 0, 0, 88, 75);
What is happening is that the last copy to take place (the frame) is taking priority and instead of seeing the ad, im getting a transparent block. Here is a blown up image of what GD is doing:
http://imageshack.us/f/684/unled1to.png/
I'm hoping there is a simple solution to get the lower layer to remain visible - if not I think I will have to write a function and go pixel by pixel and compare...
if (bottom_px == trans && top_px == trans) {
dest_px = trans;
}
else {
dest_px = top_px;
}
Set imagealphablending to true. From the manual, emphasis added:
In blending mode, the alpha channel component of the color supplied to all drawing function, such as imagesetpixel() determines how much of the underlying color should be allowed to shine through. As a result, gd automatically blends the existing color at that point with the drawing color, and stores the result in the image. The resulting pixel is opaque. In non-blending mode, the drawing color is copied literally with its alpha channel information, replacing the destination pixel. Blending mode is not available when drawing on palette images.
Also, you are not actually coloring the background transparent. You are just telling that $black is transparent. Instead, use imagefill with imagecolorallocatealpha:
imagefill($dest_img, 0, 0, imagecolorallocatealpha($dest_img, 0, 0, 0, 127));

PHP/GD ImageSaveAlpha and ImageAlphaBlending

I'm using GD to resize and convert images, however during my tests I found a weird behavior when converting transparent PNG's to JPEG's. According to the manual ImageAlphaBlending() is on by default but in order to preserve the transparency I must set ImageSaveAlpha() to true (which in turn requires that I set ImageAlphaBlending() to false). So the correct way should be:
$result = ImageCreateFromPNG(...);
ImageAlphaBlending($result, false);
ImageSaveAlpha($result, true);
ImageFill($result, 0, 0, IMG_COLOR_TRANSPARENT);
ImageJPEG($result);
ImageDestroy($result);
However if I do it the "correct" way all the transparency area comes up black in the JPEG. This seems to work (JPEG with white background on transparent areas) on my tests:
$result = ImageCreateFromPNG(...);
ImageAlphaBlending($result, true); // true by default, but still...
ImageSaveAlpha($result, true);
ImageFill($result, 0, 0, IMG_COLOR_TRANSPARENT);
ImageJPEG($result);
ImageDestroy($result);
Can someone please enlighten me on this subject?
It probably depends on your PNG. A PNG file can contain a background color, which can be used when transparency doesn't work. Your PNG probably has a white background. When you set imageaplhablending to true it picks up the background color from your PNG and uses that when writing the JPEG. When you set it to false it picks the default for GD which is black.
You can try it for yourself. Create a transparent PNG and save it with an orange or pink background color. Your second example should show that color.
By the way, the PNG background color trick is a nice one for IE6 images. IE6 does not support transparent PNGs so it will display them with whatever background color you saved them with. When saving transparent PNGs, save them with the same background color as your website. It will look better than white or black boxes around your PNG images in IE6.
If you are converting from PNG (or GIF) to JPG, you should probably copy the final image to another image that is filled with white, using imagecopy ($image is any image already created with GD):
// Create a new background
$bg = imagecreatetruecolor(imagesx($image), imagesy($image));
// Allocate the color
$color = imagecolorallocate($bg, 255, 255, 255);
// Fill the background with white
imagefill($bg, 0, 0, $color);
// Alpha blending must be enabled on the background!
imagealphablending($bg, TRUE);
// Copy the current image onto the opaque background
if (imagecopy($bg, $image, 0, 0, 0, 0, imagesx($image), imagesy($image)))
{
// Replace the image with the background copy
imagedestroy($image);
$image = $bg;
}
Hope that helps.

Categories