doumi7861 2016-06-11 17:43
浏览 151

如何使用IMagick为图像添加多行/自动装配,最大宽度的动态文本?

I've been through several solutions, and can't quite find a fast, efficient way to add dynamic, multi-line text/caption/annotation to an image using IMagick.

The script would take JSON data for several text areas to apply to an image, and the data includes all the font attributes: stroke, color, drop shadow, alignment, X & Y location (for the upper left corner), maximum width and rotation.

I've tried several methods of annotation and captions and simply can't get the text to behave. Here's what I'd like to be able to do:enter image description here

And here's my code so far:

    $data = '{
    "baseImage" : "test-image.jpg",
    "fields" : [
        {
            "name" : "name",
            "default" : "You"
        },
        {
            "name" : "email",
            "default" : "you@yoursite.com"
        }
    ],
    "textareas": [
        {
            "font": "Alpha-Echo",
            "align" : "left",
            "size" : 24,
            "color" : "#990000",
            "stroke" : {
                "color" : "#000000",
                "width" : 0
            },
            "shadow" : {
                "x" : 2,
                "y" : 2,
                "blur" : 6,
                "color" : "#000000",
                "opacity" : 0.5
            },
            "width" : 400,
            "rotation" : 0,
            "x" : 10,
            "y" : 10,
            "text" : "Welcome, {name}! How are you doing today?"
        }
    ]
}';

$json = json_decode($data);
$imgBase->setBackgroundColor(new ImagickPixel('transparent'));
$imgBase->readImage($json->baseImage);
$imgBase->setImageFormat('png');

// get image dimensions
$w = $imgBase->getImageWidth();
$h = $imgBase->getImageHeight();

// loop through the textareas and fields
foreach($json->textareas as $textarea){

    $captionHeight = $h - $textarea->y;

    $drawText = $textarea->text;

    foreach($json->fields as $field){
        $fieldText = (!empty($_GET[$field->name]))? $_GET[$field->name] : $field->default;
        $drawText = str_replace ('{' . $field->name . '}' , $fieldText , $drawText);
    }

    // create the caption
    $theText = new Imagick();
    $theText->newImage($textarea->width, $captionHeight, new ImagickPixel('transparent'));

    $draw = new ImagickDraw();
    if($textarea->stroke->width > 0){
        $draw->setStrokeOpacity(1);
        $draw->setStrokeColor($textarea->stroke->color);
        $draw->setStrokeWidth($textarea->stroke->width);
        $draw->setStrokeAntialias(true);
    }
    $draw->setGravity(1); // NORTH
    $draw->setTextAlignment($alignment[$textarea->align]); // left = 1, center = 2, right = 3
    $draw->setTextAntialias(true);
    $draw->setFont($textarea->font);
    $draw->setFontSize($textarea->size);
    $draw->setFillColor($textarea->color);
    $draw->rotate($textarea->rotation);

    $draw->annotation($textarea->x, $textarea->y, $drawText);
    $imgBase->drawImage($draw);
}
echo $imgBase->getImageBlob();

The issues I'm having are

  1. autowrapping text
  2. keeping it to a max width
  3. positioning (centering puts the text up and to the left as opposed to horizontally centering text, etc)

I'm assuming it can be done - it's available in the command line version of ImageMagick (http://www.imagemagick.org/Usage/text/#caption_bestfit) but IMagick is a different story. Any help is greatly appreciated!

  • 写回答

1条回答 默认 最新

  • dotj78335 2016-06-13 13:26
    关注

    This is more of a comment then an answer, but ran long.

    If your already invoking a new temporary Imagick instances with $theText, then why not just follow the caption bestfit technique, and composite (not draw) the resulting image over the base image?

    $theText = new Imagick();
    // Apply all font attributes.
    ... // omitted
    // Create a `caption:` pseudo image that only manages text.
    $theText->newPseudoImage($textarea->width,
                             $imgBase->height, 
                             'caption:'.$textarea->text);
    // Remove extra height.
    $theText->trimImage(0.0);
    // Compiste bestfit caption over base image.
    $imgBase->compositeImage($theText, 
                             Imagick::COMPOSITE_ATOP,
                             $textarea->x,
                             $textarea->y);
    
    评论

报告相同问题?