Skip to content

Instantly share code, notes, and snippets.

@Caffe1neAdd1ct
Last active July 5, 2018 15:44
Show Gist options
  • Save Caffe1neAdd1ct/2819a72e1b77abf6b4968ffd52c2802e to your computer and use it in GitHub Desktop.
Save Caffe1neAdd1ct/2819a72e1b77abf6b4968ffd52c2802e to your computer and use it in GitHub Desktop.
Generate PNG without writing to disk with a VariableStream wrapper.
yaourt -S fontforge

vim  ./convert-font.sh

#!/usr/bin/fontforge
# Quick and dirty hack: converts a font to truetype (.ttf)
Print("Opening "+$1);
Open($1);
Print("Saving "+$1:r+".ttf");
Generate($1:r+".ttf");
Quit(0);

Example converion:

fontforge -script convert-font.sh 'Chevin Light.otf'

Check /usr/share/fonts/TTF/ for possible fonts you can use otherwise.

<?php
/**
* Converts text to png
*
* @author Kevin Andrews <[email protected]>
*/
class TextToPng
{
protected $str = '';
public function __construct($str = '')
{
$this->str = $str;
}
public function getString()
{
return $this->str;
}
public function setString($str)
{
$this->str = $str;
return $this;
}
public function generate($font='arial.ttf', $fontSize=8, $opaque=false)
{
/** Font configs */
$fontsPath = '/path/to/fonts/dir';
/** Size calcs */
$enclosingBox = imagettfbbox(25, 0, $fontsPath . DIRECTORY_SEPARATOR . $font, $this->str);
$width = ($enclosingBox[2] - $enclosingBox[0]) + 10;
$height = ($enclosingBox[1] - $enclosingBox[7]) + $fontSize;
/** Create a blank image */
$im = imagecreatetruecolor($width, $height);
imagealphablending($im, false);
imagesavealpha($im, true);
if(!$im) {
throw new Exception('Missing GD 2 extension.');
}
/** Define Colours */
$transparent = imagecolorallocatealpha($im,255,255,255,127);
$white = imagecolorallocate($im, 255, 255, 255);
$black = imagecolorallocate($im, 0, 0, 0);
// Fill the entire background
imagefill($im, 0, 0, ($opaque) ? $white : $transparent);
// Render text to image
imagettftext($im, $fontSize, 0, 5, ($height/2) + ($fontSize/2), $black, $fontsPath . DIRECTORY_SEPARATOR . $font, $this->str);
// Open stream to varaiable
VariableStream::register();
$filePointer = fopen('var://tempImage', 'w+');
// Output image to stream
imagepng($im, $filePointer);
imagedestroy($im);
/** seek to the start of the variable stream and read whole raw png back */
fseek($filePointer, 0, SEEK_SET);
$imageRaw = '';
while (!feof($filePointer)) {
$imageRaw .= fread($filePointer, 8192);
}
fclose($filePointer);
}
}
<?php
require_once 'VariableStream.php';
require_once 'TextToPng.php';
$pngRaw = (new TextToPng('this is not a test'))->generate();
header('Content-Type: image/png');
echo $pngRaw;
<?php
/**
* Variable Stream Wrapper - useful for writing to a retrievable variable instead of a file or resource.
*
* @author Kevin Andrews <[email protected]>
*/
class VariableStream
{
public $context;
private $key = 0;
private $data = [];
private $_pos = 0;
private $_open;
public static function register()
{
stream_wrapper_register('var', self::class);
}
public function stream_open($path, $mode, $options, &$opened_path)
{
$url = parse_url($path);
if(strlen($url['host']) > 0) {
$this->key = $url['host'];
}
$this->data = [$url['host'] => null];
$this->_pos = 0;
$this->_open = true;
return true;
}
public function stream_close()
{
$this->_pos = 0;
$this->_open = false;
}
public function stream_write($data)
{
if (!$this->_open) {
return false;
}
// if (!($this->_mode & STREAM_VAR_WRITEABLE)) {
// return false;
// }
$datalen = strlen($data);
$this->data[$this->key] = substr($this->data[$this->key], 0, $this->_pos)
. $data
. substr($this->data[$this->key], $this->_pos+$datalen);
$this->_pos = $this->_pos + $datalen;
return $datalen;
}
public function stream_read($count)
{
if (!$this->_open) {
return false;
}
// if (!($this->_mode & STREAM_VAR_READABLE)) {
// return false;
// }
$data = substr($this->data[$this->key], $this->_pos, $count);
$this->_pos = $this->_pos + strlen($data);
return $data;
}
public function stream_eof()
{
return ($this->_pos >= strlen($this->data[$this->key]));
}
public function stream_tell()
{
return $this->_pos;
}
public function stream_seek($offset, $whence)
{
switch ($whence) {
// from start
case SEEK_SET:
if ($offset < strlen($this->data[$this->key]) && $offset >= 0) {
$this->_pos = $offset;
return true;
} else {
return false;
}
break;
// from current position
case SEEK_CUR:
if ($offset >= 0) {
$this->_pos += $offset;
return true;
} else {
return false;
}
break;
// from the end
case SEEK_END:
if (strlen($this->data[$this->key]) + $offset >= 0) {
$this->_pos = strlen($this->data[$this->key]) + $offset;
return true;
} else {
return false;
}
break;
default:
return false;
}
}
public function stream_stat()
{
return array();
}
public function stream_flush()
{
return true;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment