How to Wrap Text Using Imagick in PHP So That It Is Drawn as Multiline Text

How can I wrap text using Imagick in PHP so that it is drawn as multiline text?

I have been using @Sarke's version successfully for a while, but I noticed there is an infinite loop if a word is longer than the $maxWidth. Here is a version that fixes the infinite loop:

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

how to wrap text in imagemagick

Sine I could control the spacing I went with rendering the lines each

  $draw = new ImagickDraw();
$x = 0;
$y=20;
$angle = 0;
$padding = 10;
$str = "some text for testing of a word wrap in imagemagick";
$str = wordwrap($str, 10,"\r");
$str_array = explode("\n",$str);
foreach($str_array as $line)
$im->annotateImage( $draw, $x, $y+$padding, $angle, $line );
}

how to use imagick annotateImage for chinese text?

Full solution here:

https://gist.github.com/2971092/232adc3ebfc4b45f0e6e8bb5934308d9051450a4

Key ideas:

Must set the html charset and internal encoding on the form and on the processing page

header('Content-Type: text/html; charset=utf-8');
mb_internal_encoding('utf-8');

These lines must be at the top lines of the php files.

Use this function to determine if text is Chinese and use the right font file

function isThisChineseText($text) {
return preg_match("/\p{Han}+/u", $text);
}

For more details check out https://stackoverflow.com/a/11219301/80353

Set TextEncoding properly in ImagickDraw object

$draw = new ImagickDraw();

// set utf 8 format
$draw->setTextEncoding('UTF-8');

Note the Capitalized UTF. THis was helpfully pointed out to me by Walter Tross in his answer here: https://stackoverflow.com/a/11207521/80353

Use preg_match_all to explode English words, Chinese Words and spaces

// separate the text by chinese characters or words or spaces
preg_match_all('/([\w]+)|(.)/u', $text, $matches);
$words = $matches[0];

Inspired by this answer https://stackoverflow.com/a/4113903/80353

Works just as well for english text

Is there any way to find a specific pixel area that is surrounded by a black border with PHP and Imagick?

You can do that in ImageMagick command line using connected components. I do not know if PHP Imagick can do that. But you can check. Otherwise, just use PHP exec() to run my command.

The following is Unix syntax.

Input:

Sample Image

bbox=`convert Ef82Whf_d.webp -threshold 75% -type bilevel \
-define connected-components:exclude-header=true \
-define connected-components:area-threshold=500 \
-define connected-components:keep-top=1 \
-define connected-components:verbose=true \
-define connected-components:mean-color=true \
-connected-components 8 null: | \
grep "gray(255)" | tail -n +2 | awk '{print $2}'`
convert Ef82Whf_d.webp -crop $bbox +repage -shave 5x5 textbox_crop.png

Sample Image

ImageMagick best fit text within rectangle?

Updated Answer

With what I have now gathered, I think this may be your best option.

convert sea.jpg \( -size 173x50 -background none label:"A" -trim -gravity center -extent 173x50 \) -gravity northwest -geometry +312+66 -composite result.png

Sample Image

And this:

convert sea.jpg \( -size 173x50 -background none label:"A very much longer label" -trim -gravity center -extent 173x50 \) -gravity northwest -geometry +312+66 -composite result.png

Sample Image

Basically, I am using some "aside processing" in parentheses to generate the text and then compositing it onto the page afterwards. I generate the text with label: to the best automatic size, then trim off any excess space around the text. I then centre the trimmed text, using -gravity center and expand the background out (using -extent) so that the text box is always the same size, then I can position it (with -geometry) when compositing it relative to the top-left corner as I reset -gravity to NorthWest.

Original Answer

If you want ImageMagick to do its best to fit your text in a given box, you should use caption rather than annotate, label or -draw "text".

So you want to load your sea image, set the size for the caption, draw the caption and composite that onto the image at the correct spot using -geometry:

convert sea.jpg -size 173x50! caption:"Your text" -geometry +312+66 -composite result.png

Sample Image

Or, with longer text:

convert sea.jpg -size 173x50! caption:"A considerably longer text that will result in a smaller font being chosen" -geometry +312+66 -composite result.png

Sample Image


If you want a blank background, use -background none before caption:

convert sea.jpg -size 173x50! -background none caption:"Your text" -geometry +312+66 -composite result.png

Sample Image


If you want to centre your text, you can do that with PANGO, like this, but I believe you then give up the auto-sizing feature:

convert sea.jpg -size 173x50! -background none -gravity center pango:'<span foreground="yellow">ABC</span>' -gravity northwest -geometry +312+66 -composite result.png

Sample Image

Shadow text with ImageMagick

You just have to draw the shadow first then draw over it with the font

convert -size 500x500 xc:white -pointsize 35 -font arial-italic -gravity center       - fill red -draw "text 2,2 'text'" -fill black -draw "text 0,0 'text'" outfile.jpg


Related Topics



Leave a reply



Submit