Skip to content

Commit

Permalink
Initial support for font writing (no valid TTF file written yet)
Browse files Browse the repository at this point in the history
Moved most of the tables specs into static properties
  • Loading branch information
PhenX committed Aug 25, 2011
1 parent ece5717 commit 9772833
Show file tree
Hide file tree
Showing 17 changed files with 465 additions and 134 deletions.
6 changes: 3 additions & 3 deletions classes/adobe_font_metrics.cls.php
Original file line number Diff line number Diff line change
Expand Up @@ -64,12 +64,12 @@ function write($file, $encoding = null){
$this->addPair("EncodingScheme", $encoding_scheme);

$records = $font->getData("name", "records");
foreach($records as $id => $value) {
if (!isset(Font_TrueType::$nameIdCodes[$id]) || preg_match("/[\r\n]/", $value)) {
foreach($records as $id => $record) {
if (!isset(Font_TrueType::$nameIdCodes[$id]) || preg_match("/[\r\n]/", $record->string)) {
continue;
}

$this->addPair(Font_TrueType::$nameIdCodes[$id], $value);
$this->addPair(Font_TrueType::$nameIdCodes[$id], $record->string);
}

$os2 = $font->getData("OS/2");
Expand Down
8 changes: 8 additions & 0 deletions classes/font.cls.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,10 @@
/* $Id$ */

class Font {
/**
* @param string $file The font file
* @return Font_TrueType $file
*/
public static function load($file) {
$header = file_get_contents($file, false, null, null, 4);
$class = null;
Expand Down Expand Up @@ -64,4 +68,8 @@ public static function load($file) {
return $obj;
}
}

static function d($str) {
echo "$str\n";
}
}
114 changes: 100 additions & 14 deletions classes/font_binary_stream.cls.php
Original file line number Diff line number Diff line change
Expand Up @@ -43,15 +43,78 @@ class Font_Binary_Stream {
const longDateTime = 12;
const char = 13;

const modeRead = "rb";
const modeWrite = "wb";
const modeReadWrite = "rb+";

/**
* Open a font file in read mode
*
* @param string $filename The file name of the font to open
*/
public function load($filename) {
$this->f = fopen($filename, "rb");
return $this->open($filename, self::modeRead);
}

/**
* Open a font file in a chosen mode
*
* @param string $filename The file name of the font to open
* @param string $mode The opening mode
*/
public function open($filename, $mode = self::modeRead) {
if (!in_array($mode, array(self::modeRead, self::modeWrite, self::modeReadWrite))) {
throw new Exception("Unkown file open mode");
}

$this->f = fopen($filename, $mode);
return $this->f != false;
}

/**
* Change the internal file pointer
*
* @param resource $fp
*/
public function setFile($fp) {
if (!is_resource($fp)) {
throw new Exception('$fp is not a valid resource');
}

$this->f = $fp;
}

/**
* Create a temporary file in write mode
*
* @return resource the temporary file pointer resource
*/
public static function getTempFile() {
// PHP 5.1+
$f = @fopen("php://temp", "rb+");

if (!$f) {
$f = fopen(tempnam(sys_get_temp_dir(), "fnt"), "rb+");
}

return $f;
}

/**
* Move the internal file pinter to $offset bytes
*
* @param int $offset
* @return bool True if the $offset position exists in the file
*/
public function seek($offset) {
return fseek($this->f, $offset, SEEK_SET) == 0;
}

/**
* Gives the current position in the file
*
* @return int The current position
*/
public function pos() {
return ftell($this->f);
}
Expand All @@ -65,40 +128,44 @@ public function read($n) {
return fread($this->f, $n);
}

public function write($data) {
public function write($data, $length = null) {
if ($data === null || $data === "") return;
return fwrite($this->f, $data);
return fwrite($this->f, $data, $length);
}

public function readUInt8() {
return ord($this->read(1));
}

public function writeUInt8($data) {
return $this->write(chr($data));
return $this->write(chr($data), 1);
}

public function readInt8() {
$v = $this->readUInt8();

if ($v >= 0x80) {
$v -= 256;
$v -= 0x100;
}

return $v;
}

public function writeInt8($data) {
// todo
if ($data < 0) {
$data += 0x100;
}

return $this->writeUInt8($data);
}

public function readUInt16() {
$a = @unpack('nn', $this->read(2));
return $a['n'];
$a = unpack("nn", $this->read(2));
return $a["n"];
}

public function writeUInt16($data) {
return $this->write(pack("n", $data));
return $this->write(pack("n", $data), 2);
}

public function readInt16() {
Expand All @@ -120,12 +187,12 @@ public function writeInt16($data) {
}

public function readUInt32() {
$a = unpack('NN', $this->read(4));
return $a['N'];
$a = unpack("NN", $this->read(4));
return $a["N"];
}

public function writeUInt32($data) {
return $this->write(pack("N", $data));
return $this->write(pack("N", $data), 4);
}

public function readFixed() {
Expand All @@ -137,7 +204,7 @@ public function readFixed() {
public function writeFixed($data) {
$left = floor($data);
$right = ($data - $left) * 0x10000;
return $this->writeInt16($left) + $this->writeUInt16($left);
return $this->writeInt16($left) + $this->writeUInt16($right);
}

public function readLongDateTime() {
Expand Down Expand Up @@ -170,6 +237,12 @@ public function pack($def, $data) {
return $bytes;
}

/**
* Read a data of type $type in the file from the current position
*
* @param mixed $type The data type to read
* @return mixed The data that was read
*/
public function r($type) {
switch($type) {
case self::uint8: return $this->readUInt8();
Expand Down Expand Up @@ -200,6 +273,13 @@ public function r($type) {
}
}

/**
* Write $data of type $type in the file from the current position
*
* @param mixed $type The data type to write
* @param mixed $data The data to write
* @return int The number of bytes read
*/
public function w($type, $data) {
switch($type) {
case self::uint8: return $this->writeUInt8($data);
Expand All @@ -214,7 +294,7 @@ public function w($type, $data) {
case self::uFWord: return $this->writeUInt16($data);
case self::F2Dot14: return $this->writeInt16($data);
case self::longDateTime: return $this->writeLongDateTime($data);
case self::char: return $this->write($data);
case self::char: return $this->write($data, 1);
default:
if ( is_array($type) ) {
if ($type[0] == self::char) {
Expand All @@ -230,6 +310,12 @@ public function w($type, $data) {
}
}

/**
* Converts a Uint32 value to string
*
* @param int $uint32
* @param string The string
*/
public function convertUInt32ToStr($uint32) {
return chr(($uint32 >> 24) & 0xFF).chr(($uint32 >> 16) & 0xFF).chr(($uint32 >> 8) & 0xFF).chr($uint32 & 0xFF);
}
Expand Down
4 changes: 2 additions & 2 deletions classes/font_header.cls.php
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,8 @@ public function __construct(Font_TrueType $font) {
$this->font = $font;
}

protected function encode(){
trigger_error("Method not implemented : ".__METHOD__);
public function encode(){
return $this->font->pack($this->def, $this->data);
}

public function parse(){
Expand Down
53 changes: 47 additions & 6 deletions classes/font_table.cls.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@

/* $Id$ */

abstract class Font_Table extends Font_Binary_Stream {
/*abstract */class Font_Table extends Font_Binary_Stream {
/**
* @var Font_Table_Directory_Entry
*/
Expand All @@ -37,21 +37,62 @@ abstract class Font_Table extends Font_Binary_Stream {

final public function __construct(Font_Table_Directory_Entry $entry) {
$this->entry = $entry;
$entry->setTable($this);
}

/**
* @return Font_TrueType
*/
public function getFont(){
return $this->entry->getFont();
}

protected function _encode(){
trigger_error("Method not implemented : ".__METHOD__);
if (empty($this->data)) {
Font::d(" >> Table is empty");
return 0;
}

return $this->getFont()->pack($this->def, $this->data);
}

protected function _parse(){
$this->data = $this->entry->getFont()->unpack($this->def);
$this->data = $this->getFont()->unpack($this->def);
}

protected function _parseRaw(){
$this->data = $this->getFont()->read($this->entry->length);
}

protected function _encodeRaw(){
return $this->getFont()->write($this->data, $this->entry->length);
}

final public function encode(){
$this->entry->startWrite();

if (false && empty($this->def)) {
$length = $this->_encodeRaw();
}
else {
$length = $this->_encode();
}

$this->entry->endWrite();

return $length;
}

final public function parse(){
$this->entry->start();
$this->entry->startRead();

$this->_parse();
if (false && empty($this->def)) {
$this->_parseRaw();
}
else {
$this->_parse();
}

$this->entry->end();
$this->entry->endRead();
}
}
Loading

0 comments on commit 9772833

Please sign in to comment.