繁体   English   中英

GD2 Fonts 锁定在 Windows/Apache

[英]GD2 Fonts locking on Windows/Apache

我有一个使用 GD2 创建图像的 PHP 脚本。 它使用 TrueTypeFont 文件在带有imagettftext (和imagettfbbox )的图像中生成文本。 这个脚本可以在 Windows 和 Linux 机器上运行,所以我决定将一个 TTF 文件从 Windows/Fonts 目录复制到源代码中,否则我不知道在哪里寻找它。 我对这个解决方案一点也不满意,但我不知道有更好的解决方案。

但真正的问题是,在 Windows/Apache 上,字体文件在使用一次后就会被锁定。 解锁它的唯一方法是重新启动 Apache。 锁定是一个问题,因为我无法在我想删除文件时删除文件,如果您使用的是版本系统,这尤其令人讨厌。

所以我的问题有3个解决方案:

  • 有没有办法避免在 Windows/Apache 上锁定字体文件(在源代码/webroot 中)?
  • 或者有没有办法避免复制字体文件并使用本机可用的 TrueTypeFont? (尽可能独立于操作系统,可能的主机是 Windows 和 Linux - Mac,不是那么多)
  • 或者有没有办法避免使用 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 

为什么不使用库定义的字体路径?

imagettftext()文档中,您可以使用库字体路径:

根据使用的 GD 库 PHP 的版本,当 fontfile 不以前导 / 开头时,会将.ttf 附加到文件名,并且库将尝试沿着库定义的字体路径搜索该文件名。

请参阅gd_info()页面以了解您的 windows php 版本正在使用哪个 ttf 库。 然后检查相应的库文档字体路径是什么。

使用字体路径中的 TTF 可能会出现问题。

我在 GD 上也遇到过这样的问题,但在Debian发行版上。 我发现了两种可能导致wamp解决方案的解决方案:

a - 从 dotdeb.org libgd i/o native php GD 库安装捆绑图形库并重新编译源代码with-freetype选项,

或者

b - 安装imagick而不是 GD

我在debian发行版上成功应用了解决方案“a”。

以下是我当时使用的一些链接:
wamp 上的 imagick
如何伪造
drupal
libgd
布特尔

我的解决方案是综合建议。 我检查了有关拆分赏金的 StackOverflow 政策,但这是不可能的。 赏金必须授予单个综合答案。 我想将我的赏金分配给所有在这里回复/评论的人,如果有其他方式请与我联系。

我对 .gdf fonts 不太走运,我真的找不到任何好看的 fonts。 它确实为我指明了imagestring的方向,它可以在不需要任何字体文件(gdf 或 ttf)的情况下绘制文本 - 请参阅 php 文档。 “默认”字体只是一些等宽字体,它不是很漂亮,但它可以很好地作为后备。

为了避免 .ttf 锁定,我将尝试找到 OS 字体文件夹并从那里加载字体。 这个已经在我的Windows开发机上测试过了。 如果找不到 .ttf 文件,它将使用imagestring的本机字体回退。

我选择了一种面向对象的方法来抽象出文本是如何写入图像的。

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);
    }
}

像这样使用:

$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);

我确实知道一个有点费力的解决方法。 我建议的类似解决方案: imagettftext-and-the-euro-sign

在我的情况下,这可能会起作用,因为我真的只是在寻找一种方法来生成一些非常简单的带有文本的图像。 它避免了我的问题,但当然不能解决根本问题。

使用 GD fonts (.gdf) 将解决文件被锁定的问题。 即使在使用它们之后,您也可以根据需要移动/重命名/删除它们。

它们不像.ttf fonts 那样漂亮,但是通过对高斯模糊进行一些修改,您可以让它们在抗锯齿方面看起来几乎与它们的 ttf 对应物相同。 带有 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);

首先,如果这不起作用,我深表歉意。 因为我只能在 WAMP 上测试它们。 这个错误(根据在线研究)不影响的地方。

1)确保imagedestroy($im);

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();
?>

*请注意,此操作系统列表并不完整,您可能需要根据需要添加/修改它。

3)[不推荐] Persudo-“缓存”字体文件:并在服务器重置第一次运行后让缓存自行清除。 这样,虽然 fonts 被“锁定”,但只有缓存副本被锁定。 不是您正在“玩”的实际工作文件。 因此,它不会影响您的工作周期。 当系统重新启动时,这些文件最终会被删除,并且它们被“清除为删除”。

编辑:请注意,您始终可以将文件夹指向 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) 更新:只需将所有 fonts 留在一个文件夹中,并且只在实际/最终部署服务器之前删除不需要的内容。 =) 只留下字体文件夹。

示例共享服务器结构。

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

因此,对于嵌套在根 www 文件夹中的任何网站/应用程序,要访问共享字体文件夹,只需使用

'../fonts/fontName.ttf'

因此,每当您对应用程序/站点进行更改和更新时,您都可以省去 fonts 中冲突的麻烦。

暂无
暂无

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

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