Hallo....
äsentiere ich euch eine GD-Lösung welches einen Text publiziert... dieser unterscheidet zwischen:
/[b] jedoch habe ich das problem.. falls der Text länger als die (200px) vom Bild ist schreibt er mir den Text drüber hinaus... Kann mir jemand bei dem Skript helfen und dies einigermassen so anpassen bzw. helfen das sobald der Text an die 200 PX antritt auf die nächste Zeile geschrieben wird also in der Art:
PHP-Code:
$text = $_GET['text'];
/** Ein Parser interpretiert Text.
* Dieser Parser hier verarbeitet einen einfachen
* HTML ähnlichen Markup Language und gibt seine
* Daten an einen Writer weiter.
* Der Parser bestimmt in diesem Fall das Layout
* (da Markup Language als Basis), wärend
* der Writer das konkrete Design und
* das Zielformat bestimmt.
*/
class SMLParser
{
const TXT_MODE_IGNORE = 0xff;
const TXT_MODE_NORMAL = 0x00;
const TXT_MODE_BOLD = 0x01;
const TXT_MODE_ITALIC = 0x02;
private $tagMap=array('p'=>self::TXT_MODE_NORMAL,
'b'=>self::TXT_MODE_BOLD ,
'i'=>self::TXT_MODE_ITALIC,
'br'=>self::TXT_MODE_IGNORE);
private $stack=array();
private $currMode=self::TXT_MODE_NORMAL;
private $writer=null;
public function setWriter(SMLImageWriter $writer)
{
$this->writer=$writer;
}
public function parse($content)
{
if(is_null($this->writer))
throw new Exception('Cannot parse without an output channel!');
// strip newline and carriage return:
$content=preg_replace("#[\r\n]+#",'',$content);
// find all content
###TODO: Replace with propper tokenizer for longer content###
preg_match_all("#(<(([^>/]+)\s*|(/([^>]+)\s*)|(([^>/]+)\s*/))>|[^<>]+)#si",$content,$m);
// loop over content elements
foreach($m[2] as $k=>$data)
{
if(!empty($data))
{
switch($data)
{
case $m[3][$k]: // opening tag
$tag=trim($m[3][$k]);
array_push($this->stack,$tag);
$this->onOpeningTag($tag);
continue 2;
case $m[4][$k]: // closing tag
$tag=trim($m[5][$k]);
if(array_pop($this->stack)!=$tag)
throw new Exception('Parse error! Invalid closing tag detected!');
$this->onClosingTag($tag);
continue 2;
case $m[6][$k]: // empty tag
$tag=trim($m[7][$k]);
$this->onOpeningTag($tag);
$this->onClosingTag($tag);
continue 2;
}
}
// character data:
$this->onCharacterData($m[0][$k]);
}
}
private function onOpeningTag($tag)
{
if(!isset($this->tagMap[$tag]))
throw new Exception('Parse error! Unknown tag detected!');
if($tag!='br')
{
$bmask=$this->tagMap[$tag];
$this->currMode|=$bmask;
$this->writer->setMode($this->currMode^self::TXT_MODE_NORMAL);
}
}
private function onClosingTag($tag)
{
if(!isset($this->tagMap[$tag]))
throw new Exception('Parse error! Unknown tag detected!');
if($tag!='br')
{
$bmask=$this->tagMap[$tag];
$this->currMode^=$bmask;
$this->writer->setMode($this->currMode^self::TXT_MODE_NORMAL);
}else
$this->writer->lineBreak();
}
private function onCharacterData($data)
{
$this->writer->write(mb_convert_encoding($data,'UTF-8','HTML-ENTITIES'));
}
}
//Dieser Parser ist eigentlich eher ein Transformator,
//da er die Darstellungsschicht direkt ansteuert. Die Darstellungsschicht könnte dabei wie folgt aussehen:
abstract class SMLImageWriter
{
protected $img = null;
protected $mode = SMLParser::TXT_MODE_NORMAL;
protected $currLine = array();
private $fontFiles = array();
private $fontColors = array();
private $fontSizes = array();
private $offsetX = 0;
private $offsetY = 0;
private $lineSpacing= 0;
public function setBackgroundImage($img)
{
$this->img=$img;
}
public function setXY($x,$y)
{
$this->offsetX=$x;
$this->offsetY=$y;
}
public function setLineSpacing($px)
{
$this->lineSpacing=$px;
}
public function setFont($mode,$fontFile)
{
$this->fontFiles[$mode]=$fontFile;
}
public function setColor($mode,$r,$g,$b)
{
$this->fontColors[$mode]=imagecolorallocate($this->img,$r,$g,$b);
}
public function setBackgroundColor($r,$g,$b)
{
imagefill($this->img,0,0,imagecolorallocate($this->img,$r,$g,$b));
}
public function setSize($mode,$size)
{
$this->fontSizes[$mode]=$size;
}
public function initMode($mode,$fontFile,$size,$color)
{
$this->setFont($mode,$fontFile);
$this->setSize($mode,$size);
$this->setColor($mode,$color[0],$color[1],$color[2]);
}
public function setMode($mode)
{
$this->mode=$mode;
}
public function lineBreak()
{
$this->writeLine();
$this->currLine=array();
}
public function write($string)
{
$this->currLine[]=array($this->mode,$string);
}
public function store($filename)
{
$this->writeLine();
$this->doStore($filename);
}
public function display()
{
$this->writeLine();
$this->doDisplay();
}
private function writeLine()
{
// first calculate total line height:
$lineHeight=0;
$lineWidth=0;
foreach($this->currLine as $k=>$element)
{
$sizeInfo=imagettfbbox($this->fontSizes[$element[0]],
0,
$this->fontFiles[$element[0]],
$element[1]);
// Zeilenbreite inklusive des aktuellen Elements errechnen:
$lineWidth+=abs($sizeInfo[6]) - abs($sizeInfo[0]);
// Wenn Zeile zu lang wird, dann
if($lineWidth>$this->maxLineWidth)
{
// schonmal die Teile merken, die wir uns hier garnicht weiter anschauen,
$rest=array_slice($this->currLine,$k+1);
// dann das aktuelle Element in Teilworte zerlegen
if(preg_match_all('#(^|\W+)(\w{2,})(\W+|$)',$element[1],$m))
{
// Wenn Element nicht weiter zerlegbar, dann
if(count($m[0])==1)
// künstliche Trennung in Wortmitte
$m[0]=array(substr($m[0][0],0,intval(strlen($m[0][0])/2)),
substr($m[0][0],intval(strlen($m[0][0])/2)+1));
// Hier haben wir jetzt mindestens zwei Teilworte,
// die wir weiter verarbeiten müssen:
$current=array();
foreach($m[0] as $currText)
$current[]=array($element[0],$currText);
$previous=array_slice($this->currLine,0,$k);
$this->currLine=array_merge($previous,$current,$rest);
return $this->writeLine();
}
// ansonsten ist das Wort nicht mehr weiter zerlegbar
// und wir können umbrechen:
$this->lineBreak();
// jetzt müssen wir nur die nicht betrachteten Elemente in die nächste Zeile verschieben:
$rest=array_merge(array($element),rest);
foreach($rest as $appendElement)
{
$this->setMode($appendElement[0]);
$this->write($appendElement[1]);
return;
}
}
$currHeight=abs($sizeInfo[7]) - abs($sizeInfo[1]);
if($lineHeight<$currHeight)
$lineHeight=$currHeight;
}
// now write text:
$xpos=$this->offsetX;
foreach($this->currLine as $element)
{
$sizeInfo=imagettftext($this->img,
$this->fontSizes[$element[0]],
0,
$xpos,
$this->offsetY+$lineHeight,
$this->fontColors[$element[0]],
$this->fontFiles[$element[0]],
$element[1]);
$xpos=$sizeInfo[2];
}
$this->offsetY+=$lineHeight+$this->lineSpacing;
}
public abstract function doStore($filename);
public abstract function doDisplay();
}
/** Bilder gibt's in so manchen Variationen, deshalb
* müssen alle ein konkretes Format betreffenden Informationen
* in eine andere Klasse.
*/
class SMLJpegWriter extends SMLImageWriter
{
public function doStore($filename)
{
imagejpeg($this->img,$filename,75);
}
public function doDisplay()
{
header('Content-type: image/jpeg');
imagejpeg($this->img,null,75);
}
}
if($text != '')
{
// Zuerst mal brauchen wir unser Ziel:
$smlw=new SMLJpegWriter;
// Das Ziel konfigurieren wir uns 200x200 Pixel groß,
$smlw->setBackgroundImage(imagecreate(200,50));
// und mit einem weißen Hintergrund.
$smlw->setBackgroundColor(0xff,0xff,0xff);
// Jetzt legen wir das Aussehen für die unterschiedlichen Textteile fest:
$smlw->initMode(SMLParser::TXT_MODE_NORMAL,'../fonts/arial.ttf',7,array(0,0,0));
$smlw->initMode(SMLParser::TXT_MODE_BOLD,'../fonts/arialbd.ttf',7,array(0,0,0));
$smlw->initMode(SMLParser::TXT_MODE_ITALIC,'../fonts/ariali.ttf',7,array(0,0,0));
$smlw->initMode(SMLParser::TXT_MODE_ITALIC|SMLParser::TXT_MODE_BOLD,'../fonts/arialbi.ttf',7,array(0,0,0));
// uns sagen noch, wo der Text hin soll
$smlw->setXY(2,7);
// und wie viel Platz zwischen zwei Zeilen sein soll
$smlw->setLineSpacing(5);
// Um unser Ziel beschreiben zu können benötigen wir einen Parser:
$smlp=new SMLParser;
// der das Ziel kennen muss:
$smlp->setWriter($smlw);
// Außerdem brauchen wir Daten für unseren Parser:
$txt=<<<endTxt
$text
endTxt;
// und die teilen wir ihm sogar mit. Das Beschreiben unseres Ziels macht der
// Parser dabei automatisch.
$smlp->parse($txt);
// anzeigen:
$smlw->display();
}