Comment puis-je envelopper du texte en utilisant Imagick en PHP pour qu'il soit dessiné comme du texte multiligne?

la bibliothèque Imagick en PHP vous permet de dessiner du texte sur une image. Comment dire à Imagick d'envelopper le texte à partir d'une zone de texte délimitée?

, c'est-à-dire que les mots apparaissent sous forme de texte à plusieurs lignes plutôt que sous forme d'une seule ligne.

5
demandé sur Danack 2011-04-21 19:49:24

5 réponses

Utilisation:

list($lines, $lineHeight) = wordWrapAnnotation($image, $draw, $msg, 140);
for($i = 0; $i < count($lines); $i++)
    $image->annotateImage($draw, $xpos, $ypos + $i*$lineHeight, 0, $lines[$i]);

fonction:

/* Implement word wrapping... Ughhh... why is this NOT done for me!!!
    OK... I know the algorithm sucks at efficiency, but it's for short messages, okay?

    Make sure to set the font on the ImagickDraw Object first!
    @param image the Imagick Image Object
    @param draw the ImagickDraw Object
    @param text the text you want to wrap
    @param maxWidth the maximum width in pixels for your wrapped "virtual" text box
    @return an array of lines and line heights
*/
function wordWrapAnnotation(&$image, &$draw, $text, $maxWidth)
{
    $words = explode(" ", $text);
    $lines = array();
    $i = 0;
    $lineHeight = 0;
    while($i < count($words) )
    {
        $currentLine = $words[$i];
        if($i+1 >= count($words))
        {
            $lines[] = $currentLine;
            break;
        }
        //Check to see if we can add another word to this line
        $metrics = $image->queryFontMetrics($draw, $currentLine . ' ' . $words[$i+1]);
        while($metrics['textWidth'] <= $maxWidth)
        {
            //If so, do it and keep doing it!
            $currentLine .= ' ' . $words[++$i];
            if($i+1 >= count($words))
                break;
            $metrics = $image->queryFontMetrics($draw, $currentLine . ' ' . $words[$i+1]);
        }
        //We can't add the next word to this line, so loop to the next line
        $lines[] = $currentLine;
        $i++;
        //Finally, update line height
        if($metrics['textHeight'] > $lineHeight)
            $lineHeight = $metrics['textHeight'];
    }
    return array($lines, $lineHeight);
}
24
répondu BMiner 2011-08-17 05:54:20

j'ai trouvé un bug avec la fonction de @BMiner où il retourne une lineheight de 0 quand il n'y a qu'un mot.

j'ai fini par le réécrire en une boucle en utilisant des fonctions array. J'ai gardé les paramètres les mêmes donc ça fonctionne avec les implémentations actuelles.

j'ai utilisé preg_split à la place de sorte qu'il fonctionne bien avec des espaces supplémentaires ou doubles, des onglets, et des sauts de ligne.

function wordWrapAnnotation($image, $draw, $text, $maxWidth)
{
    $words = preg_split('%\s%', $text, -1, PREG_SPLIT_NO_EMPTY);
    $lines = array();
    $i = 0;
    $lineHeight = 0;

    while (count($words) > 0)
    {
        $metrics = $image->queryFontMetrics($draw, implode(' ', array_slice($words, 0, ++$i)));
        $lineHeight = max($metrics['textHeight'], $lineHeight);

        if ($metrics['textWidth'] > $maxWidth or count($words) < $i)
        {
            $lines[] = implode(' ', array_slice($words, 0, --$i));
            $words = array_slice($words, $i);
            $i = 0;
        }
    }

    return array($lines, $lineHeight);
}
7
répondu Sarke 2014-02-05 08:53:11

j'utilise la version de @Sarke avec succès depuis un certain temps, mais j'ai remarqué qu'il y a une boucle infinie si un mot est plus long que $maxWidth. Voici une version qui corrige la boucle infinie:

function wordWrapAnnotation($image, $draw, $text, $maxWidth)
{   
    $text = trim($text);

    $words = preg_split('%\s%', $text, -1, PREG_SPLIT_NO_EMPTY);
    $lines = array();
    $i = 0;
    $lineHeight = 0;

    while (count($words) > 0)
    {   
        $metrics = $image->queryFontMetrics($draw, implode(' ', array_slice($words, 0, ++$i)));
        $lineHeight = max($metrics['textHeight'], $lineHeight);

        // check if we have found the word that exceeds the line width
        if ($metrics['textWidth'] > $maxWidth or count($words) < $i) 
        {   
            // handle case where a single word is longer than the allowed line width (just add this as a word on its own line?)
            if ($i == 1)
                $i++;

            $lines[] = implode(' ', array_slice($words, 0, --$i));
            $words = array_slice($words, $i);
            $i = 0;
        }   
    }   

    return array($lines, $lineHeight);
}
4
répondu John Langford 2017-05-23 11:46:27

voici ma version pour un conteneur de texte de ligne

function GetTextSize($font,$text,$max_weight,$max_width){
$size = $max_weight;
$imagick=new Imagick();
while (true){
    $draw = new ImagickDraw();
    $draw->setFontSize($size);
    $draw->setfont($font);
    $bbox2=$imagick->queryFontMetrics($draw,$text);
    $width_of_text = $bbox2[textWidth];
    if ($width_of_text > $max_width){
        $size -= 1;
    }else{
        break;
        }
    }
    return $size;
}
$draw = new ImagickDraw();
$font="path_to_font.ttf";
$text="Love Happyness Freedom";
$output = new Imagick('path_to_image.jpg');
$output->setGravity(Imagick::GRAVITY_CENTER);
$fontsize=GetTextSize($font,$text,70,600);
$draw->setfont($font);
$draw->setFontSize($fontsize);
$draw->annotation(000, 000, $text);
$output->drawImage($draw);
$output->setImageFormat('jpg');
header('Content-Type: image/jpg');
print $output;
0
répondu Yuretz 2015-03-20 16:28:10

Salut je trouve de la solution merci pour BMinner pour son code je modifie son code et obtenir une bonne solution de travail

UTILISATION

<?
   $w = 210;
 $h = 520;


$canvas = new Imagick();
$canvas->newImage($w,$h,new ImagickPixel('green'),'png');


$draw = new ImagickDraw();
$draw->setFontSize(25);

$text="SomeTextWithoutSpacesAndGoingOn..xxxxx <br><br>some short words with spaces <br><br>and some text<br>with manuel page<br>break <br><br>and also multiple spaces                      spaces end. also w i t o n e c ha ra c ter";

 list($lines, $lineHeight)= wordWrapAnnotation($canvas, $draw, $text, $w-20);

 $canvas->annotateImage($draw, 10, $lineHeight , 0, $lines);

 header("Content-Type: image/png");
   echo $canvas;

?>

fonctions RÉFÉRANCÉES de BMinner

<?
//this is unicode split method for out of english latin characters
function str_split_unicode($str, $l = 0) {
    if ($l > 0) {
        $ret = array();
        $len = mb_strlen($str, "UTF-8");
        for ($i = 0; $i < $len; $i += $l) {
            $ret[] = mb_substr($str, $i, $l, "UTF-8");
        }
        return $ret;
    }
    return preg_split("//u", $str, -1, PREG_SPLIT_NO_EMPTY);
} 










//this is my function detects long words and split them 

 function check_long_words($image,$draw,$text,$maxWidth) {
    $metrics = $image->queryFontMetrics($draw, $text);
    if($metrics['textWidth'] <= $maxWidth)
    return array($text);

$words = str_split_unicode($text);



$i = 0;

 while($i < count($words) )
    {
        $currentLine = $words[$i];
        if($i+1 >= count($words))
        {

             $lines[] = $currentLine;
            //$lines = $lines + $checked;
            break;
        }
        //Check to see if we can add another word to this line
        $metrics = $image->queryFontMetrics($draw, $currentLine . $words[$i+1]);

        while($metrics['textWidth'] <= $maxWidth)
        {
            //If so, do it and keep doing it!
            $currentLine .= $words[++$i];
            if($i+1 >= count($words))
                break;
            $metrics = $image->queryFontMetrics($draw, $currentLine . ' ' . $words[$i+1]);
            $t++;
        }
        //We can't add the next word to this line, so loop to the next line


            $lines[] = $currentLine;

        $i++;

    }


return $lines;

}   








//this is BMiner code some fixes for manule breaks
function wordWrapAnnotation(&$image, &$draw, $text, $maxWidth)
{
    $brler = explode("<br>", $text);
    $lines = array();


    foreach($brler as $br)
    {
        $i = 0;


$words = explode(" ", $br);


 while($i < count($words) )
    {

        $currentLine = $words[$i];


 $metrics = $image->queryFontMetrics($draw, $currentLine . ' ' . $words[$i+1]);        

        if($i+1 >= count($words))
        {
            $checked=check_long_words($image,$draw,$currentLine,$maxWidth);
            $lines = array_merge($lines, $checked);

            if($metrics['textHeight'] > $lineHeight)
            $lineHeight = $metrics['textHeight'];
            //$lines = $lines + $checked;
            break;
        }
        //Check to see if we can add another word to this line


        while($metrics['textWidth'] <= $maxWidth)
        {
            //If so, do it and keep doing it!
            $currentLine .= ' ' . $words[++$i];
            if($i+1 >= count($words))
                break;
            $metrics = $image->queryFontMetrics($draw, $currentLine . ' ' . $words[$i+1]);
            $t++;
        }
        //We can't add the next word to this line, so loop to the next line

        $checked=check_long_words($image,$draw,$currentLine,$maxWidth);
            $lines = array_merge($lines, $checked);

        $i++;
        //Finally, update line height
        if($metrics['textHeight'] > $lineHeight)
            $lineHeight = $metrics['textHeight'];
    }




    }
    return array(join("\n",$lines), $lineHeight);



}

?>

ET SORTIE

enter image description here

-1
répondu Onur Öztürk 2014-11-05 06:01:11