Блокировка шрифтов GD2 в Windows / Apache - PullRequest
4 голосов
/ 10 июня 2011

У меня есть скрипт PHP, который использует GD2 для создания изображения. Он использует файл TrueTypeFont для генерации текста в изображении с imagettftextimagettfbbox). Этот сценарий может быть запущен на компьютерах с Windows и Linux, поэтому я решил скопировать файл TTF из каталога Windows / Fonts в исходный код, иначе я не знаю, где его искать. Я совсем не доволен этим решением, но не знаю лучшего.

Реальная проблема заключается в том, что в Windows / Apache файл шрифта блокируется после его однократного использования. Единственный способ разблокировать его - перезапустить Apache. Блокировка - это проблема, потому что я не могу удалить файл, когда захочу, что особенно раздражает, если вы используете систему версий.

Итак, у моей проблемы есть 3 решения:

  • Есть ли способ избежать блокировки файлов шрифтов (в исходном коде / webroot) в Windows / Apache?
  • Или есть способ избежать копирования файла шрифта и использовать собственный доступный 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 

Ответы [ 6 ]

1 голос
/ 20 июня 2011

Мое решение - это комбинация предложений. Я проверил политику StackOverflow на разделение наград, и это невозможно. Награда должна быть присуждена за один исчерпывающий ответ. Я хотел бы разделить мою награду со всеми людьми, которые ответили / прокомментировали здесь, если есть альтернативный способ, пожалуйста, свяжитесь со мной.

Мне не очень повезло со шрифтами .gdf, я не могу найти ни одного красивого шрифта. Он указал мне направление imagestring, которое может рисовать текст без необходимости использования какого-либо файла шрифта (gdf или ttf) - см. Документ php. Шрифт «по умолчанию» - это просто какой-то моноширинный шрифт, который не очень красив, но он прекрасно подходит в качестве запасного варианта.

Чтобы избежать блокировки .ttf, я попытаюсь найти папку шрифтов ОС и загрузить шрифт оттуда. Это было проверено на моей машине для разработки 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);
1 голос
/ 17 июня 2011

Я также сталкивался с такой проблемой в GD, но в дистрибутиве Debian .Я нашел два решения, которые также могут привести к решениям wamp :

a - установить графическую библиотеку комплекта из dotdeb.org libgd I / O нативная библиотека php GDи перекомпилируйте исходные коды с параметром with-freetype ,

или

b - установите imagick вместо GD

Я успешно применил решение "a" в дистрибутиве debian .

Вот несколько ссылок, которые я использовал в то время:
imagick on wamp
howtoforge
drupal
libgd
boutell

1 голос
/ 10 июня 2011

Почему бы не использовать определяемый библиотекой путь шрифта?

Из imagettftext() документов вы можете использовать путь шрифта библиотеки:

В зависимости от того, какую версию библиотеки GD использует PHP, когда файл шрифтов не начинается с начального /, к имени файла добавляется файл .ttf, и библиотека пытается найти это имя файла по определенный путь к шрифту .

См. Страницу gd_info() , чтобы узнать, какую библиотеку ttf использует ваша версия php для Windows. Затем проверьте соответствующую библиотечную документацию, что такое font-path.

При использовании TTF из шрифтового пути может возникнуть проблема.

0 голосов
/ 19 июня 2011

Во-первых, мои извинения, если это не работает.Потому что я мог только проверить их на 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- "Кэшировать" файлы шрифтов: и оставить кеш для очистки самостоятельно после первого запуска при перезагрузке сервера.Таким образом, пока шрифты блокируются, блокируется только копия кэша.Не настоящие рабочие файлы, с которыми вы «играете».Следовательно, это не влияет на ваш рабочий цикл.Файлы в конечном итоге удаляются, когда система перезагружается, и они «очищаются для удаления».

РЕДАКТИРОВАТЬ: Обратите внимание, что вы всегда можете указать папку на папку tmp вНастройка Linux, должна работать примерно так же.

<?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) ОБНОВЛЕНО: Просто оставьте все свои шрифты в одной папке и делайте только удаление того, что не нужно, до фактического /окончательное развертывание вашего сервера.=) Просто оставьте папку шрифтов в покое.

Пример структуры общего сервера.

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

Следовательно, для любого веб-сайта / приложения, вложенного в корневую папку www, для доступа к папке общего шрифта просто используйте

'../fonts/fontName.ttf'

Следовательно, всякий раз, когда вы вносите изменения и обновления в приложение / сайт, вы избавляете от конфликтов конфликтов в шрифтах.

0 голосов
/ 19 июня 2011

Использование шрифтов GD (.gdf) решит проблему с блокировкой файлов. Вы можете перемещать / переименовывать / удалять их по своему желанию даже после их использования.

Они не так хороши, как шрифты .ttf, но, немного повозившись с гауссовым размытием, вы можете заставить их выглядеть почти идентично своим аналогам ttf с точки зрения сглаживания. Пример текста с ариалом:

enter image description here

$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);
0 голосов
/ 17 июня 2011

Я знаю обходной путь, который немного трудоемок.Подобное решение, как я предлагал: imagettftext-and-the-euro-sign .

В моем случае это может сработать, так как я на самом деле просто ищу способ создать несколько очень простыхизображения с текстом.Это предотвращает мою проблему, но, конечно, не решает основную проблему.

...