簡體   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