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