php实现img转ASCII编码图片
【摘要】 经过3晚上的研究,成功实现用php将图片转换成ascii编码图 主要原理:分析像素点的灰度值,用不同字符的深浅度表示(@和.),然后进行字符串组合,输出一:以下是封装类class ImgToASCII{ protected $img_text; protected $img_data;// public $ascii_str = '@#&$8RGA90Q27y=ro|...
经过3晚上的研究,成功实现用php将图片转换成ascii编码图 主要原理:分析像素点的灰度值,用不同字符的深浅度表示(@和.),然后进行字符串组合,输出
一:以下是封装类
class ImgToASCII
{
protected $img_text;
protected $img_data;
// public $ascii_str = '@#&$8RGA90Q27y=ro|i!;:"`-_. ';//12个个字符
// protected $str = "~!@#$%^&*()_+1234567890-=qwertyuiop[]\\asdfghjkl;'zxcvbnm,.QWERTYUIOP{}|ASDFGHJKL:\"ZXCVBNM<>?";
public $ascii_str = 'MWNQqpHAgpOU@#%ER804526tJD)"j][sawf\(x*7ll11__++rr!!::;;~~^\'\',,,```...--- ';//字符
protected $config = array(
'img_path' => '',
'step_x' => 1,
'step_y' => 1,
);
public function __construct($param=array())
{
if(is_array($param)){
$this->config=array_intersect_key($param,$this->config);
}else{
$this->config['img_path']=$param;
}
var_dump($this->config);
}
/**
* 将文件转为gd句柄
* @param null $img_path
* @return resource
* @throws Exception
*/
public function getImg($img_path = null)
{
$img_path == null && $img_path = $this->config['img_path'];
$arr = getimagesize($img_path);
// var_dump($arr);
if ($arr[2] == 1) {
$this->img_data = imagecreatefromgif($img_path);
} else if ($arr[2] == 2) {
$this->img_data = imagecreatefromjpeg($img_path);
} else if ($arr[2] == 3) {
$this->img_data = imagecreatefrompng($img_path);
} else {
throw new \Exception("对不起,暂不支持该格式!");
}
return $this;
}
public function handleImg($img_data = null)
{
$img_data==null && $img_data=$this->img_data;
$x_y_array = $this->getImgXY($img_data);
$output = "";
for ($j = 0; $j < $x_y_array['y']; $j += $this->config['step_x']) {
for ($i = 0; $i < $x_y_array['x']; $i += $this->config['step_x']) {
$colors = imagecolorsforindex($img_data, imagecolorat($img_data, $i, $j)); //获取像素块的代表点RGB信息
$greyness = $this->countGray($colors['red'], $colors["green"], $colors["blue"]) / 255; //灰度值计算公式:Gray=R*0.3+G*0.59+B*0.11
$offset = (int)floor($greyness * (strlen($this->ascii_str) - 1)); //根据灰度值选择合适的字符
if ($offset == (strlen($this->ascii_str) - 1))
$output .= " "; //替换空格为 ;方便网页输出
else
$output .= $this->ascii_str[$offset];
}
$output .= "\n";
}
imagedestroy($img_data);
return $output;
// echo $output;
}
/**
* 测试字符颜色深度
*/
public function test()
{
$str = $this->ascii_str;
// $str = "~!@#$%^&*()_+1234567890-=qwertyuiop[]\\asdfghjkl;'zxcvbnm,.QWERTYUIOP{}|ASDFGHJKL:\"ZXCVBNM<>?";
$str = str_split($str, 20);
// var_dump($str);return;
$output = '';
for ($i = 0; $i <= 50; $i++) {
$str0=str_split($str[0]);
foreach ($str0 as $value) {
$output .= str_repeat($value, 50);
}
$output .= "\n";
}
$str1=str_split($str[1]);
for ($i = 0; $i <= 50; $i++) {
foreach ($str1 as $value) {
$output .= str_repeat($value, 50);
}
$output .= "\n";
}
$str2=str_split($str[2]);
for ($i = 0; $i <= 50; $i++) {
foreach ($str2 as $value) {
$output .= str_repeat($value, 50);
}
$output .= "\n";
}
$str3=str_split($str[3]);
for ($i = 0; $i <= 50; $i++) {
foreach ($str3 as $value) {
$output .= str_repeat($value, 50);
}
$output .= "\n";
}
$str4=str_split($str[4]);
for ($i = 0; $i <= 50; $i++) {
foreach ($str4 as $value) {
$output .= str_repeat($value, 50);
}
$output .= "\n";
}
file_put_contents('1.text',$output);
// echo $output;
}
/**
* 获取图片长宽值
* @param null $img_data
* @return array
*/
public function getImgXY($img_data = null)
{
$img_data == null && $img_data = $this->img_data;
$arr = array(
'x' => imagesx($img_data),
'y' => imagesy($img_data),
);
return $arr;
}
/**
* 计算灰度值
* @param $r
* @param $g
* @param $b
* @return float|int
*/
public function countGray($r, $g, $b)
{
$gray = ($r * 299 + $g * 587 + $b * 114 + 500) / 1000;
return $gray;
}
}
复制
调用方法:
$img = new ImgToASCII('3.gif');
$output=$img->getImg()->handleImg();
echo $output;
复制
可自行处理handleImg方法的换行,以及字符增加标签输出到html
也可直接保存为文件,使用notepad++打开缩小字符效果更佳
$img = new ImgToASCII(array(
'img_path'=>'4.jpg',
'step_x'=>4,//步进值,越小精度越高,1
'step_y'=>4
));
$output=$img->getImg()->handleImg();
file_put_contents('1.txt',$output);
复制
二:将动态gif动态输出
gif图片动态输出原理为:
用php获取gif所有帧,
然后所有帧进行转换成ascii,
配合nginx清屏命令进行动态输出
需要用到gif获取所有帧的类:
<?php
namespace GifFrameExtractor;
/**
* Extract the frames (and their duration) of a GIF
*
* @version 1.5
* @link https://github.com/Sybio/GifFrameExtractor
* @author Sybio (Clément Guillemain / @Sybio01)
* @license http://opensource.org/licenses/gpl-license.php GNU Public License
* @copyright Clément Guillemain
*/
class GifFrameExtractor
{
// Properties
// ===================================================================================
/**
* @var resource
*/
private $gif;
/**
* @var array
*/
private $frames;
/**
* @var array
*/
private $frameDurations;
/**
* @var array
*/
private $frameImages;
/**
* @var array
*/
private $framePositions;
/**
* @var array
*/
private $frameDimensions;
/**
* @var integer
*
* (old: $this->index)
*/
private $frameNumber;
/**
* @var array
*
* (old: $this->imagedata)
*/
private $frameSources;
/**
* @var array
*
* (old: $this->fileHeader)
*/
private $fileHeader;
/**
* @var integer The reader pointer in the file source
*
* (old: $this->pointer)
*/
private $pointer;
/**
* @var integer
*/
private $gifMaxWidth;
/**
* @var integer
*/
private $gifMaxHeight;
/**
* @var integer
*/
private $totalDuration;
/**
* @var integer
*/
private $handle;
/**
* @var array
*
* (old: globaldata)
*/
private $globaldata;
/**
* @var array
*
* (old: orgvars)
*/
private $orgvars;
// Methods
// ===================================================================================
/**
* Extract frames of a GIF
*
* @param string $filename GIF filename path
* @param boolean $originalFrames Get original frames (with transparent background)
*
* @return array
*/
public function extract($filename, $originalFrames = false)
{
if (!self::isAnimatedGif($filename)) {
throw new \Exception('The GIF image you are trying to explode is not animated !');
}
$this->reset();
$this->parseFramesInfo($filename);
$prevImg = null;
for ($i = 0; $i < count($this->frameSources); $i++) {
$this->frames[$i] = array();
$this->frameDurations[$i] = $this->frames[$i]['duration'] = $this->frameSources[$i]['delay_time'];
$img = imagecreatefromstring($this->fileHeader["gifheader"].$this->frameSources[$i]["graphicsextension"].$this->frameSources[$i]["imagedata"].chr(0x3b));
if (!$originalFrames) {
if ($i > 0) {
$prevImg = $this->frames[$i - 1]['image'];
} else {
$prevImg = $img;
}
$sprite = imagecreate($this->gifMaxWidth, $this->gifMaxHeight);
imagesavealpha($sprite, true);
$transparent = imagecolortransparent($prevImg);
if ($transparent > -1 && imagecolorstotal($prevImg) > $transparent) {
$actualTrans = imagecolorsforindex($prevImg, $transparent);
imagecolortransparent($sprite, imagecolorallocate($sprite, $actualTrans['red'], $actualTrans['green'], $actualTrans['blue']));
}
if ((int) $this->frameSources[$i]['disposal_method'] == 1 && $i > 0) {
imagecopy($sprite, $prevImg, 0, 0, 0, 0, $this->gifMaxWidth, $this->gifMaxHeight);
}
imagecopyresampled($sprite, $img, $this->frameSources[$i]["offset_left"], $this->frameSources[$i]["offset_top"], 0, 0, $this->gifMaxWidth, $this->gifMaxHeight, $this->gifMaxWidth, $this->gifMaxHeight);
$img = $sprite;
}
$this->frameImages[$i] = $this->frames[$i]['image'] = $img;
}
return $this->frames;
}
/**
* Check if a GIF file at a path is animated or not
*
* @param string $filename GIF path
*/
public static function isAnimatedGif($filename)
{
if (!($fh = @fopen($filename, 'rb'))) {
return false;
}
$count = 0;
while (!feof($fh) && $count < 2) {
$chunk = fread($fh, 1024 * 100); //read 100kb at a time
$count += preg_match_all('#\x00\x21\xF9\x04.{4}\x00(\x2C|\x21)#s', $chunk, $matches);
}
fclose($fh);
return $count > 1;
}
// Internals
// ===================================================================================
/**
* Parse the frame informations contained in the GIF file
*
* @param string $filename GIF filename path
*/
private function parseFramesInfo($filename)
{
$this->openFile($filename);
$this->parseGifHeader();
$this->parseGraphicsExtension(0);
$this->getApplicationData();
$this->getApplicationData();
$this->getFrameString(0);
$this->parseGraphicsExtension(1);
$this->getCommentData();
$this->getApplicationData();
$this->getFrameString(1);
while (!$this->checkByte(0x3b) && !$this->checkEOF()) {
$this->getCommentData(1);
$this->parseGraphicsExtension(2);
$this->getFrameString(2);
$this->getApplicationData();
}
}
/**
* Parse the gif header (old: get_gif_header)
*/
private function parseGifHeader()
{
$this->pointerForward(10);
if ($this->readBits(($mybyte = $this->readByteInt()), 0, 1) == 1) {
$this->pointerForward(2);
$this->pointerForward(pow(2, $this->readBits($mybyte, 5, 3) + 1) * 3);
} else {
$this->pointerForward(2);
}
$this->fileHeader["gifheader"] = $this->dataPart(0, $this->pointer);
// Decoding
$this->orgvars["gifheader"] = $this->fileHeader["gifheader"];
$this->orgvars["background_color"] = $this->orgvars["gifheader"][11];
}
/**
* Parse the application data of the frames (old: get_application_data)
*/
private function getApplicationData()
{
$startdata = $this->readByte(2);
if ($startdata == chr(0x21).chr(0xff)) {
$start = $this->pointer - 2;
$this->pointerForward($this->readByteInt());
$this->readDataStream($this->readByteInt());
$this->fileHeader["applicationdata"] = $this->dataPart($start, $this->pointer - $start);
} else {
$this->pointerRewind(2);
}
}
/**
* Parse the comment data of the frames (old: get_comment_data)
*/
private function getCommentData()
{
$startdata = $this->readByte(2);
if ($startdata == chr(0x21).chr(0xfe)) {
$start = $this->pointer - 2;
$this->readDataStream($this->readByteInt());
$this->fileHeader["commentdata"] = $this->dataPart($start, $this->pointer - $start);
} else {
$this->pointerRewind(2);
}
}
/**
* Parse the graphic extension of the frames (old: get_graphics_extension)
*
* @param integer $type
*/
private function parseGraphicsExtension($type)
{
$startdata = $this->readByte(2);
if ($startdata == chr(0x21).chr(0xf9)) {
$start = $this->pointer - 2;
$this->pointerForward($this->readByteInt());
$this->pointerForward(1);
if ($type == 2) {
$this->frameSources[$this->frameNumber]["graphicsextension"] = $this->dataPart($start, $this->pointer - $start);
} elseif ($type == 1) {
$this->orgvars["hasgx_type_1"] = 1;
$this->globaldata["graphicsextension"] = $this->dataPart($start, $this->pointer - $start);
} elseif ($type == 0) {
$this->orgvars["hasgx_type_0"] = 1;
$this->globaldata["graphicsextension_0"] = $this->dataPart($start, $this->pointer - $start);
}
} else {
$this->pointerRewind(2);
}
}
/**
* Get the full frame string block (old: get_image_block)
*
* @param integer $type
*/
private function getFrameString($type)
{
if ($this->checkByte(0x2c)) {
$start = $this->pointer;
$this->pointerForward(9);
if ($this->readBits(($mybyte = $this->readByteInt()), 0, 1) == 1) {
$this->pointerForward(pow(2, $this->readBits($mybyte, 5, 3) + 1) * 3);
}
$this->pointerForward(1);
$this->readDataStream($this->readByteInt());
$this->frameSources[$this->frameNumber]["imagedata"] = $this->dataPart($start, $this->pointer - $start);
if ($type == 0) {
$this->orgvars["hasgx_type_0"] = 0;
if (isset($this->globaldata["graphicsextension_0"])) {
$this->frameSources[$this->frameNumber]["graphicsextension"] = $this->globaldata["graphicsextension_0"];
} else {
$this->frameSources[$this->frameNumber]["graphicsextension"] = null;
}
unset($this->globaldata["graphicsextension_0"]);
} elseif ($type == 1) {
if (isset($this->orgvars["hasgx_type_1"]) && $this->orgvars["hasgx_type_1"] == 1) {
$this->orgvars["hasgx_type_1"] = 0;
$this->frameSources[$this->frameNumber]["graphicsextension"] = $this->globaldata["graphicsextension"];
unset($this->globaldata["graphicsextension"]);
} else {
$this->orgvars["hasgx_type_0"] = 0;
$this->frameSources[$this->frameNumber]["graphicsextension"] = $this->globaldata["graphicsextension_0"];
unset($this->globaldata["graphicsextension_0"]);
}
}
$this->parseFrameData();
$this->frameNumber++;
}
}
/**
* Parse frame data string into an array (old: parse_image_data)
*/
private function parseFrameData()
{
$this->frameSources[$this->frameNumber]["disposal_method"] = $this->getImageDataBit("ext", 3, 3, 3);
$this->frameSources[$this->frameNumber]["user_input_flag"] = $this->getImageDataBit("ext", 3, 6, 1);
$this->frameSources[$this->frameNumber]["transparent_color_flag"] = $this->getImageDataBit("ext", 3, 7, 1);
$this->frameSources[$this->frameNumber]["delay_time"] = $this->dualByteVal($this->getImageDataByte("ext", 4, 2));
$this->totalDuration += (int) $this->frameSources[$this->frameNumber]["delay_time"];
$this->frameSources[$this->frameNumber]["transparent_color_index"] = ord($this->getImageDataByte("ext", 6, 1));
$this->frameSources[$this->frameNumber]["offset_left"] = $this->dualByteVal($this->getImageDataByte("dat", 1, 2));
$this->frameSources[$this->frameNumber]["offset_top"] = $this->dualByteVal($this->getImageDataByte("dat", 3, 2));
$this->frameSources[$this->frameNumber]["width"] = $this->dualByteVal($this->getImageDataByte("dat", 5, 2));
$this->frameSources[$this->frameNumber]["height"] = $this->dualByteVal($this->getImageDataByte("dat", 7, 2));
$this->frameSources[$this->frameNumber]["local_color_table_flag"] = $this->getImageDataBit("dat", 9, 0, 1);
$this->frameSources[$this->frameNumber]["interlace_flag"] = $this->getImageDataBit("dat", 9, 1, 1);
$this->frameSources[$this->frameNumber]["sort_flag"] = $this->getImageDataBit("dat", 9, 2, 1);
$this->frameSources[$this->frameNumber]["color_table_size"] = pow(2, $this->getImageDataBit("dat", 9, 5, 3) + 1) * 3;
$this->frameSources[$this->frameNumber]["color_table"] = substr($this->frameSources[$this->frameNumber]["imagedata"], 10, $this->frameSources[$this->frameNumber]["color_table_size"]);
$this->frameSources[$this->frameNumber]["lzw_code_size"] = ord($this->getImageDataByte("dat", 10, 1));
$this->framePositions[$this->frameNumber] = array(
'x' => $this->frameSources[$this->frameNumber]["offset_left"],
'y' => $this->frameSources[$this->frameNumber]["offset_top"],
);
$this->frameDimensions[$this->frameNumber] = array(
'width' => $this->frameSources[$this->frameNumber]["width"],
'height' => $this->frameSources[$this->frameNumber]["height"],
);
// Decoding
$this->orgvars[$this->frameNumber]["transparent_color_flag"] = $this->frameSources[$this->frameNumber]["transparent_color_flag"];
$this->orgvars[$this->frameNumber]["transparent_color_index"] = $this->frameSources[$this->frameNumber]["transparent_color_index"];
$this->orgvars[$this->frameNumber]["delay_time"] = $this->frameSources[$this->frameNumber]["delay_time"];
$this->orgvars[$this->frameNumber]["disposal_method"] = $this->frameSources[$this->frameNumber]["disposal_method"];
$this->orgvars[$this->frameNumber]["offset_left"] = $this->frameSources[$this->frameNumber]["offset_left"];
$this->orgvars[$this->frameNumber]["offset_top"] = $this->frameSources[$this->frameNumber]["offset_top"];
// Updating the max width
if ($this->gifMaxWidth < $this->frameSources[$this->frameNumber]["width"]) {
$this->gifMaxWidth = $this->frameSources[$this->frameNumber]["width"];
}
// Updating the max height
if ($this->gifMaxHeight < $this->frameSources[$this->frameNumber]["height"]) {
$this->gifMaxHeight = $this->frameSources[$this->frameNumber]["height"];
}
}
/**
* Get the image data byte (old: get_imagedata_byte)
*
* @param string $type
* @param integer $start
* @param integer $length
*
* @return string
*/
private function getImageDataByte($type, $start, $length)
{
if ($type == "ext") {
return substr($this->frameSources[$this->frameNumber]["graphicsextension"], $start, $length);
}
// "dat"
return substr($this->frameSources[$this->frameNumber]["imagedata"], $start, $length);
}
/**
* Get the image data bit (old: get_imagedata_bit)
*
* @param string $type
* @param integer $byteIndex
* @param integer $bitStart
* @param integer $bitLength
*
* @return number
*/
private function getImageDataBit($type, $byteIndex, $bitStart, $bitLength)
{
if ($type == "ext") {
return $this->readBits(ord(substr($this->frameSources[$this->frameNumber]["graphicsextension"], $byteIndex, 1)), $bitStart, $bitLength);
}
// "dat"
return $this->readBits(ord(substr($this->frameSources[$this->frameNumber]["imagedata"], $byteIndex, 1)), $bitStart, $bitLength);
}
/**
* Return the value of 2 ASCII chars (old: dualbyteval)
*
* @param string $s
*
* @return integer
*/
private function dualByteVal($s)
{
$i = ord($s[1]) * 256 + ord($s[0]);
return $i;
}
/**
* Read the data stream (old: read_data_stream)
*
* @param integer $firstLength
*/
private function readDataStream($firstLength)
{
$this->pointerForward($firstLength);
$length = $this->readByteInt();
if ($length != 0) {
while ($length != 0) {
$this->pointerForward($length);
$length = $this->readByteInt();
}
}
}
/**
* Open the gif file (old: loadfile)
*
* @param string $filename
*/
private function openFile($filename)
{
$this->handle = fopen($filename, "rb");
$this->pointer = 0;
$imageSize = getimagesize($filename);
$this->gifWidth = $imageSize[0];
$this->gifHeight = $imageSize[1];
}
/**
* Close the read gif file (old: closefile)
*/
private function closeFile()
{
fclose($this->handle);
$this->handle = 0;
}
/**
* Read the file from the beginning to $byteCount in binary (old: readbyte)
*
* @param integer $byteCount
*
* @return string
*/
private function readByte($byteCount)
{
$data = fread($this->handle, $byteCount);
$this->pointer += $byteCount;
return $data;
}
/**
* Read a byte and return ASCII value (old: readbyte_int)
*
* @return integer
*/
private function readByteInt()
{
$data = fread($this->handle, 1);
$this->pointer++;
return ord($data);
}
/**
* Convert a $byte to decimal (old: readbits)
*
* @param string $byte
* @param integer $start
* @param integer $length
*
* @return number
*/
private function readBits($byte, $start, $length)
{
$bin = str_pad(decbin($byte), 8, "0", STR_PAD_LEFT);
$data = substr($bin, $start, $length);
return bindec($data);
}
/**
* Rewind the file pointer reader (old: p_rewind)
*
* @param integer $length
*/
private function pointerRewind($length)
{
$this->pointer -= $length;
fseek($this->handle, $this->pointer);
}
/**
* Forward the file pointer reader (old: p_forward)
*
* @param integer $length
*/
private function pointerForward($length)
{
$this->pointer += $length;
fseek($this->handle, $this->pointer);
}
/**
* Get a section of the data from $start to $start + $length (old: datapart)
*
* @param integer $start
* @param integer $length
*
* @return string
*/
private function dataPart($start, $length)
{
fseek($this->handle, $start);
$data = fread($this->handle, $length);
fseek($this->handle, $this->pointer);
return $data;
}
/**
* Check if a character if a byte (old: checkbyte)
*
* @param integer $byte
*
* @return boolean
*/
private function checkByte($byte)
{
if (fgetc($this->handle) == chr($byte)) {
fseek($this->handle, $this->pointer);
return true;
}
fseek($this->handle, $this->pointer);
return false;
}
/**
* Check the end of the file (old: checkEOF)
*
* @return boolean
*/
private function checkEOF()
{
if (fgetc($this->handle) === false) {
return true;
}
fseek($this->handle, $this->pointer);
return false;
}
/**
* Reset and clear this current object
*/
private function reset()
{
$this->gif = null;
$this->totalDuration = $this->gifMaxHeight = $this->gifMaxWidth = $this->handle = $this->pointer = $this->frameNumber = 0;
$this->frameDimensions = $this->framePositions = $this->frameImages = $this->frameDurations = $this->globaldata = $this->orgvars = $this->frames = $this->fileHeader = $this->frameSources = array();
}
// Getter / Setter
// ===================================================================================
/**
* Get the total of all added frame duration
*
* @return integer
*/
public function getTotalDuration()
{
return $this->totalDuration;
}
/**
* Get the number of extracted frames
*
* @return integer
*/
public function getFrameNumber()
{
return $this->frameNumber;
}
/**
* Get the extracted frames (images and durations)
*
* @return array
*/
public function getFrames()
{
return $this->frames;
}
/**
* Get the extracted frame positions
*
* @return array
*/
public function getFramePositions()
{
return $this->framePositions;
}
/**
* Get the extracted frame dimensions
*
* @return array
*/
public function getFrameDimensions()
{
return $this->frameDimensions;
}
/**
* Get the extracted frame images
*
* @return array
*/
public function getFrameImages()
{
return $this->frameImages;
}
/**
* Get the extracted frame durations
*
* @return array
*/
public function getFrameDurations()
{
return $this->frameDurations;
}
}
复制
调用以及输出代码:
$img = new ImgToASCII();
include_once 'GifFrameExtractor.php';
$gif = new \GifFrameExtractor\GifFrameExtractor();
$a =$gif->extract('2.gif');
$output_array = array();
foreach ($a as $key=> $value){
$path = "./a/{$key}.png";
imagepng($value['image'],$path);
$output_array[] = $img->getImg($path)->handleImg();
}
ob_start();
while(1){
foreach ($output_array as$output){
echo "\033[2J";//清屏
echo $output;
usleep(100000);//延时,避免播放过快
}
usleep(1000000);//循环播放
}
复制
【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱:
cloudbbs@huaweicloud.com
- 点赞
- 收藏
- 关注作者
评论(0)