简体   繁体   English

GD2 Fonts 锁定在 Windows/Apache

[英]GD2 Fonts locking on Windows/Apache

I have a PHP script that uses GD2 to create an image.我有一个使用 GD2 创建图像的 PHP 脚本。 It uses a TrueTypeFont file to generate text in the image with imagettftext (and imagettfbbox ).它使用 TrueTypeFont 文件在带有imagettftext (和imagettfbbox )的图像中生成文本。 This script can be run on both Windows and Linux machines so I decided to copy a TTF file from the Windows/Fonts directory into the source-code, else I wouldn't know where to look for it.这个脚本可以在 Windows 和 Linux 机器上运行,所以我决定将一个 TTF 文件从 Windows/Fonts 目录复制到源代码中,否则我不知道在哪里寻找它。 I'm not at all happy with this solution but I don't know of a better one.我对这个解决方案一点也不满意,但我不知道有更好的解决方案。

The real problem though is that on Windows/Apache the font file gets locked after it's been used once.但真正的问题是,在 Windows/Apache 上,字体文件在使用一次后就会被锁定。 The only way to unlock it is to restart Apache.解锁它的唯一方法是重新启动 Apache。 The locking is a problem because I can't delete the file when I want to, which is especially annoying if you're using a version system.锁定是一个问题,因为我无法在我想删除文件时删除文件,如果您使用的是版本系统,这尤其令人讨厌。

So my problem has 3 solutions:所以我的问题有3个解决方案:

  • Is there a way to avoid locking of font files (in source code/webroot) on Windows/Apache?有没有办法避免在 Windows/Apache 上锁定字体文件(在源代码/webroot 中)?
  • Or is there a way to avoid copying the font file and use a native available TrueTypeFont?或者有没有办法避免复制字体文件并使用本机可用的 TrueTypeFont? (OS independent if at all possible, likely hosts are Windows and Linux - Mac, not so much) (尽可能独立于操作系统,可能的主机是 Windows 和 Linux - Mac,不是那么多)
  • Or is there a way to avoid using a TrueTypeFont and still get pretty (aliased) text with PHP GD2?或者有没有办法避免使用 TrueTypeFont 并且仍然使用 PHP GD2 获得漂亮的(别名)文本?

-- --

GD Support  enabled
GD Version  bundled (2.0.34 compatible)
FreeType Support    enabled
FreeType Linkage    with freetype
FreeType Version    2.1.9
T1Lib Support   enabled
GIF Read Support    enabled
GIF Create Support  enabled
JPG Support     enabled
PNG Support     enabled
WBMP Support    enabled
XBM Support     enabled 

Why not using the library-defined font path?为什么不使用库定义的字体路径?

From the imagettftext() docs , you can use the library font path:imagettftext()文档中,您可以使用库字体路径:

Depending on which version of the GD library PHP is using, when fontfile does not begin with a leading / then.ttf will be appended to the filename and the library will attempt to search for that filename along a library-defined font path .根据使用的 GD 库 PHP 的版本,当 fontfile 不以前导 / 开头时,会将.ttf 附加到文件名,并且库将尝试沿着库定义的字体路径搜索该文件名。

See the gd_info() page to find out which ttf library your windows php version is using.请参阅gd_info()页面以了解您的 windows php 版本正在使用哪个 ttf 库。 Then check the according library documentation what the font-path is.然后检查相应的库文档字体路径是什么。

Using TTFs from the fontpath might have the problem.使用字体路径中的 TTF 可能会出现问题。

I also faced such an issue with GD but on a Debian distro.我在 GD 上也遇到过这样的问题,但在Debian发行版上。 I found two solutions that might lead to wamp solutions as well:我发现了两种可能导致wamp解决方案的解决方案:

a - install the bundle graphic library from dotdeb.org libgd i/o native php GD library and recompile the sources the with-freetype option, a - 从 dotdeb.org libgd i/o native php GD 库安装捆绑图形库并重新编译源代码with-freetype选项,

or或者

b - install imagick instead of GD b - 安装imagick而不是 GD

I applied solution "a" successfully on a debian distro.我在debian发行版上成功应用了解决方案“a”。

Here are some links I used at that time:以下是我当时使用的一些链接:
imagick on wamp wamp 上的 imagick
howtoforge 如何伪造
drupal drupal
libgd libgd
boutell布特尔

My solution is a combination of suggestions.我的解决方案是综合建议。 I checked StackOverflow policy on splitting bounties and it's not possible.我检查了有关拆分赏金的 StackOverflow 政策,但这是不可能的。 The bounty must be awarded to a single comprehensive answer.赏金必须授予单个综合答案。 I would like to split my bounty to all the people who replied / commented here, if there is an alternative way please contact me.我想将我的赏金分配给所有在这里回复/评论的人,如果有其他方式请与我联系。

I didn't have much luck with the.gdf fonts, I can't really find any good looking fonts.我对 .gdf fonts 不太走运,我真的找不到任何好看的 fonts。 It did point me in the direction of imagestring which can draw text without the need of any font file (gdf or ttf) - see the php doc.它确实为我指明了imagestring的方向,它可以在不需要任何字体文件(gdf 或 ttf)的情况下绘制文本 - 请参阅 php 文档。 The 'default' font is just some monospace font which isn't very pretty but it serves nicely as a fallback. “默认”字体只是一些等宽字体,它不是很漂亮,但它可以很好地作为后备。

To avoid the.ttf locking I will attempt to find the OS font folder and load the font from there.为了避免 .ttf 锁定,我将尝试找到 OS 字体文件夹并从那里加载字体。 This has been tested on my Windows development machine.这个已经在我的Windows开发机上测试过了。 If the.ttf file can't be found it will use the native font fallback from imagestring .如果找不到 .ttf 文件,它将使用imagestring的本机字体回退。

I've chosen an Object-Oriented approach to make an abstraction on how the text is written to the image.我选择了一种面向对象的方法来抽象出文本是如何写入图像的。

abstract class TextWriter {

    public static function getInstance() {
        $osName = php_uname( 's' );

        if (strtoupper(substr($osName, 0, 3)) === 'WIN') {
            $path = 'C:/Windows/Fonts/';
        } else if (strtoupper(substr($osName, 0, 5)) === 'LINUX') {
            $path = '/usr/share/fonts/truetype/';
        } else if (strtoupper(substr($osName, 0, 7)) === 'FREEBSD') {
            $path = '/usr/local/lib/X11/fonts/TrueType';
        }
        if (is_dir($path) && is_file($path . "/arial.ttf")) {
            return new TTFTextWriter($path . "/arial.ttf");
        }
        return new NativeTextWriter();
    }

    abstract public function get_dimenions($string);
    abstract public function write_text($img_resource, $x, $y, $text, $color);

}

class TTFTextWriter extends TextWriter {

    private $ttf_file;
    private $fontsize = 10;

    public function __construct($ttf_file) {
        $this->ttf_file = $ttf_file;
    }

    public function get_dimenions($text) {
        $dimenions = imagettfbbox($this->fontsize, 0, $this->ttf_file, $text);
        return array($dimenions[2], abs($dimenions[5] - $dimenions[3]));
    }

    public function write_text($img_resource, $x, $y, $text, $color) {
        imagettftext($img_resource, $this->fontsize, 0, $x, $y, $color, $this->ttf_file, $text);
    }

}

class NativeTextWriter extends TextWriter {

    private $fontsize = 3;  // number between 1-5 see manual for imagestring
    private $text_width = 7;  // corresponds to $fontsize 3
    private $text_height = 15;  // corresponds to $fontsize 3

    public function get_dimenions($text) {
        return array(strlen($text) * $this->text_width, $this->text_height);
    }

    public function write_text($img_resource, $x, $y, $text, $color) {
        imagestring($img_resource, $this->fontsize, $x, $y - $this->text_height, $text, $color);
    }
}

Use like:像这样使用:

$writer = TextWriter::getInstance();

$dimenions = $writer->get_dimenions($text);
$width = $dimenions[0];
$height = $dimenions[1];
$im = imagecreatetruecolor($width, $height);
$black = imagecolorallocate($im, 1, 1, 1);

$writer->write_text($im, 0, 0, $text, $black);
header('Content-Type: image/gif');

imagegif($im);
imagedestroy($im);

I do know a workaround that is a bit laborious.我确实知道一个有点费力的解决方法。 A similar solution as I suggested: imagettftext-and-the-euro-sign .我建议的类似解决方案: imagettftext-and-the-euro-sign

In my case this could work as I'm really just looking for a way to generate some very simple images with text.在我的情况下,这可能会起作用,因为我真的只是在寻找一种方法来生成一些非常简单的带有文本的图像。 It averts my problem but of course doesn't fix the underlying issue.它避免了我的问题,但当然不能解决根本问题。

Using GD fonts (.gdf) will solve the issue with the files getting locked.使用 GD fonts (.gdf) 将解决文件被锁定的问题。 You can move/rename/delete them as you wish even after using them.即使在使用它们之后,您也可以根据需要移动/重命名/删除它们。

They aren't quite as pretty as.ttf fonts, but with a bit of tinkering with gaussian blur you can get them to look almost identical to their ttf counterparts in terms of anti aliasing.它们不像.ttf fonts 那样漂亮,但是通过对高斯模糊进行一些修改,您可以让它们在抗锯齿方面看起来几乎与它们的 ttf 对应物相同。 Sample text with arial:带有 arial 的示例文本:

在此处输入图像描述

$im = imagecreatetruecolor(400, 200);

$bg = imagecolorallocate($im, 255, 255, 255);

imagefill ( $im , 0 , 0 ,$bg );
$textcolor = imagecolorallocate($im, 0, 0, 0);
imageantialias ( $im ,true );

$font = imageloadfont('arial-reg-20.gdf');

imagestring($im, $font, 10, 10, 'Hello world!', $textcolor);

imagefilter($im, IMG_FILTER_GAUSSIAN_BLUR,10);
imagestring($im, $font, 10, 10, 'Hello world!', $textcolor);
imagefilter($im, IMG_FILTER_GAUSSIAN_BLUR,1);
// Output the image
header('Content-type: image/png');

imagepng($im);
imagedestroy($im);

Firstly, my apologies if this does not work.首先,如果这不起作用,我深表歉意。 For i could only test them on WAMP.因为我只能在 WAMP 上测试它们。 Where this bug (according to online research) does not affect.这个错误(根据在线研究)不影响的地方。

1) Make sure to imagedestroy($im); 1)确保imagedestroy($im);

2) To get the font folders for either platforms 2)获取任一平台的字体文件夹

<?php
function fontFolder() {
    $osName = php_uname( 's' );

    if (strtoupper(substr($osName, 0, 3)) === 'WIN') {
        return '/Windows/Fonts/';
    }

    if (strtoupper(substr($osName, 0, 5)) === 'LINUX') {
        return '/usr/share/fonts/truetype/';
    }

    if (strtoupper(substr($osName, 0, 7)) === 'FREEBSD') {
        //This is not tested
        return '/usr/share/fonts/truetype/';
    }
}

echo fontFolder();
?>

*Note this list of OS is not fully extensive, you may need to add / modify it for your needs. *请注意,此操作系统列表并不完整,您可能需要根据需要添加/修改它。

3) [NOT RECOMMENDED] Persudo-"Cache" the font files: And leave the cache to clear on its own after the first run on server reset. 3)[不推荐] Persudo-“缓存”字体文件:并在服务器重置第一次运行后让缓存自行清除。 That way, while the fonts gets 'locked' it is only the cache copy that gets locked.这样,虽然 fonts 被“锁定”,但只有缓存副本被锁定。 Not the actual working files you are 'playing' with.不是您正在“玩”的实际工作文件。 Hence it does not affect your work cycle.因此,它不会影响您的工作周期。 The files does get deleted eventually, when the system is rebooted, and they are 'cleared to delete'.当系统重新启动时,这些文件最终会被删除,并且它们被“清除为删除”。

EDIT: Note that you can always point the folder to a tmp folder in a linux setup, should work somewhat the same.编辑:请注意,您始终可以将文件夹指向 linux 设置中的 tmp 文件夹,其工作方式应该有些相同。

<?php
/**
Recursive delete, with a 'file/folder igonore option'
[$ignoreArra] : An array or a single string, to ignore delete (folder or file)
[$ignoreRootFolder] : Ignores the starting root folder
**/
function recursiveDelete($str, $ignoreArray = null, $ignoreRootFolder = false){
    if($str == '' || $str == '/')   {   //Prevent accidental 'worse case scenerios'
        return false;   
    }

    //Ensures it working as an array
    if($ignoreArray == null) {
        $ignoreArray = array(); //new Array
    }
    if(!is_array( $ignoreArray ) ) {
        $ignoreArray = array( $ignoreArray );
    }

    if(is_file($str)){
        if(in_array( $str, $ignoreArray ) ) {
            return false;
        } //else
        return @unlink($str);
    }
    elseif(is_dir($str)){
        $scan = glob(rtrim($str,'/').'/*');
        $chk = true;
        foreach($scan as $index=>$path) {
            $buf = recursiveDelete($path, $ignoreArray);
            if( $buf == false ) {
                $chk = false;
            }
        }

        if( in_array( $str, $ignoreArray ) || $chk == false || $ignoreRootFolder ) {
            return false;
        } else {
            return @rmdir($str);
        }
    }   else    {
        return false;
    }
}

define('fontCacheFolder', './font_cache/');
function fontCache($fontFolder, $fontFile) {
    $cachedFile = fontCacheFolder.$fontFile;
    recursiveDelete( fontCacheFolder , $cachedFile , true);
    if( is_file( $cachedFile ) ) {
        return $cachedFile;
    }
    copy( $fontFolder.$fontFile, $cachedFile);
    return $cachedFile;
}

echo fontCache('./', 'arial.ttf');
?>

4) UPDATED: Just leave all your fonts in one folder, and only do deletes of what is not needed before the actual / final deployment of your server. 4) 更新:只需将所有 fonts 留在一个文件夹中,并且只在实际/最终部署服务器之前删除不需要的内容。 =) Just leave the font folder alone. =) 只留下字体文件夹。

Example shared server structure.示例共享服务器结构。

www/root
   +----- fonts
   +----- app A
   +----- site B

Hence for any website / application nested in the root www folder, to access the shared font folder just use因此,对于嵌套在根 www 文件夹中的任何网站/应用程序,要访问共享字体文件夹,只需使用

'../fonts/fontName.ttf'

Hence, whenever you make changes and updates to the app / site, you save the trouble of conflicts in fonts.因此,每当您对应用程序/站点进行更改和更新时,您都可以省去 fonts 中冲突的麻烦。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM