-
-
Save clifgriffin/728cc3a4ce7b81fa2d8a to your computer and use it in GitHub Desktop.
| <?php | |
| /** | |
| * Auto Fit Text To Image | |
| * | |
| * Write text to image using a target width, height, and starting font size. | |
| * | |
| * @author Clif Griffin | |
| * @url http://cgd.io/2014/auto-fit-text-to-an-image-with-php-and-wordpress | |
| * | |
| * @access public | |
| * @param bool $canvas_image_filename (default: false) The base image. | |
| * @param string $dest_filename (default: 'output.jpg') The output filename. | |
| * @param string $text (default: '') The text being written. | |
| * @param int $starting_font_size (default: 60) The starting (max) font size. | |
| * @param int $max_height (default: 500) The maximum height in lines of text. | |
| * @param int $x_pos (default: 0) X position in pixels for first line of text. | |
| * @param int $y_pos (default: 0) Y position in pixels for first line of text. | |
| * @param bool $font_file (default: false) Path to font file (.ttf) | |
| * @param string $font_color (default: 'black') The color. Also accepts rgba values. Example: "rgba(0,0,0,0.5)" | |
| * @param int $line_height_ratio (default: 1) Allows scaling the line height. Should be between 0.1 and 1. | |
| * @param string $dest_format (default: 'jpg') Output format. | |
| * @return bool True: success, False: failure | |
| */ | |
| function autofit_text_to_image( $canvas_image_filename = false, $dest_filename = 'output.jpg', $text = '', $starting_font_size = 60, $max_width = 500, $max_height = 500, $x_pos = 0, $y_pos = 0, $font_file = false, $font_color = 'black', $line_height_ratio = 1, $dest_format = 'jpg' ) { | |
| // Bail if any essential parameters are missing | |
| if ( ! $canvas_image_filename || ! $dest_filename || empty($text) || ! $font_file || empty($font_color) || empty($max_width) || empty($max_height) ) return false; | |
| // Do we have a valid canvas image? | |
| if ( ! file_exists($canvas_image_filename) ) return; | |
| $canvas_handle = fopen( $canvas_image_filename, 'rb' ); | |
| // Load image into Imagick | |
| $NewImage = new Imagick(); | |
| $NewImage->readImageFile($canvas_handle); | |
| // Instantiate Imagick utility objects | |
| $draw = new ImagickDraw(); | |
| $pixel = new ImagickPixel( $font_color ); | |
| // Load Font | |
| $font_size = $starting_font_size; | |
| $draw->setFont($font_file); | |
| $draw->setFontSize($font_size); | |
| // Holds calculated height of lines with given font, font size | |
| $total_height = 0; | |
| // Run until we find a font size that doesn't exceed $max_height in pixels | |
| while ( 0 == $total_height || $total_height > $max_height ) { | |
| if ( $total_height > 0 ) $font_size--; // we're still over height, decrement font size and try again | |
| $draw->setFontSize($font_size); | |
| // Calculate number of lines / line height | |
| // Props users Sarke / BMiner: http://stackoverflow.com/questions/5746537/how-can-i-wrap-text-using-imagick-in-php-so-that-it-is-drawn-as-multiline-text | |
| $words = preg_split('%\s%', $text, -1, PREG_SPLIT_NO_EMPTY); | |
| $lines = array(); | |
| $i = 0; | |
| $line_height = 0; | |
| while ( count($words) > 0 ) { | |
| $metrics = $NewImage->queryFontMetrics( $draw, implode(' ', array_slice($words, 0, ++$i) ) ); | |
| $line_height = max( $metrics['textHeight'], $line_height ); | |
| if ( $metrics['textWidth'] > $max_width || count($words) < $i ) { | |
| $lines[] = implode( ' ', array_slice($words, 0, --$i) ); | |
| $words = array_slice( $words, $i ); | |
| $i = 0; | |
| } | |
| } | |
| $total_height = count($lines) * $line_height * $line_height_ratio; | |
| if ( $total_height === 0 ) return false; // don't run endlessly if something goes wrong | |
| } | |
| // Writes text to image | |
| for( $i = 0; $i < count($lines); $i++ ) { | |
| $NewImage->annotateImage( $draw, $x_pos, $y_pos + ($i * $line_height * $line_height_ratio), 0, $lines[$i] ); | |
| } | |
| $NewImage->setImageFormat($dest_format); | |
| $result = $NewImage->writeImage($dest_filename); | |
| return $result; | |
| } |
^ same problem, subscribed
does the alignment for the text always have to be "left" ?
for very long words to work the second while loop should look like this:
if ( $metrics['textWidth'] > $max_width || count($words) < $i ) {
// this indicates long words and forces the font to decrease in the first loop
if($i == 1){
$total_height = $max_height + 1;
continue 2;
}
$lines[] = implode( ' ', array_slice($words, 0, --$i) );
$words = array_slice( $words, $i );
$i = 0;
}Center alignment could be done with this:
$draw->setGravity(\Imagick::GRAVITY_CENTER);But you need to adjust annotations vertical position because first line is placed right in the middle
for( $i = 0, $c = count($lines), $gravity_fix = ($total_height / 2 - $line_height / 2) ; $i < $c; $i++ )
{
$layerTextHeader->annotateImage( $draw, $x, $y + ($i * $line_height * $line_height_ratio) - $gravity_fix, 0, $lines[$i] );
}Also I would check the $font_size for positive values - just return if $font_size < 1 right after decreasing
@konoknir Hi, Thank you for your solution. Сan you suggest solutions so that with transition to another line, you can display the text, because now everything is together. Very necessary.
@clifgriffin Thank you very much!
Сan you suggest solutions so that with transition to another line, you can display the text, because now everything is together. Very necessary.
Great script - thank you! I just have one problem and can't find a solution: If the text contains a very long word that's width is greater than the max_width the script dies on line 64. Any idea?