Sign Up

Sign Up to our social questions and Answers Engine to ask questions, answer people’s questions, and connect with other people.

Have an account? Sign In

Have an account? Sign In Now

Sign In

Login to our social questions & Answers Engine to ask questions answer people’s questions & connect with other people.

Sign Up Here

Forgot Password?

Don't have account, Sign Up Here

Forgot Password

Lost your password? Please enter your email address. You will receive a link and will create a new password via email.

Have an account? Sign In Now

You must login to ask a question.

Forgot Password?

Need An Account, Sign Up Here

Please briefly explain why you feel this question should be reported.

Please briefly explain why you feel this answer should be reported.

Please briefly explain why you feel this user should be reported.

Sign InSign Up

The Archive Base

The Archive Base Logo The Archive Base Logo

The Archive Base Navigation

  • SEARCH
  • Home
  • About Us
  • Blog
  • Contact Us
Search
Ask A Question

Mobile menu

Close
Ask a Question
  • Home
  • Add group
  • Groups page
  • Feed
  • User Profile
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Buy Points
  • Users
  • Help
  • Buy Theme
  • SEARCH
Home/ Questions/Q 8763955
In Process

The Archive Base Latest Questions

Editorial Team
  • 0
Editorial Team
Asked: June 13, 20262026-06-13T15:54:26+00:00 2026-06-13T15:54:26+00:00

Question How do I appropriately match kerning from GD library in PHP (5.2.17) with

  • 0

Question

How do I appropriately match kerning from GD library in PHP (5.2.17) with SVG (1.1)?

Problem

PNG and SVG file text are not identical. Kerning seems to be off.

Situation

I have a web application which creates SVG files and image files (PNGs) from some text and positional data.

Currently, both implementations “work”, in as much as everything is being created. The SVG files work appropriately, the PNGs work appropriately. The issue that I’m having is that the text doesn’t line up. The kerning seems to be off.

The PNG is going to be our baseline (what we’re trying to replicate).

What I Want

I want for the ‘l’ in “line”, to line up with the last ‘L’ of the second line.
Visualization of what is wrong

What I’ve Tried

  • I have made sure that I’m using the same font for both SVG and PNG files.
  • I have base64 encoded the fonts with the SVG, to make SURE that it’s the same font
  • I have sacrificed a goat.

Extra

  • The PHP will be boosted to 5.3, on all PHP 5.3 servers I’ve tried, I have the same output.
  • The SVG version can change too.
  • The SVG can use groupings and viewBoxes. I just don’t have a firm grasp on them yet.

Demo

http://resurrectionwebdesign.com/demo/demo_text.php

Source
Okay, there’s a good amount of source here. I tried to simplify it as much as possible; however, what’s left is necessary (at least for making it practically accessible for everyone).

<?php
   // Prepare Background Image
   $image_width  =  300;
   $image_height =  200;
   $bg           = imagecreatetruecolor($image_width, $image_height);

   // Make it transparent
   imagesavealpha($bg, true);
   $transparent_color = imagecolorallocatealpha($bg, 0, 0, 0, 127);
   imagefill($bg, 0, 0, imagecolorallocatealpha($bg, 0, 0, 0, 127));

   // Prepare black for the color to use
   $black = imagecolorallocate($bg, 0x00, 0x00, 0x00);

   // Prepare two lines of text.
   $line1['text']     = "Multiple words in a line.";
   $line1['height']   = 22;
   $line1['width']    = 233;
   $line1['pt']       = 17;
   $line1['font']     = "ARIAL.TTF";
   $line1['font_fam'] = 'Arial';
   $line1['x']        = 24;
   $line1['y']        = 94;
   $line1['angle']    = 0;

   $line2['text']     = "Last up last L";
   $line2['height']   = 25;
   $line2['width']    = 160;
   $line2['pt']       = 20.25;
   $line2['font']     = "ARIAL.TTF";
   $line2['font_fam'] = 'Arial';
   $line2['x']        = 68;
   $line2['y']        = 118;

   imagettftext( $bg, 
                 $line1['pt'], 
                 $line1['angle'], 
                 $line1['x'],
                 $line1['y'],
                 $line1['color'],
                 $line1['font'],
                 $line1['text']);

   imagettftext( $bg, 
                 $line2['pt'], 
                 $line2['angle'], 
                 $line2['x'],
                 $line2['y'],
                 $line2['color'],
                 $line2['font'],
                 $line2['text']);

   // Save the PNG file.
   $im = imagepng($bg, 'text_align.png');
   imagedestroy($bg);

   // Prepare SVG
   $svg = <<< EOT
       <svg xmlns="http://www.w3.org/2000/svg"
         xmlns:xlink="http://www.w3.org/1999/xlink"
         xmlns:ev="http://www.w3.org/2001/xml-events" 
         width="{$image_width}px" 
         height="{$image_height}px"
         baseProfile="full"
         version="1.1">
EOT;

   // Line 1
   $svg .= "\r\n\t<text x='{$line1['x']}' y='{$line1['y']}'";
   $svg .= "font-size='{$line1['pt']}pt'  font-family='{$line1['font_fam']}'";
   $svg .= "fill='rgb(0,0,0)'>{$line1['text']}</text>";
   // Line 2
   $svg .= "\r\n\t<text x='{$line2['x']}' y='{$line2['y']}'";
   $svg .= "font-size='{$line2['pt']}pt'  font-family='{$line2['font_fam']}'";
   $svg .= "fill='rgb(0,0,0)'>{$line2['text']}</text>";

   // Close SVG
   $svg .= "\r\n</svg>";

   $file = fopen('text_align.svg', 'w');
   fwrite($file, $svg);
   fclose($file);   

   if(isset($_GET['download']) && !empty($_GET['download']))
   {
      if($_GET['download'] == 'SVG')
      {
         $file   = 'text_align.svg';
         $header = "Content-type: image/svg+xml";
      }
      elseif($_GET['download'] == 'IMAGE')
      {
         $file   = 'text_align.png';
         $header = "Content-type: image/png";
      }
      if(isset($header))
      {
         header($header);
         header('Content-Disposition: attachment; filename="'.$file.'"');
         echo file_get_contents($file);
      }
   }
   else
   {
?>   
<!doctype html>
<html>
   <body>
      Download Image: <a href="demo_text.php?download=IMAGE">Text Align PNG</a>
      <br /><img src='text_align.png' /><br />
      Download SVG: <a href="demo_text.php?download=SVG">Text Align SVG</a>
      <div style="border: 1px dotted blue;"><?echo $svg ?></div>
   </body>
</html>
<?
   }
?>

Updates / Progress

Update 1

I’m not sure if it has anything to do with the image being generated on the server, and the text being rendered on the client. I’m currently running a Windows build, but if I have to I’ll throw up a CentOS VM, and test the image on the VM as well as what the image looks like from a browser within the VM.

Update 2

I’ve tried embedding fonts every way that I know how. So far, the results are all the same. I’ll look at trying a transform to see if that works.

Update 3

Okay! Some progress! I found that the people from the SVG WG committee have suggested removing the doctype from the SVG document. I did, and now I’m getting some different results. I’m not sure how much better they are, BUT I’m definitely seeing different things now. So that’s a plus.

Update 4
I’ve tried explicitly setting the spacing between each character (instead of just the sentence), but still no dice. This seemed to offset everything even more. And looked uglier. Though the function works well and is useful for images (possibly analyzing CAPTCHAs?)

Here’s the code, if anyone is interested:

/**
* Function: Returns the space between letters, and the width of letters.
*           The first index is set to 0, as that is where it starts
*           Since spaces don't register (no pixels), strlen may not work.
* $image to analyze vertical gaps (from imagecreatetruecolor)
*/
function get_letter_dimensions($image)
{
   $bg           = imagecolorallocatealpha($image, 0, 0, 0, 127);
   $height       = imagesy($image) - 1; // was causing issues without
   $width        = imagesx($image);
   $bottom       = 0;
   $right        = 0;
   $letter_space = array(0=>0); // This holds the pixels between the letters
   $letter_width = array(0=>0); // This holds the width of the letters
   $y            = 0;
   $spacing      = 0;
   $lettering    = 0;
   $data         = array();

   for ($x = 0 ; $x < $width ; $x++) 
   {
      while((imagecolorat($image, $x, $y) == $bg) && ($y < ($height))) $y++;

      if($y == $height) 
      {
         if($lettering) $letter_width[] = $lettering;
         $lettering = 0;
         $spacing++;
      }
      else
      {
         if($spacing) $letter_space[] = $spacing;
         $spacing = 0;
         $lettering++;
      }
      $y = 0;
   }

   foreach($letter_space as $k=>$val) $data[$k] = $val + $letter_width[$k];

   return $data;      
}

Update 5

The mighty attribute called “textLength” has been some help to me! I haven’t gotten it to work COMPLETELY yet, BUT it’s definitely a marked improvement. There are still some scaling issues that I’m having. I’m not sure if it’s acceptable yet, however, it’s pretty close.

Update 6

Here is what I’ve found the textLength element doing:

enter image description here

So, as you can see, the second line “Line up last L” look pretty much perfect, as far as lining up goes, WITHOUT textLength. However, the first line “Multiple words in a line” looks terrible. Everything is WAY off. WITH textLength, however, it seems to be a much closer fit.

Update 7

I think I solved it. Instead of just doing “textLength” and setting it to the length provided, I adjusted it by 2px, and it lines up pretty well. The tiny differences could simply be because of pixel width on the server vs the granularity of the SVG placement. I don’t know if there’s really anything more I can do to change it. I’m sure there is, but I’m going to answer my own question and mark it as solved.

  • 1 1 Answer
  • 0 Views
  • 0 Followers
  • 0
Share
  • Facebook
  • Report

Leave an answer
Cancel reply

You must login to add an answer.

Forgot Password?

Need An Account, Sign Up Here

1 Answer

  • Voted
  • Oldest
  • Recent
  • Random
  1. Editorial Team
    Editorial Team
    2026-06-13T15:54:27+00:00Added an answer on June 13, 2026 at 3:54 pm

    OP, it’s me again, OP. I just solved my problem, as closely as I’ll be able to, that is.

    I modified the text element generation of the SVG portion.

    Previously

    $svg .= "fill='rgb(0,0,0)'>{$line2['text']}</text>";
    

    Modification

    $line2['width'] = $line2['width'] + 2;
    $svg .= "fill='#000' textLength='{$line2['width']}px'>$line2['text']}</text>";
    

    This is going to have to be sufficient. Thank you, @feeela, for your help. It was much appreciated.

    To any future people who read this question, I hope my plumb into insanity was beneficial to you too.

    • 0
    • Reply
    • Share
      Share
      • Share on Facebook
      • Share on Twitter
      • Share on LinkedIn
      • Share on WhatsApp
      • Report

Sidebar

Related Questions

I'm not sure this question is appropriate here but I hope I could get
Random question, sorry if not appropriate for stackoverflow, but I didn't think it would
Question from Object-Oriented JavaScript book: Imagine Array() doesn't exist and the array literal notation
This so a continuation of this question: I created textarea expander from script but
I've already looked myself but it seems my Google-fu is not strong today. I'm
First of all I am not sure if this question fits best on SO,
I'm new to iPhone dev, so this probably seems like a really silly question,
I hope this question is phrased appropriately to the policies of this site. I
I don't know if this question is titled appropriately. I have a sidebar populated
First of all, sorry if this isn't an appropriate question for StackOverflow. I've tried

Explore

  • Home
  • Add group
  • Groups page
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Users
  • Help
  • SEARCH

Footer

© 2021 The Archive Base. All Rights Reserved
With Love by The Archive Base

Insert/edit link

Enter the destination URL

Or link to existing content

    No search term specified. Showing recent items. Search or use up and down arrow keys to select an item.