Search code examples
phpcssfontsimagettftextbaseline

PHP GD2 : imagettftext on same position as rendered in HTML


To make the question simpler to understand, I've made this very simple script :

<?php
    if(!empty($_POST)){
        $img = imagecreatetruecolor(300,100);

        $font = "./custom_font/aquilinetwo-webfont.ttf";
        $dimensions = imagettfbbox($_POST['font_size'],0,$font,$_POST['font_value']);
        $x_pos = $_POST["font_pos_x"];
        $y_pos = $_POST["font_pos_y"]+abs($dimensions[7]);
        $color = imagecolorallocate($img, 255, 255, 255);
        imagettftext($img,$_POST['font_size'],0,$x_pos,$y_pos,$color,$font,$_POST['font_value']);

        imagepng($img, "./image.png");
    }
?>

<html>
<head>
    <script type="text/javascript" src="jquery-1.11.1.js"></script>
    <script type="text/javascript">
        $(function(){
            $("#form_font_value").keyup(function(){
                $("#myImage span").html($(this).val());
            });
            $("#form_font_size").keyup(function(){
                $("#myImage span").css("font-size",$(this).val()+"pt");
            });
            $("#form_font_x").keyup(function(){
                $("#myImage span").css("left",$(this).val()+"px");
            });
            $("#form_font_y").keyup(function(){
                $("#myImage span").css("top",$(this).val()+"px");
            });
        });
    </script>
    <style>
        @font-face {
            font-family: 'aquilinetworegular';
            src: url('./custom_font/aquilinetwo-webfont.eot');
            src: url('./custom_font/aquilinetwo-webfont.eot?#iefix') format('embedded-opentype'),
                 url('./custom_font/aquilinetwo-webfont.woff2') format('woff2'),
                 url('./custom_font/aquilinetwo-webfont.woff') format('woff'),
                 url('./custom_font/aquilinetwo-webfont.ttf') format('truetype'),
                 url('./custom_font/aquilinetwo-webfont.svg#aquilinetworegular') format('svg');
            font-weight: normal;
            font-style: normal;
        }

        #myImage        {background-color:#000;width:300px;height:100px;margin-bottom:20px;position:relative;}
        #myImage span   {position:absolute;font-family:"aquilinetworegular";font-size:<?php echo @$_POST["font_size"]?$_POST["font_size"]:"12";?>pt;top:<?php echo @$_POST["font_pos_y"]?$_POST["font_pos_y"]:"0";?>px;left:<?php echo @$_POST["font_pos_x"]?$_POST["font_pos_x"]:"0";?>px;color:#FFF;}
    </style>
</head>
<body>
    <div id="myImage">
        <span><?php echo @$_POST["font_value"]?$_POST["font_value"]:"YourText";?></span>
    </div>
    <form method="post">
        Value : <input type="text" name="font_value" id="form_font_value" value="<?php echo @$_POST["font_value"]?$_POST["font_value"]:"YourText";?>"><br/>
        Size : <input type="text" name="font_size" id="form_font_size" value="<?php echo @$_POST["font_size"]?$_POST["font_size"]:"12";?>">pt<br/>
        Position X :<input type="text" name="font_pos_x" id="form_font_x" value="<?php echo @$_POST["font_pos_x"]?$_POST["font_pos_x"]:"0";?>">px<br/>
        Position Y :<input type="text" name="font_pos_y" id="form_font_y" value="<?php echo @$_POST["font_pos_y"]?$_POST["font_pos_y"]:"0";?>">px<br/>
        <input type="submit">
    </form>
    <hr>
    <img src="image.png" alt="Send datas first">
</body>
</html>

What it must do ?

User choose where he want to put his text on an image. Then, the image is generated.

The problem :

The text is not placed on the correct Y axis position. Depending on the font family/size. The font-family can be changed. So I cannot "hard code" the position.

Where I think the problem can be :

imagettftext() doc says : argument Y is the position of the fonts baseline, not the very bottom of the character

So I suppose I need to add the height between the baseline and the top of the font to my Y position to get the exact same position as rendered in HTML/CSS. This is why I use the value 7 of imagettfbbox().

But it doesn't work. The Y position is sometimes good, sometimes bad. I don't understand why.

If you have an idea ... Thank you !

Result example :

enter image description here


Solution

  • After reading this post about a bounding box problem : PHP imagettftext return bounding box differs from rendered bounding box

    It changed my view on the problem. What if the font or the CSS is the problem ?

    I was trying to make GD2 render like displayed on HTML/CSS.

    BUT, the HTML/CSS use another variable that I've completely forgot : the line-height.

    In HTML : Text_center ~= margin_top+line_height/2. Where line_height can vary depending on text size or if changed by the CSS property.

    So, to get the exact same position between HTML render and GD2 render, I've setted the CSS property line-height to 0 to ignore it. And now, the position is perfectly identical.