Thiago Rodrigues Thiago Rodrigues - 2 months ago 15
PHP Question

How to align text based on its box size using PHP Imagick?

I'm puting some texts in a image at specifics positions X and Y. I also trying to align the text like we do in a box on Photoshop, but when I use $draw->setTextAlignment() I got a different result. See bellow:

Current result:

Current alignment

Desired result:

Desired alignment

The text and its properties (font name, size, color, etc) are dynamic, so the size can vary.

Can someone help me with that?

Code:

<?php

$draw = new \ImagickDraw();
$draw->setStrokeColor(new \ImagickPixel('black'));
$draw->setFillColor(new \ImagickPixel('red'));
$draw->setStrokeWidth(1);
$draw->setFontSize(36);

// First box
$draw->setTextAlignment(\Imagick::ALIGN_LEFT);
$draw->annotation(250, 75, "First line\nSecond Line");

// Second box
$draw->setTextAlignment(\Imagick::ALIGN_CENTER);
$draw->annotation(250, 210, "First line\nSecond Line");

// Third box
$draw->setTextAlignment(\Imagick::ALIGN_RIGHT);
$draw->annotation(250, 330, "First line\nSecond Line");

$draw->line(250, 0, 250, 500);

$image = new \Imagick();
$image->newImage(500, 500, new \ImagickPixel('transparent'));
$image->setImageFormat("png");
$image->drawImage($draw);

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


p.s. The vertical lines are used on these examples only to show the alignment differences.

Answer

I found the solution! See the result image and the explanation:

See the text boxes properly aligned

We can query the $draw object using Imagick::queryFontMetrics in order to know the text width and height - it also returns other information's not needed for this purpose, see:

Array returned by Imagick::queryFontMetrics

The X coordinate is the first argument of ImagickDraw::annotation and specifies where the text should be drawn on the horizontal axis of image.

With the width of text in our hands (textWidth) we can can calculate the correct X coordinate of text doing the following for each text alignment:

  • Left - use the X coordinate as is - nothing to do.
  • Center - sum the X coordinate + half width of text.
  • Right - sum the X coordinate + the entire width of text.

See the code in action:

<?php
$image = new \Imagick();

$draw = new \ImagickDraw();
$draw->setStrokeColor(new \ImagickPixel('black'));
$draw->setFillColor(new \ImagickPixel('red'));
$draw->setStrokeWidth(1);
$draw->setFontSize(36);
$text = "First line\nSecond Line";

// First box
$draw->setTextAlignment(\Imagick::ALIGN_LEFT);
$draw->annotation(250, 75, $text);

// Second box
$draw->setTextAlignment(\Imagick::ALIGN_CENTER);
$metrics = $image->queryFontMetrics($draw, $text);
$draw->annotation(250 + ($metrics['textWidth'] / 2), 210, $text);


// Third box
$draw->setTextAlignment(\Imagick::ALIGN_RIGHT);
$metrics = $image->queryFontMetrics($draw, $text);
$draw->annotation(250 + ($metrics['textWidth']), 330, $text);

$draw->line(250, 0, 250, 500);

$image->newImage(500, 500, new \ImagickPixel('transparent'));
$image->setImageFormat("png");
$image->drawImage($draw);

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

It outputs the image with the texts properly aligned.

For more info see the following references: