2015-12-04 6 views
6

Ho il seguente codice per stampare il testo su un'immagine. Sto anche aggiungendo una casella di debug intorno al testo. Tuttavia, ho notato che il testo a sinistra si trova al di fuori del riquadro che PHP mi dà con imagettfbbox.Come account per lo swash di font con PHP e GD

enter image description here

Questo appare come un problema con lo sciabordio font. Esiste comunque una spiegazione per questo? Posso calcolare la distanza tra l'inizio dello sciabordio e la posizione attuale imagettfbbox?

Non penso che questo sia un problema con il font, come ho provato con alcuni font di stile di script ei risultati erano simili.

<?php 

$font  = 'scriptin.ttf'; 
$text  = 'Ipsum'; 
$size  = 30; 
$image  = imagecreatetruecolor(200, 200); 
$fontColour = imagecolorallocate($image, hexdec('11'), hexdec('11'), hexdec('11')); 
$bgColour = imagecolorallocate($image, hexdec('CC'), hexdec('CC'), hexdec('CC')); 

imagefilledrectangle($image, 0, 0, 200, 200, $bgColour); 

$dimensions = imagettfbbox($size, 0, $font, $text); 
imagefilledrectangle(
    $image, 
    $dimensions[0] + 40, 
    $dimensions[7] + 50, 
    $dimensions[2] + 40, 
    $dimensions[3] + 50, 
    imagecolorallocate($image, mt_rand(1, 180), mt_rand(1, 180), mt_rand(1, 180)) 
); 

imagettftext(
    $image, 
    $size, 
    0, 
    40, 
    50, 
    $fontColour, 
    $font, 
    $text 
); 

header('Content-Type: image/png'); 
imagepng($image); 

Il codice e il tipo di carattere è disponibile qui: https://github.com/AydinHassan/image-swash-example

Se si punta una VHOST al repository, si può solo colpire swash.php

+0

sembra che tu non abbia posizionato correttamente il riquadro: la quantità di spazio "mancante" a sinistra sembra identica alla quantità di spazio "troppo" a destra. –

+0

Questo è quello che pensavo, ma se lo sono, non riesco a vedere dove sto sbagliando. Sto usando l'informazione 'imagettfbbox' mi sta dando. –

+1

http://php.net/manual/en/function.imagettfbbox.php#97211 suggerisce che si tratta di un bug noto, se scomodo. –

risposta

2

Edit: Questo sembra essere fissato in PHP (bug #53504) quindi il codice qui sotto non dovrebbe essere richiesto.


Sulla base di un comment in the PHP manual ho scritto la seguente funzione per calcolare e restituire la differenza tra dove GD pensa il lato sinistro del rettangolo di selezione è e dove il pixel più a sinistra si trova:

function xadjust($size, $angle, $fontfile, $text) 
{ 
    $bbox = imagettfbbox($size, $angle, $fontfile, $text); 

    $width = $bbox[4] - $bbox[6]; // upper right x - upper left x; 
    $height = $bbox[1] - $bbox[7]; // lower left y - upper left y; 

    // create an image with height and width doubled to fit any 'swash'. 
    $im = imagecreatetruecolor($width * 2, $height * 2); 

    // set background color to opaque black. 
    imagefill($im, 0, 0, 0x00000000); 

    // draw the text in opaque white. 
    imagettftext(
     $im, 
     $size, 
     0, 
     $width/2, 
     $height, 
     0x00ffffff, 
     $fontfile, 
     $text 
    ); 

    // set the min-width to its possible maximum. 
    $min_x = $width * 2; 

    for ($x = 0; $x < $width * 2; $x++) { 
     // each x-pixel (horizontal) 
     for ($y = 0; $y < $height * 2; $y++) { 
      // each y-pixel (vertical) 
      if (imagecolorat($im, $x, $y) > 0) { 
       // non-black pixel found! 
       $min_x = min($x, $min_x); 
      } 
     } 
    } 

    imagedestroy($im); 

    // return the difference between where GD thinks the bounding box is and 
    // where we found the leftmost non-black pixel. 
    return (($width/2) - $min_x) - abs($bbox[0]); 
} 

Questo può essere integrato al vostro script abbastanza facilmente:

$font  = 'scriptin.ttf'; 
$text  = 'Ipsum'; 
$size  = 30; 
$image  = imagecreatetruecolor(200, 200); 
$fontColour = imagecolorallocate($image, hexdec('11'), hexdec('11'), hexdec('11')); 
$bgColour = imagecolorallocate($image, hexdec('CC'), hexdec('CC'), hexdec('CC')); 

imagefilledrectangle($image, 0, 0, 200, 200, $bgColour); 

$xadjust = xadjust($size, 0, $font, $text); // 1. get the adjust value. 

$dimensions = imagettfbbox($size, 0, $font, $text); 
imagefilledrectangle(
    $image, 
    $dimensions[0] + 40 - $xadjust, // 2. move the left-side of the box to the left. 
    $dimensions[7] + 50, 
    $dimensions[2] + 40 - $xadjust, // 3. move the right-side of the box to the left. 
    $dimensions[3] + 50, 
    imagecolorallocate($image, mt_rand(1, 180), mt_rand(1, 180), mt_rand(1, 180)) 
); 

imagettftext(
    $image, 
    $size, 
    0, 
    40, 
    50, 
    $fontColour, 
    $font, 
    $text 
); 

header('Content-Type: image/png'); 
imagepng($image); 

Questo mi dà il seguente risultato:

script result

L'ho eseguito con pochi altri tipi di carattere e dimensioni e sembra accurato all'interno di 1 pixel.

+1

Mi sono ritrovato con qualcosa di simile. Tranne che ho contato all'indietro, il che mi ha fatto perdere un sacco di tempo per le immagini di grandi dimensioni. Ho anche eseguito un controllo preliminare, eseguendo il rendering del testo in un'immagine temporanea e controllando se ci fossero dei pixel nella prima colonna. Avevo bisogno di queste ottimizzazioni dato che eseguiremo il rendering in serie di queste immagini. Grazie! –

Problemi correlati