homepage Welcome to WebmasterWorld Guest from 54.225.57.156
register, free tools, login, search, pro membership, help, library, announcements, recent posts, open posts,
Become a Pro Member

Visit PubCon.com
Home / Forums Index / Code, Content, and Presentation / PHP Server Side Scripting
Forum Library, Charter, Moderators: coopster & jatar k

PHP Server Side Scripting Forum

    
Cutting a Triangle out of PNG and leaving the background transparent
adder




msg:4528429
 3:18 pm on Dec 15, 2012 (gmt 0)

Hi,

I'm trying to write a script that takes a PNG, cuts out a triangle, leaves the PNG data within the triangle and creates transparent background outside the triangle.

This is what I've done and it seemed pretty logical to me before I tested the script :)
As a result it simply displays the original PNG unaltered.

<?php
//create the image
$image = imagecreatefrompng('landscape.png');
//define the foreground
$fground = imagecolorallocatealpha($image, 0, 0, 0, 127);
//define the background
$bground = imagecolorallocate($image, 0, 0, 0);

//make the background transparent
imagecolortransparent($image, $bground);
//draw a triangle and fill with $image data
imagefilledpolygon($image, array(0,0, 120,0, 120,120), 3, $fground);

//save the image
header('Content-type: image/png');
imagepng($image);
imagedestroy($image);
?>


What am I doing wrong?

 

rainborick




msg:4528488
 7:05 pm on Dec 15, 2012 (gmt 0)

If you change your code to:

$fground = imagecolorallocatealpha($image, 0, 0, 0, 0);

you'll draw the polygon with full transparency. The alpha channel controls opacity, so 0 = transparent and 127 = fully opaque.

adder




msg:4528497
 7:41 pm on Dec 15, 2012 (gmt 0)

rainborick, thanks but I actually want it the other way round. I want the polygon to be filled with data from the original PNG and the transparency to be outside of the polygon.

In other words, I want to get rid of everything except that triangle.

lucy24




msg:4528524
 10:09 pm on Dec 15, 2012 (gmt 0)

Obvious backtracking question: What aspect of the triangle is dynamic? There has to be some reason why the png wasn't simply made with an alpha channel in the first place-- but sometimes there's more than one way to achieve the result you want.

adder




msg:4528536
 11:03 pm on Dec 15, 2012 (gmt 0)

@lucy24, well, actually, the triangle is dynamic and the x,y points will vary. The points will be retrieved from another script but that's not a problem. I'll simply make the array in imagefilledpolygon line dynamic.

What do you have in mind regarding that alpha channel? I actually control the making of png so maybe I can create that alpha channel before all this cutting happens? Would that be a better approach? And if yes, how do I do it?

Sorry if this is a stupid question, I've just started learning about GD :)

swa66




msg:4528545
 12:14 am on Dec 16, 2012 (gmt 0)

Why don't you draw the transparant color to all but the triangle ?

Assuming maxx and maxy to be the dimensions of the image

You could use a polygon to draw
(0,0, // star in a corner
x1,y1, //triangle 1
x2,y2, //triangle 2
x3,y3, //triangle 3
0,0 // go back to the first corner again
maxx,0 // corner
maxx,maxy //corner
0,maxy //corner
)

Guess you will need to take care with the case wwhere an X or Y of your triangle gets to be 0 or maxx or maxy.

rainborick




msg:4528709
 5:06 pm on Dec 16, 2012 (gmt 0)

I found a handful of references to masking with GD, but I didn't have any luck working up an example. So I fell back on ImageMagick where I knew the tools existed.

// Polygonal Masking using ImageMagick

$pContent = "Content-type: image/png"; // MIME-type for PNG files
$old_image = 'landscape.png'; // Original image file.

// Always output .png
$theContent = $pContent;
$theWMType = 'png:-';

// Get original image dimensions
$image = imagecreatefrompng($old_image);
$width = imagesx($image);
$height = imagesy($image);

// Create the mask image file - same size as original
// "black" in a mask is transparent, white is opaque
$wmCmd = "convert -size " . $width . "x" . $height . " xc:black";
// Set up drawing color to create mask
$wmCmd .= " -fill white -stroke white";
// -draw the desired mask
$wmCmd .= " -draw \"polygon 0,0, 120,0, 120,120\"";
// Output the result to file
$wmCmd .= " mask.png";
system($wmCmd);

// Composite the mask with the image
$wmCmd = "convert $old_image mask.png -alpha Off -compose CopyOpacity -composite";
// Crop to fit (optional for this example only!)
$wmCmd .= " -crop 120x120+0+0"; // (width)x(height)(x-offset)(y-offset)
$wmCmd .= " $theWMType";

header($theContent);
passthru($wmCmd); // use passthru() to output binary image data to browser
exit;

This should work on any server that has ImageMagick installed as long as the script has write permission in the directory where the script resides. No PHP libraries are required.

swa66




msg:4528749
 9:20 pm on Dec 16, 2012 (gmt 0)

Oh, I just realized that the coordiante I gave need to be properly sorted so that the way you turn around the traigle and the way you turn around the edge are in the same sense". Not that hard to fix (for testing: if it's wrong: just swap 2 corners of the triangle).

lucy24




msg:4528790
 11:55 pm on Dec 16, 2012 (gmt 0)

This should work on any server that has ImageMagick installed as long as the script has write permission in the directory where the script resides.

Uh-oh, that's about two more "if"s that you generally want to see :( What a shame there isn't something more one-size-fits-all.

rainborick




msg:4528851
 3:39 am on Dec 17, 2012 (gmt 0)

ImageMagick is fairly ubiquitous - especially on shared hosts - and is easily installed on dedicated servers that might lack it. I mentioned the directory write permission issue only to cover all of the details. A more experienced ImageMagick developer could almost certainly create a script that would do the job completely in memory without resorting to the mask file. I intend to play around with this a bit myself to see if I can do it.

As I said, I found several references to using GD to do image masking via Google, but couldn't locate a working script. I'll keep looking.

rainborick




msg:4528853
 3:59 am on Dec 17, 2012 (gmt 0)

Wouldn't you know it... two seconds into a second search, I found some GD code that works thanks to a contributor on php.net:

<?php
// Polygonal masking using GD
// imagealphamask() Courtesy of author at http://www.php.net/manual/en/function.imagesavealpha.php#94986

// Load the image
$image = imagecreatefrompng('landscape.png');
$width = imagesx($image); // get dimensions
$height = imagesy($image);

// Create mask
$mask = imagecreatetruecolor($width, $height);
// "black" in a mask is transparent, while white is opaque
$opaque = imagecolorallocate($mask, 255, 255, 255);
imagefilledpolygon($mask, array(0,0, 120,0, 120,120), 3, $opaque);

// Apply mask to source
imagealphamask( $image, $mask );

// Output image and free memory
header('Content-type: image/png');
imagepng($image);
imagedestroy($image);
imagedestroy($mask);
exit;

function imagealphamask( &$picture, $mask ) {
// Get sizes and set up new picture
$xSize = imagesx( $picture );
$ySize = imagesy( $picture );
$newPicture = imagecreatetruecolor( $xSize, $ySize );
imagesavealpha( $newPicture, true );
imagefill( $newPicture, 0, 0, imagecolorallocatealpha( $newPicture, 0, 0, 0, 127 ) );

// Resize mask if necessary
if( $xSize != imagesx( $mask ) || $ySize != imagesy( $mask ) ) {
$tempPic = imagecreatetruecolor( $xSize, $ySize );
imagecopyresampled( $tempPic, $mask, 0, 0, 0, 0, $xSize, $ySize, imagesx( $mask ), imagesy( $mask ) );
imagedestroy( $mask );
$mask = $tempPic;
}

// Perform pixel-based alpha map application
for( $x = 0; $x < $xSize; $x++ ) {
for( $y = 0; $y < $ySize; $y++ ) {
$alpha = imagecolorsforindex( $mask, imagecolorat( $mask, $x, $y ) );
$alpha = 127 - floor( $alpha[ 'red' ] / 2 );
$color = imagecolorsforindex( $picture, imagecolorat( $picture, $x, $y ) );
imagesetpixel( $newPicture, $x, $y, imagecolorallocatealpha( $newPicture, $color[ 'red' ], $color[ 'green' ], $color[ 'blue' ], $alpha ) );
}
}

// Copy back to original picture
imagedestroy( $picture );
$picture = $newPicture;
} // end imagealphamask()

?>

adder




msg:4540756
 10:53 pm on Jan 30, 2013 (gmt 0)

@rainborick this is much appreciated, thank you very much for the solution. It works really well! (sorry, took a long time to answer, was too stuck in the offline world :)

Global Options:
 top home search open messages active posts  
 

Home / Forums Index / Code, Content, and Presentation / PHP Server Side Scripting
rss feed

All trademarks and copyrights held by respective owners. Member comments are owned by the poster.
Home ¦ Free Tools ¦ Terms of Service ¦ Privacy Policy ¦ Report Problem ¦ About ¦ Library ¦ Newsletter
WebmasterWorld is a Developer Shed Community owned by Jim Boykin.
© Webmaster World 1996-2014 all rights reserved