* * This source file is subject to the MIT license that is bundled * with this source code in the file LICENSE. */ class PNGQuant { private $binaryPath = "pngquant"; private $imagePath = ""; private $options = array(); /** * The error table is based in the pngquant_error enum of the official library * @see https://github.com/pornel/pngquant/blob/8eebc5702df6901cff71062fc616c4441bfeb48f/rwpng.h#L47 */ private $_errorTable = array( "0" => "SUCCESS", "1" => "MISSING_ARGUMENT", "2" => "READ_ERROR", "4" => "INVALID_ARGUMENT", "15" => "NOT_OVERWRITING_ERROR", "16" => "CANT_WRITE_ERROR", "17" => "OUT_OF_MEMORY_ERROR", "18" => "WRONG_ARCHITECTURE", // Missing SSE "24" => "PNG_OUT_OF_MEMORY_ERROR", "25" => "LIBPNG_FATAL_ERROR", "26" => "WRONG_INPUT_COLOR_TYPE", "35" => "LIBPNG_INIT_ERROR", "98" => "TOO_LARGE_FILE", "99" => "TOO_LOW_QUALITY" ); public function __construct(){ } public function setBinaryPath($pathToBinary){ $this->binaryPath = escapeshellarg($pathToBinary); return $this; } public function setOption($key, $value = null , $space = false, $isPath = false){ $length_options = count($this->options); // Overwrite an option if it was already set for($i = 0; $i < $length_options; ++$i){ $existent_option = $this->options[$i]; if($key == $existent_option["key"]){ array_splice($this->options, $i, 1); } } array_push($this->options, array( 'key' => $key, 'value' => $value, 'space' => $space, 'isPath' => $isPath )); return $this; } public function buildCommand(){ $command = $this->binaryPath. " ". $this->imagePath; foreach($this->options as $option){ $key = $option['key']; $value = $option['value']; $space = $option['space']; $isPath = $option['isPath']; if(!$value){ $command .= " $key"; continue; } if($isPath){ $value = escapeshellarg($value); } if($space){ $command .= " $key $value"; }else{ $command .= " $key=$value"; } } return $command; } /** END console utility wrapper **/ /** Start wrapper **/ public function disableDithering(){ return $this->setOption('--nofs'); } public function getErrorTable(){ return $this->_errorTable; } public function setImage($imagePath){ $this->imagePath = $imagePath; return $this; } public function setCustomExtension($extension){ return $this->setOption('--ext',$extension, true, true); } public function setDitheringLevel($level){ return $this->setOption('--floyd', $level); } public function skipIfLarger(){ return $this->setOption('--skip-if-larger'); } public function setQuality($minQuality = 60, $maxQuality = 80){ return $this->setOption('--quality', "$minQuality-$maxQuality", true); } public function setOutputImage($imagePath){ return $this->setOption('--output', $imagePath, true, true); } public function setSpeed($speed){ return $this->setOption('--speed', $speed, true); } public function overwriteExistingFile(){ return $this->setOption('--force'); } public function posterize($value){ return $this->setOption('--posterize', $value); } public function removeMetadata(){ return $this->setOption('--strip'); } /** * Run the built command */ public function execute(){ $consoleInstruction = $this->buildCommand(); $output = null; system($consoleInstruction, $output); return $output; } /** * Execute PNGQUANT with the providen commands and retrieve the generated image * directly into a variable */ public function getRawOutput(){ // Create a temporal file in the system $fileName = uniqid() . '.png'; $tempFile = tempnam(Zc::C('temp.dir'), $fileName); // Set the output path the tmp file $this->setOutputImage($tempFile); $consoleInstruction = $this->buildCommand(); $output = null; system($consoleInstruction, $output); $imageData = file_get_contents($tempFile); unlink($tempFile); return array( 'statusCode' => $output, 'imageData' => $imageData ); } }