Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Gd and Imagick/Gmagick font problems #32

Closed
conf opened this issue Apr 13, 2011 · 6 comments
Closed

Gd and Imagick/Gmagick font problems #32

conf opened this issue Apr 13, 2011 · 6 comments

Comments

@conf
Copy link
Contributor

conf commented Apr 13, 2011

There are 2 main font problems for these libraries;

  1. Gd library has hard-coded resolution 96, while Imagick/Gmagick have 72 by default (tuneable), so Gd will produce larger symbols for same text, size, font than imagick. Workaround for this is to calculate Gd specific font size like this
    code>$size *= 72 / 96;

    So to handle this correctly Font (or maybe some other) class should respect current resolution.
    See also http://bugs.php.net/bug.php?id=15656
  2. Second problem is bounding box calculation. Gd does it pretty well (assuming it was provided correct font size to its resolution, see p.1) but Imagick gives much larger height than needed (possibly 15% larger than Gd). However it provides more exact width than Gd (about 5%) and some more useful information, such as ascender/descender height. The problem is that both libraries are inperfect in calculating bbox, so while Gd behaves better Imagick only users will suffer from its incorrect bbox calculation.
    Gmagick provides slightly different results from Imagick and it seems it doesn't support font antialiasing (see links in P.P.S. further)
    Ideas on solving this:
  3. Combine results from two libraries.
    Drawbacks: low performance, no library isolation
    Advantages: exact results
  4. Report about bugs to upstream
    Drawbacks: nobody knows when (and if) it will be done
    Advantage: library isolation, exact results
  5. Create own layer in Imagine
    Drawbacks: hard task (both libraries use FreeType as backend), possibly slow performance due to php implementation
    Advantage: library isolation, exact results

More?

P.S. I used imageftbbox for bbox calculation in GD and queryfontmetrics in Imagick.
P.P.S. Comparing results Imagick/Gmagick with Gd:
Imagick with GD: http://pastie.org/1794355 (save code on your computer by clicking download on left upper corner and open it in your browser)
Gmagick with GD: http://pastie.org/1794360 (same instrucations as above)
PHP code that was used for generation: http://pastie.org/1794364. For proper running you need a webserver with enabled gd with imagick either gmagick (but not both) and fix the path to the font in the beginning of the script.

@avalanche123
Copy link
Collaborator

So looks like GD calculates acceptable boxes and could be the standard to go with.
We need to modify FontInterface::box() to also accept desired resolution and default it to 96, like so box($string, $angle = 0, $resolution = 96)
From there we can proportionally modify the box size based on 96 as the base resolution as it appears to be hard-coded in gd library here - http://svn.php.net/viewvc/php/php-src/trunk/ext/gd/libgd/gd.h?view=markup#l696

To re-create correct font size calculations in Imagick and potentially Gmagick, we will use Gd's algorithm implemented here - http://svn.php.net/viewvc/php/php-src/trunk/ext/gd/libgd/gdft.c?revision=296693&view=markup#l1055 and described here - http://www.freetype.org/freetype2/docs/glyphs/glyphs-6.html

@avalanche123
Copy link
Collaborator

on a second look and after consulting Piere, looks like the 'resolution' option is available but undocumented as can be seen here - http://svn.php.net/viewvc/php/php-src/tags/php_5_3_0/ext/gd/libgd/gdft.c?view=markup#l847 and in the current trunk - http://svn.php.net/viewvc/php/php-src/trunk/ext/gd/libgd/gdft.c?revision=296693&view=markup#l848

@conf
Copy link
Contributor Author

conf commented Apr 14, 2011

Yes, as I previously said libgd allows it but php interface recognize only linespacing option as can be seen here http://svn.php.net/viewvc/php/php-src/trunk/ext/gd/gd.c?revision=307019&view=markup#l3965, see lines 3965-3985. The patch to allow this behavior should be quite simple though.

@igorbt
Copy link

igorbt commented Nov 16, 2011

Hello,

First of all thanks for this library, good job. We decided to use it in our project, but we will develop inside it as it is not so extendable as it could be. More that that, unfortunately, we still use PHP 5.2 on some servers, so I rewrote to adapt to the lack of namespaces.

Anyway, I also had some problems with Imagine queryFontMetrics as it returned wrong textHeight. As I observed (I could not found this really documented) the actual text height can be calculated as:

$actualTextHeight = $info['boundingBox']['y2'] - $info['boundingBox']['y1'];

where $info is array returned by Imagick queryFontMetrics().

More that that, other problem (that you guys probably wanted to solve) was that when writing a text at a coordinate, Imagick put left bottom corner of the text at that coordinate. If I correctly understood, you try to make it write text using left top corner (in function Drawer::text()). Because I didn't understand you formulas I change them to get this result. Here is the patch (It is for my php 5.2 library, but hopefully you will find corresponding places in original library if you want to):

Index: source/common/library_frameworks/Imagine/lib-php-5.2/Imagine/Imagick/Drawer.php
===================================================================
--- source/common/library_frameworks/Imagine/lib-php-5.2/Imagine/Imagick/Drawer.php (revision 6774)
+++ source/common/library_frameworks/Imagine/lib-php-5.2/Imagine/Imagick/Drawer.php (working copy)
@@ -344,19 +344,11 @@
             $cos  = cos($rad);
             $sin  = sin($rad);
 
-            // round(0 * $cos - 0 * $sin)
-            $x1 = 0;
-            $x2 = round($info['characterWidth'] * $cos - $info['characterHeight'] * $sin);
-            // round(0 * $sin + 0 * $cos)
-            $y1 = 0;
-            $y2 = round($info['characterWidth'] * $sin + $info['characterHeight'] * $cos);
-
-            $xdiff = 0 - min($x1, $x2);
-            $ydiff = 0 - min($y1, $y2);
+            $actualTextHeight = $info['boundingBox']['y2'] - $info['boundingBox']['y1'];
 
             $this->imagick->annotateImage(
-                $text, $position->getX() + $x1 + $xdiff,
-                $position->getY() + $y2 + $ydiff, $angle, $string
+                $text, $position->getX() - round($actualTextHeight * $sin),
+                $position->getY() + round($actualTextHeight * $cos), $angle, $string
             );
 
             $pixel->clear();
Index: source/common/library_frameworks/Imagine/lib-php-5.2/Imagine/Imagick/Font.php
===================================================================
--- source/common/library_frameworks/Imagine/lib-php-5.2/Imagine/Imagick/Font.php   (revision 6769)
+++ source/common/library_frameworks/Imagine/lib-php-5.2/Imagine/Imagick/Font.php   (working copy)
@@ -42,7 +42,11 @@
 
         $info = $this->imagick->queryFontMetrics($text, $string);
 
-        $box = new Imagine_Image_Box($info['textWidth'], $info['textHeight']);
+        //$box = new Imagine_Image_Box($info['textWidth'], $info['textHeight']);
+        $box = new Imagine_Image_Box(
+            $info['textWidth'] - $info['boundingBox']['x1'],
+            $info['boundingBox']['y2'] - $info['boundingBox']['y1']
+        );
 
         return $box;
     }

@avalanche123
Copy link
Collaborator

this is great, I'll take a look, the code that you removed was taking rotation angle into account to compute the end bounding box of rotated text, I'll see how I can incorporate your findings in it

@avalanche123
Copy link
Collaborator

here is what I came up with so far 2637e79
still things to fix for rotated text but overall results look much closer now

@romainneutron romainneutron modified the milestones: 0.6, 1.0 Apr 21, 2014
@mlocati mlocati removed this from the 0.6 milestone Oct 6, 2021
@mlocati mlocati closed this as completed Oct 6, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Development

No branches or pull requests

5 participants