Tim Barclay
Tim Barclay

Reputation: 855

Making ttf characters touch in an image with PHP

I'd really appreciate the help of anyone with more PHP experience than me.

I'm using PHP to generate close-packed text images. So far, it works like this:

  1. First it generates a random string of x number of characters.
  2. Then it makes an image with background etc.
  3. It places the first character in a specific place (with some randomising of the size, rotation etc)
  4. Then it places the next character so that the bottom left corner of its bounding box is at the same point as the bottom right corner of the bounding box of the character before (plus some randomness etc). The code for that goes like this:

    $coords = array();
    $pos_y = $this->image_height / 2;
    
    for ($counter = 0; $counter < $this->code_length; $counter++){
        $sbox = @imagettfbbox($size, $angle, $font, $this->code[$counter]);
        if($counter == 0)
            $pos_x = $this->image_width / $this->code_length;
        else
            // element 2 is the x co-ord of the bottom right corner of the ttf box
            $pos_x = $coords[$counter-1][2];
        @imagettftext($this->image, $size, $angle, 
             $pos_x, $pos_y, $fontcolor, $font, $this->code[$counter]);
    }
    
  5. and repeat 4 for each subsequent character in the string.

What I want is for, as much as possible, every character to be touching its neighbour(s). What I've done so far works fine for characters like 'M' where the bottom corners of the glyph are more or less in the corners of the bounding box, but it's nowhere close for a letter like 'G' or 'I'.

Does anyone know of a way to get the actual dimensions of a ttf glyph rather than just the bounding box? Or can anyone think of any better way to approach this problem?

Any thoughts/ideas/advice much appreciated.

Upvotes: 0

Views: 332

Answers (1)

the bounding box is simply that - the box that indicates the min/max x and y values for the text. If you have the letter C and the letter O, making their bounding boxes touch will never make the actual letters touch, because the line the two letters are joined on has the C at the top and bottom, and the O in the middle.

If you want to make sure the letters touch, you'll have to get the glyph outline data, instead, and either use clever algorithms that find projection points for glyph 1 on glyph 2, or use a naive minmax algorithm where you put the two next to each other, rasterise them with a transparent color, see if any of the pixels coloured are darker than they should be, if so, move the letters apart by distance D, try again, if they don't overlap, move back together by distance D/2, if they overlap, move out again by D/4, if they don't, move in more by D/4, then correct with D/8, D/16, etc until the distance is less than a pixel.

Bounding box aligning is cheap and easy, what you want to do is, unfortunately, not both. It can be cheap (but then the algorithm is hard) or easy (but then the algorithm is expensive).

(should you want to give using glyph outline data a try, you can try to use FreeType2, or something like https://github.com/pomax/php-font-parser)

Upvotes: 1

Related Questions