Added converting ANSI to a binary format, and custom font rendering
This commit is contained in:
parent
82e3283d6d
commit
eda0926758
380
app/Classes/ANSI.php
Normal file
380
app/Classes/ANSI.php
Normal file
@ -0,0 +1,380 @@
|
||||
<?php
|
||||
|
||||
namespace App\Classes;
|
||||
|
||||
use Illuminate\Support\Collection;
|
||||
|
||||
class ANSI
|
||||
{
|
||||
/* 8 BIT COLORS
|
||||
* Foreground 0-3, Background 4-7
|
||||
* Color 0-2, 4-6, High 3, 7
|
||||
*/
|
||||
private const COLOR_8BIT = 0x1B;
|
||||
private const COLOR_HIGH = 1; // Bit 1.
|
||||
private const COLOR_BLACK = 0; // F30 B40
|
||||
private const COLOR_RED = 1; // F31 B41
|
||||
private const COLOR_GREEN = 2; // F32 B42
|
||||
private const COLOR_YELLOW = 3; // F33 B43
|
||||
private const COLOR_BLUE = 4; // F34 B44
|
||||
private const COLOR_MAGENTA = 5; // F35 B45
|
||||
private const COLOR_CYAN = 6; // F36 B46
|
||||
private const COLOR_WHITE = 7; // F37 B47
|
||||
|
||||
private const DEFAULT_FORE = 37;
|
||||
private const DEFAULT_BACK = 40;
|
||||
|
||||
/* 256 BIT COLORS */
|
||||
/* 0x26 0xAA 0xBB */
|
||||
|
||||
public const LOGO_BUFFER_WIDTH = 1;
|
||||
public const LOGO_BUFFER_HEIGHT = 0; // Not implemented
|
||||
public const LOGO_OFFSET_WIDTH = 1;
|
||||
public const LOGO_OFFSET_HEIGHT = 0; // Not implemented
|
||||
|
||||
private Collection $width;
|
||||
private Collection $ansi;
|
||||
private const BUFREAD = 2048;
|
||||
|
||||
/* MAGIC METHODS */
|
||||
|
||||
public function __construct(string $file)
|
||||
{
|
||||
$this->width = collect();
|
||||
$this->ansi = collect();
|
||||
|
||||
$f = fopen($file,'r');
|
||||
while (! feof($f)) {
|
||||
$line = stream_get_line($f,self::BUFREAD,"\r");
|
||||
|
||||
// If the last line is blank, we'll ignore it
|
||||
if ((! feof($f)) || $line) {
|
||||
$this->width->push(self::line_width($line,FALSE));
|
||||
$this->ansi->push(array_map(function($item) { return ord($item); },str_split($line,1)));
|
||||
}
|
||||
}
|
||||
fclose($f);
|
||||
|
||||
return $this->ansi;
|
||||
}
|
||||
|
||||
public function __get($key)
|
||||
{
|
||||
switch ($key) {
|
||||
case 'width':
|
||||
return $this->width;
|
||||
|
||||
case 'max_width':
|
||||
return $this->width->max()+self::LOGO_BUFFER_WIDTH+self::LOGO_OFFSET_WIDTH;
|
||||
|
||||
case 'height':
|
||||
return $this->ansi->count()+self::LOGO_BUFFER_HEIGHT+self::LOGO_OFFSET_HEIGHT;
|
||||
}
|
||||
}
|
||||
|
||||
/* STATIC METHODS */
|
||||
|
||||
/**
|
||||
* Convert a binary ANSI file back to its ANSI version
|
||||
*
|
||||
* @param string $file
|
||||
* @return string
|
||||
*/
|
||||
public static function ansi(string $file)
|
||||
{
|
||||
return static::bin_to_ansi((new self($file))->ansi->toArray());
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a binary ANS file to ANSI text
|
||||
*
|
||||
* @param array $ansi
|
||||
* @param bool $return
|
||||
* @return string
|
||||
*/
|
||||
public static function bin_to_ansi(array $ansi,bool $return=TRUE): string
|
||||
{
|
||||
$output = '';
|
||||
$escape = FALSE;
|
||||
$current = []; // Default Screen
|
||||
|
||||
foreach ($ansi as $line) {
|
||||
foreach ($line as $char) {
|
||||
if ($char == 0x1b) {
|
||||
$escape = TRUE;
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($escape) {
|
||||
if ($x=static::color($char,$current))
|
||||
$output .= "\x1b[".$x;
|
||||
|
||||
$escape = FALSE;
|
||||
|
||||
} else {
|
||||
$output .= chr($char);
|
||||
}
|
||||
}
|
||||
|
||||
if ($return)
|
||||
$output .= "\r\n";
|
||||
}
|
||||
|
||||
return $output;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert an ANSI file into a binary form
|
||||
*
|
||||
* @param string $file
|
||||
* @return Collection
|
||||
*/
|
||||
public static function binary(string $file): Collection
|
||||
{
|
||||
$f = fopen($file,'r');
|
||||
$escape = FALSE;
|
||||
$ansi = FALSE;
|
||||
$buffer = '';
|
||||
$line = '';
|
||||
$result = collect();
|
||||
|
||||
$current = self::reset();
|
||||
|
||||
while (! feof($f)) {
|
||||
$c = fread($f,1);
|
||||
|
||||
switch (ord($c)) {
|
||||
// Ignore \n (0x0a)
|
||||
case 0x0a:
|
||||
continue 2;
|
||||
|
||||
// New line \r (0x0d)
|
||||
case 0x0d:
|
||||
$result->push($line);
|
||||
$line = '';
|
||||
continue 2;
|
||||
|
||||
// We got our ESC
|
||||
case 0x1b:
|
||||
$escape = TRUE;
|
||||
continue 2;
|
||||
|
||||
case ord('['):
|
||||
if ($escape) {
|
||||
$ansi = TRUE;
|
||||
continue 2;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if ($ansi) {
|
||||
switch ($c) {
|
||||
case ';':
|
||||
case 'm':
|
||||
if ((int)$buffer === 0) {
|
||||
$current = self::reset();
|
||||
|
||||
} elseif ((int)$buffer === 1) {
|
||||
$current['h'] = 1;
|
||||
|
||||
} elseif (((int)$buffer >= 30) && (int)$buffer <= 37) {
|
||||
$current['f'] = (int)$buffer;
|
||||
|
||||
} elseif (((int)$buffer >= 40) && (int)$buffer <= 47) {
|
||||
$current['b'] = (int)$buffer;
|
||||
}
|
||||
|
||||
if ($c == 'm') {
|
||||
$ansi = FALSE;
|
||||
$escape = FALSE;
|
||||
$line .= chr(0x1b).chr(self::code($current));
|
||||
}
|
||||
|
||||
$buffer = '';
|
||||
break;
|
||||
|
||||
default:
|
||||
$buffer .= $c;
|
||||
}
|
||||
|
||||
} else {
|
||||
// If escape is still set, but we didnt get an ANSI starter, then we need to record the ESC.
|
||||
if ($escape) {
|
||||
$line .= chr(0x1b);
|
||||
$escape = FALSE;
|
||||
}
|
||||
|
||||
$line .= $c;
|
||||
}
|
||||
}
|
||||
|
||||
// In case our line didnt end \r and we still have data
|
||||
if ($line)
|
||||
$result->push($line);
|
||||
|
||||
fclose($f);
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert an array of 8 bit color codes to a binary form
|
||||
*
|
||||
* @param array $code
|
||||
* @return int
|
||||
*/
|
||||
private static function code(array $code): int
|
||||
{
|
||||
$result = 0;
|
||||
foreach ($code as $item) {
|
||||
switch ($item) {
|
||||
// Color Reset
|
||||
case 0: $result = 0; break;
|
||||
// High Intensity
|
||||
case 1: $result |= self::COLOR_HIGH; break;
|
||||
|
||||
// Foreground
|
||||
case 30: $result |= (self::COLOR_BLACK<<1); break;
|
||||
case 31: $result |= (self::COLOR_RED<<1); break;
|
||||
case 32: $result |= (self::COLOR_GREEN<<1); break;
|
||||
case 33: $result |= (self::COLOR_YELLOW<<1); break;
|
||||
case 34: $result |= (self::COLOR_BLUE<<1); break;
|
||||
case 35: $result |= (self::COLOR_MAGENTA<<1); break;
|
||||
case 36: $result |= (self::COLOR_CYAN<<1); break;
|
||||
case 37: $result |= (self::COLOR_WHITE<<1); break;
|
||||
|
||||
// Background
|
||||
case 40: $result |= (self::COLOR_BLACK<<5); break;
|
||||
case 41: $result |= (self::COLOR_RED<<5); break;
|
||||
case 42: $result |= (self::COLOR_GREEN<<5); break;
|
||||
case 43: $result |= (self::COLOR_YELLOW<<5); break;
|
||||
case 44: $result |= (self::COLOR_BLUE<<5); break;
|
||||
case 45: $result |= (self::COLOR_MAGENTA<<5); break;
|
||||
case 46: $result |= (self::COLOR_CYAN<<5); break;
|
||||
case 47: $result |= (self::COLOR_WHITE<<5); break;
|
||||
|
||||
default:
|
||||
dd('unhandled code:'.$item);
|
||||
}
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert binary code to ANSI escape code
|
||||
*
|
||||
* @param int $code
|
||||
* @param array $current
|
||||
* @return string
|
||||
*/
|
||||
private static function color(int $code,array &$current): string
|
||||
{
|
||||
if (! $current)
|
||||
$current = static::reset();
|
||||
|
||||
$h = ($code&0x01);
|
||||
|
||||
switch ($x=(($code>>1)&0x07)) {
|
||||
case self::COLOR_BLACK: $f = '30'; break;
|
||||
case self::COLOR_RED: $f = '31'; break;
|
||||
case self::COLOR_GREEN: $f = '32'; break;
|
||||
case self::COLOR_YELLOW: $f = '33'; break;
|
||||
case self::COLOR_BLUE: $f = '34'; break;
|
||||
case self::COLOR_MAGENTA: $f = '35'; break;
|
||||
case self::COLOR_CYAN: $f = '36'; break;
|
||||
case self::COLOR_WHITE: $f = '37'; break;
|
||||
default:
|
||||
dump(['unknown color'=>$x]);
|
||||
}
|
||||
|
||||
switch ($x=(($code>>5)&0x07)) {
|
||||
case self::COLOR_BLACK: $b = '40'; break;
|
||||
case self::COLOR_RED: $b = '41'; break;
|
||||
case self::COLOR_GREEN: $b = '42'; break;
|
||||
case self::COLOR_YELLOW: $b = '43'; break;
|
||||
case self::COLOR_BLUE: $b = '44'; break;
|
||||
case self::COLOR_MAGENTA: $b = '45'; break;
|
||||
case self::COLOR_CYAN: $b = '46'; break;
|
||||
case self::COLOR_WHITE: $b = '47'; break;
|
||||
default:
|
||||
dump(['unknown color'=>$x]);
|
||||
}
|
||||
$return = '';
|
||||
$highlight_changed = false;
|
||||
|
||||
if ($h !== $current['h']) {
|
||||
$return .= $h;
|
||||
$current['h'] = $h;
|
||||
$highlight_changed = TRUE;
|
||||
}
|
||||
|
||||
if ($f !== $current['f']) {
|
||||
if (! $highlight_changed || $h || (($f != self::DEFAULT_FORE) || ($b != self::DEFAULT_BACK)))
|
||||
$return .= (strlen($return) ? ';' : '').$f;
|
||||
|
||||
$x = $f;
|
||||
$current['f'] = $f;
|
||||
}
|
||||
|
||||
if ($b !== $current['b']) {
|
||||
if (! $highlight_changed || $h || (($x != self::DEFAULT_FORE) || ($b != self::DEFAULT_BACK)))
|
||||
$return .= (strlen($return) ? ';' : '').$b;
|
||||
|
||||
$current['b'] = $b;
|
||||
}
|
||||
|
||||
return ($return !== '') ? $return.'m' : '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate the width of a line
|
||||
*
|
||||
* @param string $line
|
||||
* @param bool $buffer
|
||||
* @return int
|
||||
*/
|
||||
public static function line_width(string $line,bool $buffer=TRUE): int
|
||||
{
|
||||
return strlen(preg_replace('/\x1b./','',$line))+($buffer ? self::LOGO_OFFSET_WIDTH+self::LOGO_BUFFER_WIDTH : 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* The ANSI was reset (normally CSI [ 0m)
|
||||
*
|
||||
* @return int[]
|
||||
*/
|
||||
private static function reset(): array
|
||||
{
|
||||
return [
|
||||
'h'=>0,
|
||||
'f'=>self::DEFAULT_FORE,
|
||||
'b'=>self::DEFAULT_BACK
|
||||
];
|
||||
}
|
||||
|
||||
/* METHODS */
|
||||
|
||||
/**
|
||||
* Return a specific line
|
||||
*
|
||||
* @param int $line
|
||||
* @return array
|
||||
*/
|
||||
public function line(int $line): array
|
||||
{
|
||||
return $this->ansi->get($line);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the binary line
|
||||
*
|
||||
* @param int $line
|
||||
* @return string
|
||||
*/
|
||||
public function line_raw(int $line): string
|
||||
{
|
||||
return join('',array_map(function($item) { return chr($item); },$this->line($line)));
|
||||
}
|
||||
}
|
258
app/Classes/Font.php
Normal file
258
app/Classes/Font.php
Normal file
@ -0,0 +1,258 @@
|
||||
<?php
|
||||
|
||||
namespace App\Classes;
|
||||
|
||||
use Illuminate\Support\Arr;
|
||||
use Illuminate\Support\Collection;
|
||||
|
||||
class Font
|
||||
{
|
||||
private const DEBUG = FALSE;
|
||||
|
||||
protected const MSG_WIDTH = 79;
|
||||
|
||||
/**
|
||||
* This function will format text to static::MSG_WIDTH, as well as adding the logo.
|
||||
* It is up to the text to be spaced appropriately to wrap around the icon.
|
||||
*
|
||||
* @param string $text
|
||||
* @param ANSI|null $logo
|
||||
* @param bool $right
|
||||
* @param int $step
|
||||
* @return string
|
||||
*/
|
||||
public static function format_msg(string $text,ANSI $logo=NULL,int $step=1,bool $right=FALSE): string
|
||||
{
|
||||
$result = '';
|
||||
$result_height = 0;
|
||||
$current_pos = 0;
|
||||
|
||||
while ($current_pos < strlen($text)) {
|
||||
$result_line = ''; // Line being created
|
||||
$lc = 0; // Line length count (without ANSI)
|
||||
|
||||
$buffer = $step ? $logo->width->skip(intdiv($result_height,$step)*$step)->take($step)->max() : 1;
|
||||
|
||||
// Add our logo
|
||||
if ($result_height <= $logo->height-1) {
|
||||
$line = ANSI::bin_to_ansi([$logo->line($result_height)],FALSE);
|
||||
$lc = $logo->line_width($logo->line_raw($result_height),FALSE);
|
||||
$result_line = str_repeat(' ',ANSI::LOGO_OFFSET_WIDTH)
|
||||
.$line
|
||||
.str_repeat(' ',ANSI::LOGO_BUFFER_WIDTH+($right ? 0 : $buffer-$lc));
|
||||
}
|
||||
|
||||
// Look for a return
|
||||
$return_pos = strpos($text,"\r",$current_pos);
|
||||
|
||||
// We have a return
|
||||
if ($return_pos !== FALSE) {
|
||||
$subtext = substr($text,$current_pos,$return_pos-$current_pos);
|
||||
|
||||
// If the reset of the string will fit on the current line
|
||||
} elseif (strlen($text)-$current_pos < static::MSG_WIDTH-$lc) {
|
||||
$subtext = substr($text,$current_pos);
|
||||
|
||||
// Get the next lines worth of chars
|
||||
} else {
|
||||
$subtext = substr($text,$current_pos,static::MSG_WIDTH-$buffer);
|
||||
|
||||
// Include the text up to the last space
|
||||
if (substr($text,$current_pos+strlen($subtext),1) !== ' ')
|
||||
$subtext = substr($text,$current_pos,strrpos($subtext,' '));
|
||||
}
|
||||
|
||||
$result .= $result_line.
|
||||
str_repeat(' ',($right ? static::MSG_WIDTH-$lc-strlen($subtext)+((! $lc) ? (ANSI::LOGO_OFFSET_WIDTH+ANSI::LOGO_BUFFER_WIDTH) : 0) : 0))
|
||||
.$subtext."\r\n";
|
||||
$current_pos += strlen($subtext)+1;
|
||||
$result_height++;
|
||||
}
|
||||
|
||||
// In case our text is shorter than the logo
|
||||
for (;$result_height<$logo->height;$result_height++) {
|
||||
$result .= str_repeat(' ',ANSI::LOGO_OFFSET_WIDTH)
|
||||
.ANSI::bin_to_ansi([$logo->line($result_height)],FALSE)
|
||||
.str_repeat(' ',ANSI::LOGO_BUFFER_WIDTH)
|
||||
."\r\n";
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* The height of this font (based on the 1st char)
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public static function height(): int
|
||||
{
|
||||
return count(Arr::get(static::FONT,'a'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert text into a graphical font
|
||||
*
|
||||
* @param string $text
|
||||
* @param Collection $width
|
||||
* @param int $height
|
||||
* @param int $step
|
||||
* @return string
|
||||
*/
|
||||
public static function fontText(string $text,Collection $width,int $height,int $step): string
|
||||
{
|
||||
return self::text_to_font($text,$width,$height,$step);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert text to this font
|
||||
* This function will pad the text to fit around the icon, so that the icon+font fils to self::MSG_WIDTH
|
||||
*
|
||||
* @param string $text
|
||||
* @param Collection $icon_width Width to make the font
|
||||
* @param int $icon_height Minimal width for this height, then full width (self::MSG_WIDTH)
|
||||
* @param int $step The grouping of lines (normally font height) around the icon
|
||||
* @return string
|
||||
*/
|
||||
protected static function text_to_font(string $text,Collection $icon_width,int $icon_height,int $step): string
|
||||
{
|
||||
$chars = collect(); // Characters needed for this $text
|
||||
$font_height = 0; // Max height of text using font
|
||||
|
||||
// Trim any leading/trailing spaces
|
||||
$text = trim(strtolower($text));
|
||||
|
||||
// Work out the characters we need
|
||||
foreach (array_unique(str_split($text)) as $c) {
|
||||
if (($c == ' ') || (! $x=Arr::get(static::FONT,$c))) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$chars->put($c,$x);
|
||||
$font_height = (($y=count($x)) > $font_height) ? $y : $font_height;
|
||||
}
|
||||
|
||||
if (self::DEBUG) dump(['uniquechars'=>$chars->count(),'font_height'=>$font_height]);
|
||||
if (self::DEBUG) dump(['drawing'=>$text,'textlen'=>strlen($text),'logo_width'=>$icon_width,'logo_height'=>$icon_height]);
|
||||
|
||||
$result = ''; // Our result
|
||||
$current_pos = 0; // Our current position through $text
|
||||
$result_height = 0; // Our current line height
|
||||
$line_pos = 0; // Our current character position for this line of the font
|
||||
|
||||
while ($current_pos < strlen($text)) {
|
||||
if (self::DEBUG) dump(sprintf('current position %d of %d',$current_pos,strlen($text)));
|
||||
|
||||
for ($line=0;$line<$font_height;$line++) {
|
||||
if ($line == 0) {
|
||||
$line_icon_width = $icon_width
|
||||
->skip(intdiv($result_height,$step)*$step)
|
||||
->take($step)
|
||||
->max();
|
||||
|
||||
if ($line_icon_width)
|
||||
$line_icon_width += ANSI::LOGO_OFFSET_WIDTH+ANSI::LOGO_BUFFER_WIDTH;
|
||||
|
||||
$line_width = self::MSG_WIDTH-$line_icon_width; // Width we are working towards, initially $icon_width until height then its self::MSG_WIDTH
|
||||
}
|
||||
|
||||
$line_result = ''; // Our current line of font
|
||||
if (self::DEBUG) dump(sprintf('- current line %d of %d',$line+1,$font_height));
|
||||
|
||||
// If we are mid way through rendering a font, and have already finished with the height offset, we'll need to fill with blanks
|
||||
if (($line_width !== self::MSG_WIDTH) && ($result_height > $icon_height-1))
|
||||
$line_result .= str_repeat(' ',$line_icon_width);
|
||||
|
||||
$line_pos = $current_pos;
|
||||
$next_space_pos = $current_pos;
|
||||
$next_next_space_width = 0; // What our width will be after the next next space
|
||||
$next_next_space_pos = 0; // The position of the next space after the next one
|
||||
$next_next_space_chars = 0; // The number of chars between the next space and the next next space
|
||||
$current_line_width = 0; // Our current width of the line
|
||||
|
||||
while ($current_line_width < $line_width) {
|
||||
if (self::DEBUG) dump(sprintf(' - current width %d of %d, and we are working on char %d',$current_line_width,$line_width,$line_pos));
|
||||
$find_space_pos = $line_pos;
|
||||
|
||||
// Find our next char
|
||||
if (self::DEBUG) dump(sprintf(' - find our next space from %d after %d',$find_space_pos,$next_space_pos));
|
||||
|
||||
$next_space_chars = 0;
|
||||
if ($next_space_pos <= $line_pos) {
|
||||
if (! $next_next_space_pos) {
|
||||
while (($find_space_pos < strlen($text)) && (($c=substr($text,$find_space_pos++,1)) !== ' ')) {
|
||||
$x = count(Arr::get($chars->get($c),$line));
|
||||
if (self::DEBUG) dump(sprintf(' + char is [%s] (%x) and will take %d chars',$c,ord($c),$x));
|
||||
$next_space_chars += $x;
|
||||
}
|
||||
|
||||
$next_space_pos = $find_space_pos;
|
||||
$next_next_space_pos = $find_space_pos;
|
||||
$next_next_space_width = $current_line_width+$next_space_chars;
|
||||
|
||||
} else {
|
||||
$next_space_pos = $next_next_space_pos;
|
||||
$next_space_chars = $next_next_space_chars;
|
||||
}
|
||||
|
||||
// Find our next next space, which we'll use to decide whether we need to include a space when we find one
|
||||
$next_next_space_chars = 0;
|
||||
while (($next_next_space_pos < strlen($text)) && (($c=substr($text,$next_next_space_pos++,1)) !== ' ')) {
|
||||
$next_next_space_chars += count(Arr::get($chars->get($c),$line,[]));
|
||||
if (self::DEBUG) dump(sprintf(' + char is [%s] (%x) and will take us to %d',$c,ord($c),$next_next_space_chars));
|
||||
}
|
||||
|
||||
$next_next_space_width = $current_line_width+$next_space_chars+$next_next_space_chars;
|
||||
};
|
||||
|
||||
if (self::DEBUG) dump(sprintf(' - our next space is: [%s] (%x) at %d in %d chars, taking %d chars (taking our width to %d)',$c,ord($c),$find_space_pos,$find_space_pos-$line_pos,$next_space_chars,$current_line_width+$next_space_chars));
|
||||
|
||||
// We are only spaces, so we can return to the next line
|
||||
if ($current_line_width+$next_space_chars > $line_width) {
|
||||
if (self::DEBUG) dump(' = next char should go onto new line');
|
||||
|
||||
// Only go to a new line if we already have chars
|
||||
if ($current_line_width)
|
||||
break;
|
||||
}
|
||||
|
||||
$c = substr($text,$line_pos,1);
|
||||
if (($c == ' ') || (! $font_chars=$chars->get($c))) {
|
||||
// Ignore this space if we are at the beginning of the line
|
||||
if ($current_line_width && ($next_next_space_width < $line_width)) {
|
||||
$line_result .= $c;
|
||||
$current_line_width++;
|
||||
}
|
||||
|
||||
} else {
|
||||
if (self::DEBUG) dump(sprintf('adding char [%s] which is [%s]',$c,join('|',Arr::get($font_chars,$line))));
|
||||
|
||||
foreach ($x=Arr::get($font_chars,$line) as $char)
|
||||
$line_result .= chr($char);
|
||||
|
||||
$current_line_width += count($x);
|
||||
}
|
||||
|
||||
$line_pos++;
|
||||
if (self::DEBUG) dump(sprintf(' = line width [%d of %d] and we are on char [%d] our space is [%d]',$current_line_width,$line_width,$line_pos,$find_space_pos));
|
||||
|
||||
if ($line_pos == strlen($text)) {
|
||||
if (self::DEBUG) dump(sprintf(' = we are finished, as we are on char %d on line %d',$line_pos,$line));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
$result_height++;
|
||||
$result .= $line_result."\r";
|
||||
}
|
||||
|
||||
$current_pos = $line_pos;
|
||||
if (self::DEBUG) dump(sprintf('= new line starting with char [%d] - our width is [%d] and we are on line [%d]',$current_pos,$line_width,$result_height));
|
||||
}
|
||||
|
||||
if (self::DEBUG)
|
||||
dd(['result'=>$result]);
|
||||
|
||||
return $result;
|
||||
}
|
||||
}
|
142
app/Classes/Fonts/Thick.php
Normal file
142
app/Classes/Fonts/Thick.php
Normal file
@ -0,0 +1,142 @@
|
||||
<?php
|
||||
|
||||
namespace App\Classes\Fonts;
|
||||
|
||||
use App\Classes\Font;
|
||||
|
||||
class Thick extends Font
|
||||
{
|
||||
|
||||
protected const FONT = [
|
||||
'a' => [
|
||||
[0xdc,0xdc,0xdc,0x20],
|
||||
[0xdc,0xdc,0xdb,0x20],
|
||||
[0xdb,0xdc,0xdb,0x20],
|
||||
],
|
||||
'b' => [
|
||||
[0xdc,0x20,0x20,0x20],
|
||||
[0xdb,0xdf,0xdb,0x20],
|
||||
[0xdb,0xdc,0xdb,0x20],
|
||||
],
|
||||
'c' => [
|
||||
[0xdc,0xdc,0xdc,0x20],
|
||||
[0xdb,0x20,0xdf,0x20],
|
||||
[0xdb,0xdc,0xdb,0x20],
|
||||
],
|
||||
'd' => [
|
||||
[0x20,0x20,0xdc,0x20],
|
||||
[0xdb,0xdf,0xdb,0x20],
|
||||
[0xdb,0xdc,0xdb,0x20],
|
||||
],
|
||||
'e' => [
|
||||
[0xdc,0xdc,0xdc,0x20],
|
||||
[0xdb,0xdc,0xdb,0x20],
|
||||
[0xdb,0xdc,0xdc,0x20],
|
||||
],
|
||||
'f' => [
|
||||
[0xdc,0xdc,0xdc,0x20],
|
||||
[0xdb,0xdc,0x20,0x20],
|
||||
[0xdb,0x20,0x20,0x20],
|
||||
],
|
||||
'g' => [
|
||||
[0xdc,0xdc,0xdc,0x20],
|
||||
[0xdb,0xdc,0xdb,0x20],
|
||||
[0xdc,0xdc,0xdb,0x20],
|
||||
],
|
||||
'h' => [
|
||||
[0xdc,0x20,0x20,0x20],
|
||||
[0xdb,0xdf,0xdb,0x20],
|
||||
[0xdb,0x20,0xdb,0x20],
|
||||
],
|
||||
'i' => [
|
||||
[0xdc,0x20],
|
||||
[0xdc,0x20],
|
||||
[0xdb,0x20],
|
||||
],
|
||||
'j' => [
|
||||
[0x20,0x20,0xdc,0x20],
|
||||
[0x20,0x20,0xdb,0x20],
|
||||
[0xdb,0xdc,0xdb,0x20],
|
||||
],
|
||||
'k' => [
|
||||
[0xdc,0x20,0xdc,0x20],
|
||||
[0xdb,0xdc,0xdf,0x20],
|
||||
[0xdb,0x20,0xdb,0x20],
|
||||
],
|
||||
'l' => [
|
||||
[0xdc,0x20,0x20,0x20],
|
||||
[0xdb,0x20,0x20,0x20],
|
||||
[0xdb,0xdc,0xdb,0x20],
|
||||
],
|
||||
'm' => [
|
||||
[0xdc,0xdc,0xdc,0xdc,0xdc,0x20],
|
||||
[0xdb,0x20,0xdb,0x20,0xdb,0x20],
|
||||
[0xdb,0x20,0x20,0x20,0xdb,0x20],
|
||||
],
|
||||
'n' => [
|
||||
[0xdc,0xdc,0xdc,0x20],
|
||||
[0xdb,0x20,0xdb,0x20],
|
||||
[0xdb,0x20,0xdb,0x20],
|
||||
],
|
||||
'o' => [
|
||||
[0xdc,0xdc,0xdc,0x20],
|
||||
[0xdb,0x20,0xdb,0x20],
|
||||
[0xdb,0xdc,0xdb,0x20],
|
||||
],
|
||||
'p' => [
|
||||
[0xdc,0xdc,0xdc,0x20],
|
||||
[0xdb,0x20,0xdb,0x20],
|
||||
[0xdb,0xdf,0xdf,0x20],
|
||||
],
|
||||
'q' => [
|
||||
[0xdc,0xdc,0xdc,0x20],
|
||||
[0xdb,0x20,0xdb,0x20],
|
||||
[0xdf,0xdf,0xdb,0x20],
|
||||
],
|
||||
'r' => [
|
||||
[0xdc,0xdc,0xdc,0x20],
|
||||
[0xdb,0x20,0xdf,0x20],
|
||||
[0xdb,0x20,0x20,0x20],
|
||||
],
|
||||
's' => [
|
||||
[0xdc,0xdc,0xdc,0x20],
|
||||
[0xdb,0xdc,0xdc,0x20],
|
||||
[0xdc,0xdc,0xdb,0x20],
|
||||
],
|
||||
't' => [
|
||||
[0xdc,0xdc,0xdc,0x20],
|
||||
[0x20,0xdb,0x20,0x20],
|
||||
[0x20,0xdb,0x20,0x20],
|
||||
],
|
||||
'u' => [
|
||||
[0xdc,0x20,0xdc,0x20],
|
||||
[0xdb,0x20,0xdb,0x20],
|
||||
[0xdb,0xdc,0xdb,0x20],
|
||||
],
|
||||
'v' => [
|
||||
[0xdc,0x20,0xdc,0x20],
|
||||
[0xdb,0x20,0xdb,0x20],
|
||||
[0xdf,0xdc,0xdf,0x20],
|
||||
],
|
||||
'w' => [
|
||||
[0xdc,0x20,0x20,0x20,0xdc,0x20],
|
||||
[0xdb,0x20,0xdb,0x20,0xdb,0x20],
|
||||
[0xdb,0xdc,0xdb,0xdc,0xdb,0x20],
|
||||
],
|
||||
'x' => [
|
||||
[0xdc,0x20,0xdc,0x20],
|
||||
[0xdf,0xdb,0xdf,0x20],
|
||||
[0xdb,0xdf,0xdb,0x20],
|
||||
],
|
||||
'y' => [
|
||||
[0xdc,0x20,0xdc,0x20],
|
||||
[0xdb,0xdc,0xdb,0x20],
|
||||
[0xdc,0xdc,0xdb,0x20],
|
||||
],
|
||||
'z' => [
|
||||
[0xdc,0xdc,0xdc,0x20],
|
||||
[0x20,0xdc,0xdf,0x20],
|
||||
[0xdb,0xdc,0xdc,0x20],
|
||||
],
|
||||
];
|
||||
}
|
203
app/Classes/Fonts/Thin.php
Normal file
203
app/Classes/Fonts/Thin.php
Normal file
@ -0,0 +1,203 @@
|
||||
<?php
|
||||
|
||||
namespace App\Classes\Fonts;
|
||||
|
||||
use Illuminate\Support\Collection;
|
||||
|
||||
use App\Classes\Font;
|
||||
|
||||
final class Thin extends Font
|
||||
{
|
||||
protected const FONT = [
|
||||
'a' => [
|
||||
[0xda,0xc4,0xbf],
|
||||
[0xda,0xc4,0xb3],
|
||||
[0xc0,0xc4,0xd9],
|
||||
],
|
||||
'b' => [
|
||||
[0xc3,0xc4,0xbf],
|
||||
[0xb3,0x20,0xb3],
|
||||
[0xc0,0xc4,0xd9],
|
||||
],
|
||||
'c' => [
|
||||
[0xda,0xc4,0xbf],
|
||||
[0xb3,0x20,0x20],
|
||||
[0xc0,0xc4,0xd9],
|
||||
],
|
||||
'd' => [
|
||||
[0xda,0xc4,0xb4],
|
||||
[0xb3,0x20,0xb3],
|
||||
[0xc0,0xc4,0xd9],
|
||||
],
|
||||
'e' => [
|
||||
[0xda,0xc4,0xbf],
|
||||
[0xb3,0xc4,0xd9],
|
||||
[0xc0,0xc4,0xd9],
|
||||
],
|
||||
'f' => [
|
||||
[0xda,0xc4,0xbf],
|
||||
[0xb3,0xc4,0x20],
|
||||
[0xc0,0x20,0x20],
|
||||
],
|
||||
'g' => [
|
||||
[0xda,0xc4,0xbf],
|
||||
[0xc0,0xc4,0xb3],
|
||||
[0xc0,0xc4,0xd9],
|
||||
],
|
||||
'h' => [
|
||||
[0xc2,0x20,0x20],
|
||||
[0xc3,0xc4,0xbf],
|
||||
[0xc1,0x20,0xc1],
|
||||
],
|
||||
'i' => [
|
||||
[0xfe],
|
||||
[0xc2],
|
||||
[0xc1],
|
||||
],
|
||||
'j' => [
|
||||
[0x20,0x20,0xc2],
|
||||
[0x20,0x20,0xb3],
|
||||
[0xc0,0xc4,0xd9],
|
||||
],
|
||||
'k' => [
|
||||
[0xc2,0x20,0xc2],
|
||||
[0xb3,0x2f,0xbf],
|
||||
[0xc1,0x20,0xc1],
|
||||
],
|
||||
'l' => [
|
||||
[0xc2,0x20,0x20],
|
||||
[0xb3,0x20,0x20],
|
||||
[0xc0,0xc4,0xd9],
|
||||
],
|
||||
'm' => [
|
||||
[0xda,0xc4,0xc2,0xbf],
|
||||
[0xb3,0x20,0xb3,0xb3],
|
||||
[0xc1,0x20,0x20,0xc1],
|
||||
],
|
||||
'n' => [
|
||||
[0xda,0xc4,0xbf],
|
||||
[0xb3,0x20,0xb3],
|
||||
[0xc1,0x20,0xc1],
|
||||
],
|
||||
'o' => [
|
||||
[0xda,0xc4,0xbf],
|
||||
[0xb3,0x20,0xb3],
|
||||
[0xc0,0xc4,0xd9],
|
||||
],
|
||||
'p' => [
|
||||
[0xda,0xc4,0xbf],
|
||||
[0xb3,0x20,0xb3],
|
||||
[0xc3,0xc4,0xd9],
|
||||
],
|
||||
'q' => [
|
||||
[0xda,0xc4,0xbf],
|
||||
[0xb3,0x20,0xb3],
|
||||
[0xc0,0xc4,0xb4],
|
||||
],
|
||||
'r' => [
|
||||
[0xda,0xc4,0xbf],
|
||||
[0xb3,0x20,0x20],
|
||||
[0xc1,0x20,0x20],
|
||||
],
|
||||
's' => [
|
||||
[0xda,0xc4,0xbf],
|
||||
[0xc0,0xc4,0xbf],
|
||||
[0xc0,0xc4,0xd9],
|
||||
],
|
||||
't' => [
|
||||
[0xc2,0x20,0x20],
|
||||
[0xc5,0xc4,0x20],
|
||||
[0xc1,0xc4,0xd9],
|
||||
],
|
||||
'u' => [
|
||||
[0xda,0x20,0xbf],
|
||||
[0xb3,0x20,0xb3],
|
||||
[0xc0,0xc4,0xd9],
|
||||
],
|
||||
'v' => [
|
||||
[0xda,0x20,0xbf],
|
||||
[0xb3,0x20,0xb3],
|
||||
[0x20,0x56,0x20],
|
||||
],
|
||||
'w' => [
|
||||
[0xda,0x20,0x20,0xbf],
|
||||
[0xb3,0xb3,0x20,0xb3],
|
||||
[0xc0,0xc1,0xc4,0xd9],
|
||||
],
|
||||
'x' => [
|
||||
[0xda,0x20,0xbf],
|
||||
[0x20,0x58,0x20],
|
||||
[0xc0,0x20,0xd9],
|
||||
],
|
||||
'y' => [
|
||||
[0xda,0x20,0xbf],
|
||||
[0xc0,0xc4,0xb4],
|
||||
[0xc0,0xc4,0xd9],
|
||||
],
|
||||
'z' => [
|
||||
[0xda,0xc4,0xbf],
|
||||
[0xda,0x2f,0xd9],
|
||||
[0xc0,0xc4,0xd9],
|
||||
],
|
||||
'1' => [
|
||||
[0xda,0xbf,0x20],
|
||||
[0x20,0xb3,0x20],
|
||||
[0xc4,0xc1,0xc4],
|
||||
],
|
||||
'2' => [
|
||||
[0xda,0xc4,0xbf],
|
||||
[0xda,0xc4,0xd9],
|
||||
[0xc0,0xc4,0xd9],
|
||||
],
|
||||
'3' => [
|
||||
[0xda,0xc4,0xbf],
|
||||
[0x20,0xc4,0xb4],
|
||||
[0xc0,0xc4,0xd9],
|
||||
],
|
||||
'4' => [
|
||||
[0xda,0x20,0xbf],
|
||||
[0xc0,0xc4,0xb4],
|
||||
[0x20,0x20,0xd9],
|
||||
],
|
||||
'5' => [
|
||||
[0xda,0xc4,0xbf],
|
||||
[0xc0,0xc4,0xbf],
|
||||
[0xc0,0xc4,0xd9],
|
||||
],
|
||||
'6' => [
|
||||
[0xda,0xc4,0xbf],
|
||||
[0xc3,0xc4,0xbf],
|
||||
[0xc0,0xc4,0xd9],
|
||||
],
|
||||
'7' => [
|
||||
[0xda,0xc4,0xbf],
|
||||
[0x20,0xda,0xd9],
|
||||
[0x20,0xc1,0x20],
|
||||
],
|
||||
'8' => [
|
||||
[0xda,0xc4,0xbf],
|
||||
[0xc3,0xc4,0xb4],
|
||||
[0xc0,0xc4,0xd9],
|
||||
],
|
||||
'9' => [
|
||||
[0xda,0xc4,0xbf],
|
||||
[0xc0,0xc4,0xb4],
|
||||
[0x20,0x20,0xd9],
|
||||
],
|
||||
'0' => [
|
||||
[0xda,0xc4,0xbf],
|
||||
[0xb3,0x2f,0xb3],
|
||||
[0xc0,0xc4,0xd9],
|
||||
],
|
||||
'#' => [
|
||||
[0x5f,0x7c,0x7c,0x5f],
|
||||
[0xc4,0xb3,0xb3,0xc4],
|
||||
[0x20,0x20,0x20,0x20],
|
||||
],
|
||||
'!' => [
|
||||
[0xb3],
|
||||
[0xb3],
|
||||
[0xfe],
|
||||
],
|
||||
];
|
||||
}
|
35
app/Console/Commands/ANSIDecode.php
Normal file
35
app/Console/Commands/ANSIDecode.php
Normal file
@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use Illuminate\Console\Command;
|
||||
|
||||
use App\Classes\ANSI;
|
||||
|
||||
class ANSIDecode extends Command
|
||||
{
|
||||
/**
|
||||
* The name and signature of the console command.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'ansi:decode'
|
||||
.' {file : ANS file to decode}';
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description = 'Encode ANS file to custom binary';
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
echo ANSI::ansi($this->argument('file'));
|
||||
}
|
||||
}
|
40
app/Console/Commands/ANSIEncode.php
Normal file
40
app/Console/Commands/ANSIEncode.php
Normal file
@ -0,0 +1,40 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use Illuminate\Console\Command;
|
||||
|
||||
use App\Classes\ANSI;
|
||||
|
||||
class ANSIEncode extends Command
|
||||
{
|
||||
/**
|
||||
* The name and signature of the console command.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'ansi:encode'
|
||||
.' {file : ANS file to encode}';
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description = 'Encode ANS file to custom binary';
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
foreach (ANSI::binary($this->argument('file')) as $line) {
|
||||
foreach (str_split(bin2hex($line),2) as $y)
|
||||
echo hex2bin($y);
|
||||
|
||||
echo "\r";
|
||||
}
|
||||
}
|
||||
}
|
1
public/logo/netmail.bin
Normal file
1
public/logo/netmail.bin
Normal file
@ -0,0 +1 @@
|
||||
ÜÛÛÛÜÜ
ÜáÛÛßßßÛßÛÜ
ÜÜÜáÛßÛÛÛÛî Ûî ÛÜÜÜ
ÜÛÛÛßÞ Ûà-ÛÛÛÛà-Û ÝßÛÛÛ
ßÛÜÜÜ ßÛÜßßßßÜÛß ÜÜÜÛ
ßÛÛßß ßÛÛÛÛßÜ ÛÛÛß
ÜÛÛÜÛÜ þ ÛÛÛÛß
ÜÛÛÜ ÛÛÛÛ Ü!Ü ÜÜÛ
ÛÛÛÛ ÛßßÝÜÜÜß ß
ÛßßÝÜÝÛÛßßß
ÛÛß
|
Loading…
Reference in New Issue
Block a user