How can I add a drop-shadow to an image using PHP?

10,706

Solution 1

You're not going to be able to do this in PHP without building in a full edge-detector algorithm and significant processing overhead. Look into using GIMP with some script-fu, and let it do the hard work for you.

Solution 2

Just for the hell of it (I know it was answered and accepted): a few months ago, in response to a question on graphic design stackexchange about recovering a mask from a PNG where the source file was lost I slapped together something which uses PHP GD functions to extract the alpha channel from a transparent PNG. As Joe in a comment mentioned above, you can use the alpha channel as the drop shadow, merely offset it by x and y pixels, and then apply an image convolution blur filter to it, then copymerge the original on top. Following code is probably SLOW and proof of concept, but it is a start and it is in PHP as you originally requested.

<?php

$im = imagecreatefrompng('./images/alphatest_nolayer.png');
$w = imagesx($im);
$h = imagesy($im);

$om = imagecreatetruecolor($w,$h);

for ($x = 0; $x < $w; $x++) {
    for ($y = 0; $y < $h; $y++) {
        $rgb = imagecolorat($im, $x, $y);
        $colors = imagecolorsforindex($im,  $rgb);

        $orgb = imagecolorallocate($om,$colors['alpha'],$colors['alpha'],$colors['alpha']);
        imagesetpixel($om,$x,$y,$orgb);
    }
}

header('Content-Type: image/png');
imagepng($om);

imagedestroy($om);
imagedestroy($im);

?>

Solution 3

Actually this can be done with image magick's convert, no need for GD library:

<?php
    $cmd = 'convert /path/to/source.png \( +clone -background black -shadow 80x3+4+4 \) \+swap -background none -layers merge +repage /path/to/destination.png';
    exec($cmd);
?>

you can play a little with the shadow parameter.

-shadow percent-opacity{xsigma}{+-}x{+-}y{%}

result

Solution 4

I used Marc B's advice, and called upon The GIMP to do this for me. If anyone else cares, here's the code I used:

/**
 * Call upon The GIMP to apply a dropshadow to a given image.
 * 
 * NOTE: This will overwrite the image file at $filename! Be sure to make a copy
 * of this file first if you need one.
 * 
 * @param string $filename
 * @param int $offset_x
 * @param int $offset_y
 * @param float $radius
 * @param array $color
 * @param int $opacity
 * @return type 
 * @todo Resize the canvas so there's room to apply dropshadows to images which have no whitespace around them.
 */
function apply_gimp_dropshadow($filename,$offset_x=8,$offset_y=8,$radius=15,$color=false,$opacity=40)
{
    if(!is_array($color))
        $color = array(0,0,0);
    $color = join(' ',$color);

    $gimpScript = <<<END_OF_SCHEME_CODE_OH_HOW_I_HATE_YOU_SCHEME
(define (dropshadow filename)
  (let* (
      (image (car (gimp-file-load RUN-NONINTERACTIVE filename filename)))
      (drawable (car (gimp-image-get-active-layer image)))
    )
    (script-fu-drop-shadow image drawable 8 8 15 '($color) 40 FALSE)
    (set! drawable (car (gimp-image-merge-visible-layers image 0)))
    (gimp-file-save RUN-NONINTERACTIVE image drawable filename filename)
    (gimp-image-delete image)
  )
)

(dropshadow "$filename")
(gimp-quit 0)
END_OF_SCHEME_CODE_OH_HOW_I_HATE_YOU_SCHEME;

    $descriptorspec = array(
        0 => array("pipe", "r"),  // stdin is a pipe that the child will read from
        1 => array("pipe", "w"),  // stdout is a pipe that the child will write to
    );

    $cwd = '/tmp';
    $gimp = proc_open('/usr/bin/gimp -i -b -', $descriptorspec, $pipes, $cwd);

    if (!is_resource($gimp))
        throw new Exception('Could not open a pipe to GIMP');

    fwrite($pipes[0], $gimpScript);
    fclose($pipes[0]);

    $gimpOutput = stream_get_contents($pipes[1]);
    fclose($pipes[1]);
    $gimpResult = proc_close($gimp);

    return $gimpResult;
}

Solution 5

You can use PHPs GD Image Processing Libraries

Here is a tutorial on how to add the shadow effect. However if this doesn't fit your needs i'm sure googling "PHP GD Drop Shadow" will do the trick.

Share:
10,706
Josh
Author by

Josh

I am Josh Gitlin, CTO and co-founder of Digital Fruition a software as a service eCommerce company. Currently serving as Principal DevOps Engineer at Pinnacle 21, and hacking away at Cinc Server, the free-as-in-beer rebranded distribution of Chef Server.

Updated on June 03, 2022

Comments

  • Josh
    Josh about 2 years

    I am looking for a way to add a drop shadow to an image using PHP. Before you answer or vote to close: I am not looking to do this using CSS or HTML. I want to generate an image file. This is not a duplicate of this question nor this one.

    I am looking for a very specific effect. For example, given this input image:

    It's an image!

    I want to produce the following image:

    It's an image, with a drop shadow!


    TL;DR: This image above was generated using Photoshop's Drop Shadow effect. I want a look very similar to that. For reference, here's the settings our design team used. Ideally, I'd have similar control in my code for angle, distance, opacity, etc:

    It's some Photoshop settings!

    I have full access to our debian-linus-based servers, so any GD or ImageMagick solution will work. As will any FOSS linux software solution, although I'd prefer a way to do it with IM or GD as those are already installed and don't require new software to be installed.

    The shadow must be able to be placed on a transparent, non-rectangular PNG!

    I'm asking the question mainly because the scripts and solutions I have found on the web either only produce rectangular shadows, look like total poo, or just plain don't work at all.

  • Josh
    Josh almost 13 years
    I don't know why I didn't think of GIMP! Could be a challenge, but I'm up for it.
  • Josh
    Josh almost 13 years
    This was one of many I saw. The shadows look like crap, and are rectangular only. I need a lot more power than that.
  • Josh
    Josh almost 13 years
    Sadly Google is failing me on this one. The signal to noise ration for "PHP Dropshadow (GD|ImageMagick)" is just waaaay too low. So I was asking geniuses here!
  • Joe White
    Joe White almost 13 years
    Huh? There's nothing about drop shadows that would use edge detection. Just copy the image's alpha channel to a black image, apply a blur effect, and then composite the two images together (with a few pixels' offset to the shadow layer). I don't know anything about PHP image libraries, but drop shadows shouldn't be hard as long as you can work with channels and apply a gaussian blur.
  • Josh
    Josh almost 13 years
    (and for anyone else finding this, this question looks like a good place to start for PHP/GIMP integration)
  • Marc B
    Marc B almost 13 years
    @Joe: That applies a shadow all around the image. A drop shadow appears on 2 "edges" at most. As well, nothing in the OP's question suggests that those tiles in the image are actually masked. If it's a bog-standard rectangular non-transparent image, then all your method would do is build a blurred shadow outside the boundaries of the image
  • Joe White
    Joe White almost 13 years
    @Marc, sure, if you you forgot to apply the offset. You make the shadow show up on the lower right by moving it down and right -- that's the way drop shadows have always worked. And OP specified a "transparent, non-rectangular PNG", which tells me that yes, it's got a full alpha channel. (There's also the fact that OP said Photoshop could give the drop shadow he wants, which it couldn't if the image didn't have alpha.)
  • horatio
    horatio almost 13 years
    Joe has the answer. This IS how drop shadows are made in photoshop. If you try it is PS with a small enough offset and the right angle, the shadow will be more like a halo as Mark describes. IIRC, PS distance parameter is the offset (along with the angle)
  • Josh
    Josh almost 13 years
    @Marc this is going to work great. I posted the actual code I used as an answer
  • Josh
    Josh almost 13 years
    Thanks @horatio! I think yours is a much better answer that rlemon's and deserves more upvotes.
  • Sathyajith Bhat
    Sathyajith Bhat almost 13 years
    LOL @ END_OF_SCHEME_CODE_OH_HOW_I_HATE_YOU_SCHEME
  • anschauung
    anschauung over 12 years
    Incidentally, this page was the top hit when I googled that exact phrase :p
  • Josh
    Josh about 11 years
    Wow I just noticed this answer, that's better than my Gimp solution I think.
  • NeoTechni
    NeoTechni almost 3 years
    How do you apply the blur to the alpha image? I've tried imagefilter($om, IMG_FILTER_GAUSSIAN_BLUR); but the shadow looks like it was on the NES, in that it's jaggedy like lego.