Search code examples
phpimagegdimagickdrawimage

Is there any way to make image with text shadow in PHP with GD?


I've made a tool in which user will type the text & script will make image of that text, but getting issue with text shadow, I wants to make image with text shadow but GB library shadowImage function only place the shadow of image not for text,

Here is the image which I got now

enter image description here

But I wants like that

enter image description here

Is there anyone know any way so I can make image like that?

here is my method with I used to create it,

public function render()
{
    $this->_image = new Imagick;

    if(!$this->text)
    {
        $this->_image->newImage(1, 1, 'white');
        return;
    }

    $draw = new ImagickDraw();
    $color = new ImagickPixel($this->color);
    $background = new ImagickPixel($this->surfaceColor);

    /* Font properties */
    $draw->setStrokeAntialias(true);
    $draw->setTextAntialias(true);
    $draw->setFontSize($this->fontSize);
    $draw->setFillColor($color);
    $draw->setFont(Model_Tool_Font::find($this->font_id)->getFontPath($this->bold, $this->italic));

    /* Border ? */
    if ($this->borderWidth)
    {
        $draw->setStrokeColor($this->borderColor);
        $draw->setStrokeWidth($this->borderWidth * $this->fontSize * self::BORDER_WIDTH_MULTIPLIER );
    }

    /* Get font metrics */
    $metrics = $this->_image->queryFontMetrics($draw, $this->text);
    /* Sizing calculations */
    $width  = $metrics['textWidth'];
    $height = $metrics['textHeight'];
    //respect custom proportions
    if(!$this->maintainProportions  &&  $this->customHeight > 0  &&  $this->customWidth > 0)
    {
        //stretching is better than shrinking (possibly for quality)
        //size limits should be used to constrain size

        $aspect = $this->customWidth / $this->customHeight;
        if($this->customHeight / $height  >  $this->customWidth / $width)
            $height = $width / $aspect;
        else
            $width = $height * $aspect;
    }

    $this->_limitSize($width, $height);
    /* Sizing calculations end */
    //appears to result in bigger image than before sizing?
    if($height > $this->fontSize)
    {
    //update the metrics
        $draw->setFontSize($this->fontSize = $height);
        $metrics = $this->_image->queryFontMetrics($draw, $this->text);
    }

    /* Create text */
    $draw->annotation(0, $metrics['ascender'], $this->text);

    /* Create image */
    $this->_image->newImage($metrics['textWidth'], $metrics['textHeight'], $background);
    $this->_image->drawImage($draw);

    if ($this->reverseCut == 1) {
        $this->_image->flopImage();
    }

    /* Shadow */
    if ($this->shadowOffset)
    {
        $this->shadowOffset = abs((int)$this->shadowOffset);
        $x = $y = 0;
        switch($this->shadowOrient)
        {
            case self::ORIENT_TOP:
                $x =  0;
                $y = -3 - ($this->shadowOffset);
                break;
            case self::ORIENT_TOPRIGHT:
                $x = 2 + ($this->shadowOffset);
                $y = -3 - ($this->shadowOffset);
                break;
            case self::ORIENT_RIGHT:
                $x = 2 + ($this->shadowOffset);
                $y = 0;
                break;
            case self::ORIENT_BOTTOMRIGHT:
                $x = 2 + ($this->shadowOffset);
                $y = 2 + ($this->shadowOffset);
                break;
            case self::ORIENT_BOTTOM:
                $x = 0;
                $y = 2 + ($this->shadowOffset);
                break;
            case self::ORIENT_BOTTOMLEFT:
                $x = -2 - ($this->shadowOffset);
                $y = 2 + ($this->shadowOffset);
                break;
            case self::ORIENT_LEFT:
                $x = -3 - ($this->shadowOffset);
                $y = 0;
                break;
            case self::ORIENT_TOPLEFT:
                $x = -3 - ($this->shadowOffset);
                $y = -3 - ($this->shadowOffset);
                break;
        }

        //transform logical sizes into pixels
        $r = $this->fontSize * self::BORDER_WIDTH_MULTIPLIER;
        $x *= $r;
        $y *= $r;

        $shadow = clone $this->_image;
        $shadow->setImageBackgroundColor( new ImagickPixel( $this->shadowColor ) );
        $shadow->shadowImage( 96, 0.5, 0, 0);
        if($x || $y) {
            $geo = $this->_image->getImageGeometry();
            $currentImage = $this->_image->getImage();
            $this->_image->newImage($geo['width'] + abs($x), $geo['height'] + abs($y), 'none');

            $shift_x = $shift_y = 0;

            if($x < 0) {
                $shift_x = -$x;
                $x = 0;
            }

            if($y < 0) {
                $shift_y = -$y;
                $y = 0;
            }
            $this->_image->compositeImage( $currentImage, Imagick::COMPOSITE_OVER , $shift_x, $shift_y);

        }
        $this->_image->compositeImage( $shadow, Imagick::COMPOSITE_DSTOVER , $x, $y);

    }
    $this->_image->resizeImage($width, $height, imagick::FILTER_LANCZOS, 0.9, $this->maintainProportions);

}

Solution

  • just use Imagick::annotateImage to draw the text with shadow color and shadow offset, then draw text again in your desired position. modified code below copied from php Imageick manual

    <?php
        /* Create some objects */
        $image = new Imagick();
        $draw = new ImagickDraw();
        $pixel = new ImagickPixel( 'white' );
    
        /* New image */
        $image->newImage(800, 75, $pixel);
    
    
        /* Font properties */
        $draw->setFont('Bookman-DemiItalic');
        $draw->setFontSize( 30 );
    
        $offset_x = 3;
        $offset_y = 3;
    
        /* Black shadow */
        $draw->setFillColor('black');
        /* Create text */
        $image->annotateImage($draw, 10+$offset_x, 45+$offset_y, 0, 'The quick brown fox jumps over the lazy dog');
    
        /* Yellow Test */
        $draw->setFillColor('yellow');
        /* Create text */
        $image->annotateImage($draw, 10, 45, 0, 'The quick brown fox jumps over the lazy dog');
    
        /* Give image a format */
        $image->setImageFormat('png');
    
        /* Output the image with headers */
        header('Content-type: image/png');
        echo $image;
    
    ?>