有没有办法用GD在PHP中制作带有文字阴影的图像?

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

我制作了一个工具,用户可以在其中键入文本,脚本会制作该文本的图像,但是文本阴影有问题,我想制作带有文本阴影的图像,但 GB 库 shadowImage功能只放置图像的阴影而不是文本,

这是我现在得到的图像

但我想要那样

有没有人知道我可以制作这样的图像的方法?

这是我用来创建它的方法,

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);

}

只需使用Imagick::annotateImage绘制带有阴影颜色和阴影偏移的文本,然后在您想要的位置再次绘制文本。从 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;

?>

您可以从此处获取参考 [GitHub Repository]。代码复现如下

/*
 * imagettftextblur v1.0.0
 *
 * Copyright (c) 2013 Andrew G. Johnson  <andrew@andrewgjohnson.com>
 * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 *
 * @author Andrew G. Johnson <andrew@andrewgjohnson.com>
 * @copyright Copyright (c) 2013 Andrew G. Johnson <andrew@andrewgjohnson.com>
 * @link http://github.com/andrewgjohnson/imagettftextblur
 * @license http://www.opensource.org/licenses/mit-license.php The MIT License
 * @version 1.0.0
 * @package imagettftextblur
 *
 */

if (!function_exists('imagettftextblur'))
{
    function imagettftextblur(&$image,$size,$angle,$x,$y,$color,$fontfile,$text,$blur_intensity = null)
    {
        $blur_intensity = !is_null($blur_intensity) && is_numeric($blur_intensity) ? (int)$blur_intensity : 0;
        if ($blur_intensity > 0)
        {
            $text_shadow_image = imagecreatetruecolor(imagesx($image),imagesy($image));
            imagefill($text_shadow_image,0,0,imagecolorallocate($text_shadow_image,0x00,0x00,0x00));
            imagettftext($text_shadow_image,$size,$angle,$x,$y,imagecolorallocate($text_shadow_image,0xFF,0xFF,0xFF),$fontfile,$text);
            for ($blur = 1;$blur <= $blur_intensity;$blur++)
                imagefilter($text_shadow_image,IMG_FILTER_GAUSSIAN_BLUR);
            for ($x_offset = 0;$x_offset < imagesx($text_shadow_image);$x_offset++)
            {
                for ($y_offset = 0;$y_offset < imagesy($text_shadow_image);$y_offset++)
                {
                    $visibility = (imagecolorat($text_shadow_image,$x_offset,$y_offset) & 0xFF) / 255;
                    if ($visibility > 0)
                        imagesetpixel($image,$x_offset,$y_offset,imagecolorallocatealpha($image,($color >> 16) & 0xFF,($color >> 8) & 0xFF,$color & 0xFF,(1 - $visibility) * 127));
                }
            }
            imagedestroy($text_shadow_image);
        }
        else
            return imagettftext($image,$size,$angle,$x,$y,$color,$fontfile,$text);
    }
}

添加阴影的方法如下:

imagettftextblur($image,$size,0,$x + 3,$y + 3,$shadow_color,$font,$string,1); // 1 can be higher to increase blurriness of the shadow
imagettftextblur($image,$size,0,$x,$y,$text_color,$font,$string);

将文本绘制两次。首先在文本位置的右侧和下方稍微绘制阴影文本(没有轮廓),然后按正常方式绘制文本。