}
- public static function importFluidbookSettings(){
+ public static function importFluidbookSettings()
+ {
commonDroits::min(5);
global $core;
$res = commonPage::barre();
$res = [];
foreach ($xls->getAllSheets() as $sheet) {
- $res[$sheet->getTitle()]=$sheet->toArray();
+ $res[$sheet->getTitle()] = $sheet->toArray();
}
ob_end_clean();
header('Content-Type: application/json');
die(json_encode($res));
}
+
+ public static function quizUpdater($args)
+ {
+ global $core;
+ $res = commonPage::barre();
+ $res .= commonPage::tMain();
+ $res .= commonPage::bh();
+ $res .= '<form action="' . SITE_PATH . 'tools/updateQuiz" method="post" class="notajax" enctype="multipart/form-data">';
+ $res .= '<table class="liste">';
+ $res .= '<tr><th><strong>' . __('Update your quiz') . '</strong></th></tr>';
+ $res .= '<tr><td>Please upload your quiz (ZIP file expected)</td></tr>';
+ $res .= '<tr class="odd"><td><input type="file" name="file" /></td></tr>';
+ $res .= '<tr><td class="right"><a href="#" class="submit">' . $core->typo->BoutonOK(__('Proceed to update')) . '</a></td></td>';
+ $res .= '</table>';
+ $res .= '</form>';
+ $res .= '</div>';
+ $res .= commonPage::bf();
+ $res .= commonPage::bMain();
+ return $res;
+ }
+
+ public static function updateQuiz()
+ {
+ $tidySettings=['input-xml'=> 1, 'indent' => 1, 'wrap' => 0];
+
+ $template = ROOT . '/quiz/template.zip';
+ $temp = ROOT . '/quiz/quiz-' . md5(rand(0, 10000000)) . '.zip';
+ copy($template, $temp);
+
+ $assets = ['assets/logo.png', 'assets/banner.jpg'];
+
+ $uploaded = new ZipArchive();
+ $uploaded->open($_FILES['file']['tmp_name']);
+
+ $template = new ZipArchive();
+ $template->open($temp);
+
+ $data = simplexml_load_string($uploaded->getFromName('data.xml'));
+ $quizTitle = (string)$data->xpath('/quiz/title')[0];
+
+ // Replace assets
+ foreach ($assets as $asset) {
+ $template->addFromString($asset, $uploaded->getFromName($asset));
+ }
+ // *** Replace XML ***
+ // First, merge both xml
+ $oMX = new MergeXML();
+ $oMX->AddSource($template->getFromName('data.xml'));
+ $oMX->AddSource($uploaded->getFromName('data.xml'));
+ $template->deleteName('data.xml');
+ // Save data.xml in dest zip
+ $template->addFromString('data.xml', tidy_repair_string($oMX->Get(1), $tidySettings));
+ // *** IMS Manifest ***
+ $imsmanifest = file_get_contents(ROOT . '/quiz/imsmanifest.xml');
+ $imsmanifest = str_replace('$title', $quizTitle, tidy_repair_string($imsmanifest,$tidySettings));
+ $template->addFromString('imsmanifest.xml', $imsmanifest);
+ // *** Save zip ***
+ $template->close();
+
+ header('Content-Type: application/zip');
+ header('Content-Disposition: attachment; filename=' . $_FILES['file']['name']);
+ ob_end_clean();
+
+ echo file_get_contents($temp);
+ unlink($temp);
+ exit;
+ }
+
}
+
+
+/**
+ * XML merging class
+ * Merge multiple XML sources
+ *
+ * @package MergeXML
+ * @author Vallo Reima
+ * @copyright (C)2014
+ */
+class MergeXML
+{
+ private $cln = 'DOMDocument';
+ private $dom; /* result DOM object */
+ private $dxp; /* result xPath object */
+ private $nsp; /* namespaces list */
+ private $nsd = '_'; /* default namespace prefix */
+ private $ovw = array(
+ 'stay' => array(), /* do not overwrite me */
+ 'keep' => array() /* do not overwrite existing */
+ );
+ private $join; /* joining root name */
+ private $updn; /* update nodes sequentially by name */
+ private $count = 0; /* adding counter */
+ private $error; /* error info */
+ /**
+ * set (default) options, create result object
+ * @param array $opts -- stay, keep, join, updn, fmt, enc
+ */
+ public function __construct($opts = array())
+ {
+ $this->Protect($opts);
+ $this->join = !isset($opts['join']) ? 'root' : (string)$opts['join'];
+ $this->updn = !isset($opts['updn']) ? true : (bool)$opts['updn'];
+ $this->error = (object)array('code' => '', 'text' => '');
+ if (class_exists($this->cln)) {
+ $this->dom = new $this->cln();
+ $this->dom->preserveWhiteSpace = false;
+ $this->dom->formatOutput = !isset($opts['fmt']) ? true : (bool)$opts['fmt'];
+ $this->dom->encoding = !isset($opts['enc']) ? 'utf-8' : (string)$opts['enc'];
+ } else {
+ $this->Error('nod');
+ }
+ }
+
+ /**
+ * add XML file
+ * @param string $file -- pathed filename
+ * @param array $opts
+ * @return object|false
+ */
+ public function AddFile($file, $opts = array())
+ {
+ $this->Protect($opts);
+ $data = @file_get_contents($file);
+ if ($data === false) {
+ $rlt = $this->Error('nof');
+ } else if (empty($data)) {
+ $rlt = $this->Error('emf');
+ } else {
+ $rlt = $this->AddSource($data);
+ }
+ return $rlt;
+ }
+
+ /**
+ * add XML to result object
+ * @param string|object $xml
+ * @param array $opts
+ * @return mixed -- false - bad content
+ * object - result
+ */
+ public function AddSource($xml, $opts = array())
+ {
+ $this->Protect($opts);
+ if (is_object($xml)) {
+ if (get_class($xml) != $this->cln) {
+ $dom = false;
+ } else if ($this->dom->hasChildNodes()) {
+ $dom = $xml;
+ } else {
+ $this->dom = $xml;
+ $this->dom->formatOutput = true;
+ $dom = true;
+ }
+ } else if ($this->dom->hasChildNodes()) { /* not first */
+ $dom = new $this->cln();
+ $dom->preserveWhiteSpace = false;
+ if (!@$dom->loadXML($xml)) {
+ $dom = false;
+ }
+ } else { /* first slot */
+ $dom = @$this->dom->loadXML($xml) ? true : false;
+ }
+ if ($dom === false) {
+ $rlt = $this->Error('inv');
+ } else if ($dom === true && $this->NameSpaces()) {
+ $this->count = 1;
+ $rlt = $this->dom;
+ } else if (is_object($dom) && $this->CheckSource($dom)) {
+ $this->Merge($dom, '/'); /* add to existing */
+ $this->count++;
+ $rlt = $this->dom;
+ } else {
+ $rlt = false;
+ }
+ return $rlt;
+ }
+
+ /**
+ * set stay/keep
+ * @param array $opt -- options
+ */
+ private function Protect($opt)
+ {
+ foreach ($this->ovw as $key => $val) {
+ if (isset($opt[$key])) {
+ if (is_array($opt[$key])) {
+ $this->ovw[$key] = array_merge($val, $opt[$key]);
+ } else if (!empty($opt[$key])) {
+ array_push($this->ovw[$key], $opt[$key]);
+ }
+ } else if (empty($this->ovw[$key])) {
+ array_push($this->ovw[$key], 'all');
+ }
+ }
+ }
+
+ /**
+ * check/modify root and namespaces,
+ * @param object $dom source
+ * @return {bool}
+ */
+ private function CheckSource(&$dom)
+ {
+ $rlt = true;
+ if (strcasecmp($dom->encoding, $this->dom->encoding) !== 0) {
+ $rlt = $this->Error('enc');
+ } else if ($dom->documentElement->namespaceURI != $this->dom->documentElement->namespaceURI) { /* $dom->documentElement->lookupnamespaceURI(NULL) */
+ $rlt = $this->Error('nse');
+ } else if ($dom->documentElement->nodeName != $this->dom->documentElement->nodeName) {
+ if (!$this->join) {
+ $rlt = $this->Error('dif');
+ } else if (is_string($this->join)) {
+ $doc = new DOMDocument();
+ $doc->encoding = $this->dom->encoding;
+ $doc->preserveWhiteSpace = false;
+ $doc->formatOutput = true;
+ $xml = "<?xml version=\"{$this->dom->xmlVersion}\" encoding=\"{$this->dom->encoding}\"?><$this->join></$this->join>";
+ if (@$doc->loadXML($xml)) {
+ $tmp = $doc->importNode($this->dom->documentElement, true);
+ $doc->documentElement->appendChild($tmp);
+ $this->dom = $doc;
+ $this->join = true;
+ } else {
+ $rlt = $this->Error('jne');
+ $this->join = null;
+ }
+ }
+ }
+ if ($rlt) {
+ $doc = simplexml_import_dom($dom);
+ $rlt = $this->NameSpaces($doc->getDocNamespaces(true));
+ }
+ return $rlt;
+ }
+
+ /**
+ * register namespaces
+ * @param array $nsp -- additional namespaces
+ * @return bool
+ */
+ private function NameSpaces($nsp = array())
+ {
+ $doc = simplexml_import_dom($this->dom);
+ $nsps = $doc->getDocNamespaces(true);
+ foreach ($nsp as $pfx => $url) {
+ if (!isset($nsps[$pfx])) {
+ $this->dom->createAttributeNS($url, "$pfx:attr");
+ $nsps[$pfx] = $url;
+ }
+ }
+ $this->dxp = new DOMXPath($this->dom);
+ $this->nsp = array();
+ $rlt = true;
+ foreach ($nsps as $pfx => $url) {
+ if ($pfx == $this->nsd) {
+ $rlt = $this->Error('nse');
+ break;
+ } else if (empty($pfx)) {
+ $pfx = $this->nsd;
+ }
+ $this->nsp[$pfx] = $url;
+ $this->dxp->registerNamespace($pfx, $url);
+ }
+ return $rlt;
+ }
+
+ /**
+ * join 2 dom objects
+ * @param object $src -- current source node
+ * @param object $pth -- current source path
+ */
+ private function Merge($src, $pth)
+ {
+ $i = 0;
+ foreach ($src->childNodes as $node) {
+ $path = $this->GetNodePath($src->childNodes, $node, $pth, $i);
+ $obj = $this->Query($path);
+ if ($node->nodeType === XML_ELEMENT_NODE) {
+ $flg = true; /* replace existing node by default */
+ if ($obj->length == 0 || $obj->item(0)->namespaceURI != $node->namespaceURI) { /* add node */
+ $tmp = $this->dom->importNode($node, true);
+ $this->Query($pth)->item(0)->appendChild($tmp);
+ } else {
+ if (array_search($obj->item(0)->getAttribute('stay'), $this->ovw['stay']) !== false ||
+ (array_search($node->getAttribute('keep'), $this->ovw['keep']) !== false &&
+ array_search($obj->item(0)->getAttribute('keep'), $this->ovw['keep']) === false)) {
+ $flg = false; /* don't replace */
+ }
+ if ($flg && $node->hasAttributes()) { /* add/replace attributes */
+ foreach ($node->attributes as $attr) {
+ $obj->item(0)->setAttribute($attr->nodeName, $attr->nodeValue);
+ }
+ }
+ }
+ if ($node->hasChildNodes() && $flg) {
+ $this->Merge($node, $path); /* recurse to subnodes */
+ }
+ } else if ($node->nodeType === XML_TEXT_NODE || $node->nodeType === XML_COMMENT_NODE) { /* leaf node */
+ if ($obj->length == 0) {
+ if ($node->nodeType === XML_TEXT_NODE) {
+ $tmp = $this->dom->createTextNode($node->nodeValue);
+ } else {
+ $tmp = $this->dom->createComment($node->nodeValue);
+ }
+ $this->Query($pth)->item(0)->appendChild($tmp);
+ } else {
+ $obj->item(0)->nodeValue = $node->nodeValue;
+ }
+ }
+ $i++;
+ }
+ }
+
+ /**
+ * form the node xPath expression
+ * @param {object} $nodes -- child nodes
+ * @param {object} $node -- current child
+ * @param {string} $pth -- parent path
+ * @param {int} $eln -- element sequence number
+ * @return {string} query path
+ */
+ private function GetNodePath($nodes, $node, $pth, $eln)
+ {
+ $j = 0;
+ if ($node->nodeType === XML_ELEMENT_NODE) {
+ $i = 0;
+ foreach ($nodes as $nde) {
+ if ($i > $eln) {
+ break;
+ } else if (($this->updn && $nde->nodeType === $node->nodeType && $nde->nodeName === $node->nodeName && $nde->namespaceURI === $node->namespaceURI) ||
+ (!$this->updn && $nde->nodeType !== XML_PI_NODE)) {
+ $j++;
+ }
+ $i++;
+ }
+ if ($this->updn) {
+ if ($node->prefix) {
+ $p = $node->prefix . ':';
+ } else if (isset($this->nsp[$this->nsd])) {
+ $p = $this->nsd . ':';
+ } else {
+ $p = '';
+ }
+ $p .= $node->localName;
+ } else {
+ $p = 'node()';
+ }
+ } else if ($node->nodeType === XML_TEXT_NODE || $node->nodeType === XML_COMMENT_NODE) {
+ $i = 0;
+ foreach ($nodes as $nde) {
+ if ($i > $eln) {
+ break;
+ } else if ($nde->nodeType === $node->nodeType) {
+ $j++;
+ }
+ $i++;
+ }
+ $p = $node->nodeType === XML_TEXT_NODE ? 'text()' : 'comment()';
+ } else {
+ $p = $pth;
+ }
+ if ($j > 0) {
+ $p = $pth . ($pth === '/' ? '' : '/') . $p . '[' . $j . ']';
+ }
+ return $p;
+ }
+
+ /**
+ * xPath query
+ * @param string $qry -- query statement
+ * @return object
+ */
+ public function Query($qry)
+ {
+ if ($this->join === true) {
+ $qry = "/{$this->dom->documentElement->nodeName}" . ($qry === '/' ? '' : $qry);
+ }
+ $rlt = $this->dxp->query($qry);
+ return $rlt;
+ }
+
+ /**
+ * get result
+ * @param {int} flg -- 0 - object
+ * 1 - xml
+ * 2 - html
+ * @return {mixed}
+ */
+ public function Get($flg = 0)
+ {
+ if ($flg == 0) {
+ $rlt = $this->dom;
+ } else {
+ $rlt = $this->dom->saveXML();
+ if ($flg == 2) {
+ $r = str_replace(' ', ' ', htmlspecialchars($rlt));
+ $rlt = str_replace(array("\r\n", "\n", "\r"), '<br />', $r);
+ }
+ }
+ return $rlt;
+ }
+
+ /**
+ * set error message
+ * @param string $err token
+ * @return false
+ */
+ private function Error($err = 'und')
+ {
+ $errs = array(
+ 'nod' => "$this->cln is not supported",
+ 'nof' => 'File not found',
+ 'emf' => 'File is empty', /* possible delivery fault */
+ 'inv' => 'Invalid XML source',
+ 'enc' => 'Different encoding',
+ 'dif' => 'Different root nodes',
+ 'jne' => 'Invalid join parameter',
+ 'nse' => 'Namespace incompatibility',
+ 'und' => 'Undefined error');
+ $this->error->code = isset($errs[$err]) ? $err : 'und';
+ $this->error->text = $errs[$this->error->code];
+ return false;
+ }
+
+ /**
+ * get property value
+ * @param string $name
+ * @return mixed -- null - missing
+ */
+ public function __get($name)
+ {
+ return isset($this->$name) ? $this->$name : null;
+ }
+}
+
+/**
+ * Minify XML source
+ *
+ * @package Packer
+ * @author Vallo Reima
+ * @copyright (C)2015
+ */
+class PackXML
+{
+ private $input;
+ private $nodes = []; /* node objects to remove */
+ /**
+ * @param string $source
+ * @param array $options
+ * @return mixed -- string - ok
+ */
+ public static function minify($source, $options = [])
+ {
+ $min = new self($source);
+ return $min->process();
+ }
+
+ /**
+ * @param string $input
+ */
+ public function __construct($input)
+ {
+ $this->input = $input;
+ }
+
+ /**
+ * minify
+ * @return string|false
+ */
+ private function process()
+ {
+ $dom = new DOMDocument();
+ $dom->preserveWhiteSpace = false;
+ $dom->formatOutput = false;
+ if (@$dom->loadXML($this->input)) {
+ $this->Detect($dom); // fix excessive nodes
+ foreach ($this->nodes as $node) {
+ $node->parentNode->removeChild($node); // remove fixed nodes
+ }
+ $rlt = $dom->saveXML(); // convert to string
+ } else { // bad content
+ $rlt = false;
+ }
+ return $rlt;
+ }
+
+ /**
+ * collect excessive node objects
+ * @param object $root
+ */
+ private function Detect($root)
+ {
+ foreach ($root->childNodes as $node) {
+ if ($node->nodeType == XML_COMMENT_NODE || ($node->nodeType == XML_TEXT_NODE && trim($node->nodeValue) == '')) {
+ array_push($this->nodes, $node); // comment or empty text
+ } else if ($node->nodeType == XML_ELEMENT_NODE) {
+ $this->Detect($node); // recurse subnodes
+ }
+ }
+ }
+}
\ No newline at end of file
class wsTools
{
- protected static $_r;
- protected static $_i;
- protected static $_e;
- protected static $_u;
-
- public static function encodeWebVideos($file, $dir = null, $async = true, $force = false, $format = 'all')
- {
- if (is_null($dir)) {
- $dir = dirname($file);
- }
-
- $videos = array('mp4', 'jpg');
-
- if (is_string($format)) {
- if ($format == 'none') {
- $format = array();
- } elseif ($format == 'all') {
- $format = $videos;
- } else {
- $format = array($format);
- }
- }
-
- if (!$force) {
- $format = array();
- }
-
- $base = $dir . '/' . cubeFiles::getName($file);
- $log = $base . '.log';
-
- foreach ($videos as $v) {
- $vfile = $base . '.' . $v;
- if (!file_exists($vfile)) {
- $force = true;
- } else if (filemtime($file) > filemtime($vfile) || in_array($v, $format)) {
- $force = true;
- unlink($vfile);
- }
- }
-
- if (!$force && file_exists($log) && filemtime($log) > filemtime($file)) {
- return;
- }
-
- $webvideo = new cubeCommandLine('webvideo', $log);
- $webvideo->setPath(CONVERTER_PATH);
- if ($async) {
- $webvideo->setNohup(true);
- }
- $webvideo->setArg(null, $file);
- $webvideo->setArg(null, $dir);
- $webvideo->execute();
- }
-
- public static function colorizeAndRasterizeIcon($iconSet, $icon, $colors, $dest, $scale, &$w, &$h, $makepng = true)
- {
- // Init directory
- if (is_string($colors)) {
- $colors = array('colorize' => $colors);
- }
- $hash = sha1(json_encode($colors));
- foreach ($colors as $k => $v) {
- $colors[$k] = wsHTML5::colorToArray($colors[$k]);
- }
-
- $e = explode('-', $icon);
- $type = $e[0];
-
- if ($type == 'nav') {
- $svgRef = WS_ICONS . '/' . $iconSet . '/mobile/' . $icon . '.svg';
- if (!file_exists($svgRef)) {
- $iconSet = 1;
- $svgRef = WS_ICONS . '/' . $iconSet . '/mobile/' . $icon . '.svg';
- }
-
- $dirColorized = WS_ICONS . '/' . $iconSet . '/mobile/colorized/' . $hash . '/';
- $svgColorized = $dirColorized . '/' . $icon . '.svg';
- } else {
- $dirColorized = WS_ICONS . '/' . $type . '/colorized/' . $hash;
- $svgRef = WS_ICONS . '/' . $type . '/' . $icon . '.svg';
- $svgColorized = $dirColorized . '/' . $icon . '.svg';
- }
-
- if (!file_exists($dirColorized)) {
- mkdir($dirColorized, 0777, true);
- }
-
-
- // SVG
- $time = max(filemtime(__FILE__), filemtime($svgRef));
- if (!file_exists($svgColorized) || filemtime($svgColorized) <= $time) {
- $svg = file_get_contents($svgRef);
- // Colorize it
- foreach ($colors as $k => $v) {
- $replace = "#" . $v['hex'];
- if ($v['opacity'] < 1) {
- $replace .= '" stroke-opacity="' . $v['opacity'];
- }
- $svg = str_replace('$s' . $k, $replace, $svg);
-
-
- $replace = "#" . $v['hex'];
- if ($v['opacity'] < 1) {
- $replace .= '" fill-opacity="' . $v['opacity'];
- }
- $svg = str_replace('$' . $k, $replace, $svg);
- }
- file_put_contents($svgColorized, $svg);
- }
- self::copy($svgColorized, $dest . '/' . $icon . '.svg');
-
- // PNG
- $png = $dirColorized . '/' . $icon . '.png';
- $time = max(filemtime(__FILE__), filemtime($svgColorized));
- if (!file_exists($png) || filemtime($png) <= $time) {
- $svg = simplexml_load_file($svgColorized);
- $w = (string)$svg['width'];
- $h = (string)$svg['height'];
- $w = rtrim($w, 'px');
- $h = rtrim($h, 'px');
- // Finally rasterize it
- $batik = new cubeCommandLine('inkscape');
- $batik->setArg('z');
- $batik->setArg('e', $png);
- $batik->setArg('w', floatval($w) * $scale);
- $batik->setArg('h', floatval($h) * $scale);
- $batik->setManualArg($svgColorized);
- $batik->execute();
- }
-
- if (file_exists($png)) {
- $dim = getimagesize($png);
- $w = $dim[0] / $scale;
- $h = $dim[1] / $scale;
- }
-
- if ($makepng) {
- self::copy($png, $dest . '/' . $icon . '.png');
- }
- }
-
- public static function optimizeSVG($original, $optimized, $resolutions = [], $force = false)
- {
-
- if (!file_exists($original)) {
- return 'doesnt exists';
- }
-
- $baseoptimized = str_replace('%s', '', $optimized);
-
- $expireoriginallimit = max(filemtime($original), filemtime(__FILE__));
-
- $notexists = !file_exists($baseoptimized);
- if (!$notexists) {
- $cleanerexpired = filemtime($baseoptimized) < filemtime('/usr/local/bin/svgcleaner');
- $originalexpired = filemtime($baseoptimized) < $expireoriginallimit;
- } else {
- $cleanerexpired = false;
- $originalexpired = false;
- }
-
- $optimize = $force ||
- $notexists ||
- $cleanerexpired ||
- $originalexpired;
-
- if ($optimize) {
- $cmd = "timeout -s 1 120 /usr/local/bin/svgcleaner --allow-bigger-file --paths-coordinates-precision 3 --copy-on-error --stdout $original";
- $svg = `$cmd`;
- if ($svg == '') {
- $svg = file_get_contents($original);
- }
- $svg = substr_replace($svg, ' preserveAspectRatio="none" ', 5, 0);
-
- $fname = $baseoptimized;
- file_put_contents($fname, $svg);
-
- if (count($resolutions) > 0) {
- foreach ($resolutions as $resolution) {
- self::$_r = $resolution;
- $osvg = preg_replace_callback('|\<image([^>]*)\>|', 'wsTools::optimizeRaster', $svg);
- $osvg = preg_replace('/^<svg[^>]*>/', '$0<rect width="100%" height="100%" fill="white" />', $osvg);
- $ofname = sprintf($optimized, '-' . $resolution);
- file_put_contents($ofname, $osvg);
- }
- }
- return true;
- }
- return false;
- }
-
- public static function optimizeRaster($matches)
- {
- preg_match_all('/([a-z\:\-]*)="([^"]*)"/', $matches[1], $m);
-
- foreach ($m[1] as $i => $key) {
- $attrs[$key] = $m[2][$i];
- }
- $e = explode(',', $attrs['xlink:href'], 2);
- $image = imagecreatefromstring(base64_decode($e[1]));
- $iw = imagesx($image);
- $ih = imagesy($image);
- $scale = 1;
- if (isset($attrs['transform']) && strpos($attrs['transform'], 'matrix(') === 0) {
- preg_match_all('/([\d\-\.]+)/', $attrs['transform'], $ma);
- $values = $ma[0];
- $scale = max($values[0], $values[1]);
- }
-
- $resolutionScale = ($iw / $attrs['width']) * $scale * (self::$_r / 72);
-
- $dw = round($resolutionScale * $iw);
- $dh = round($resolutionScale * $ih);
-
- $im = imagecreatetruecolor($dw, $dh);
- imagecopyresampled($im, $image, 0, 0, 0, 0, $dw, $dh, $iw, $ih);
- imagedestroy($image);
-
- $tmp = CubeIT_Files::tempnam();
- imagejpeg($im, $tmp, 85);
- imagedestroy($im);
-
- $attrs['xlink:href'] = 'data:image/jpeg;base64,' . base64_encode(file_get_contents($tmp));
- unlink($tmp);
-
- $res = '<image ';
- foreach ($attrs as $k => $v) {
- $res .= $k . '="' . $v . '" ';
- }
- $res .= '/>';
- return $res;
- }
-
- public static function copy($source, $dest)
- {
- if (!file_exists($source)) {
- return;
- }
- $dir = dirname($dest);
- if (!file_exists($dir)) {
- mkdir($dir, 0777, true);
- }
- copy($source, $dest);
- touch($dest, filemtime($source));
- }
-
- public static function pages2html($book_id, $page)
- {
- global $core;
- if ($page % 2 == 1) {
- $page--;
- }
-
- $convert = [$page, $page + 1];
-
- $dao = new wsDAOBook($core->con);
- $pages = $dao->getPagesOfBook($book_id);
-
- $svg = '';
- $left = 0;
- $css = '';
- foreach ($convert as $item) {
-
- if (isset($pages[$item])) {
- $p = $pages[$item];
- $dir = wsDocument::getDir($p['document_id']);
- $f = $dir . '/html/fo' . $p['document_page'] . '-150.svg';
-
- if (!isset($width)) {
- $s = CubeIT_Image::getimagesize($f);
- $width = $s[0];
- $height = $s[1];
- }
-
- $svg .= '<div class="page" id="p' . $item . '">';
- $svg .= self::_svg(file_get_contents($f), $item);
- $svg .= '</div>';
- $css .= '#p' . $item . '{left:' . $left . 'px;}';
- $left += ($width - 1);
- }
- }
-
- $res = '<html>';
- $res .= '<head>';
- $res .= '<meta name="width" value="' . $left . '">';
- $res .= '<meta name="height" value="' . $height . '">';
- $res .= '<!-- tweenmax --><script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/2.0.2/TweenMax.min.js"></script><!-- -->';
- $res .= '<!-- jquery --><script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script><!-- -->';
- $res .= '<script src="main.js"></script>';
- $res .= '<style type="text/css">*{padding:0;margin:0}svg{display: block;}.page{position: absolute;top: 0;}.page svg{width:' . $width . 'px;height:' . $height . 'px;}' . $css . '</style></head>';
- $res .= '<link href="main.css" type="text/css" rel="stylesheet" />';
- $res .= '<body>';
- $res .= $svg;
- $res .= '</body>';
- $res .= '</html>';
-
- $n = 'fb_' . $book_id . '_' . $page . '.zip';
- $zipname = '/tmp/' . $n;
- $zip = new ZipArchive();
- $zip->open($zipname, ZipArchive::CREATE);
- $zip->addFromString('index.html', $res);
- $zip->close();
- return ['name' => $n, 'path' => $zipname];
- }
-
- protected static function _svg($c, $p)
- {
- self::$_i = 0;
- self::$_e = 0;
- self::$_u = 0;
-
- $c = str_replace('id="', 'id="p' . $p . '-', $c);
- $c = str_replace('url(#', 'url(#p' . $p . '-', $c);
- $c = str_replace('xlink:href="#', 'xlink:href="#p' . $p . '-', $c);
- $c = preg_replace_callback('/\<image([^\>]*)\>/m', function ($matches) use ($p) {
- self::$_i++;
- return '<g id="p' . $p . '-imageholder-' . self::$_i . '"><image id="p' . $p . '-image-' . self::$_i . '" ' . $matches[1] . '></g>';
- }, $c);
- $c = str_replace('</image>', '</image></g></g>', $c);
-
- $c = preg_replace_callback('/<path /', function () use ($p) {
- self::$_e++;
- return '<path id="p' . $p . '-e-' . self::$_e . '" ';
- }, $c);
- $c = preg_replace_callback('/<use /', function () use ($p) {
- self::$_u++;
- return '<use id="p' . $p . '-u-' . self::$_u . '" ';
- }, $c);
-
- return $c;
- }
-
-
- public function chiffres()
- {
-
- }
+ protected static $_r;
+ protected static $_i;
+ protected static $_e;
+ protected static $_u;
+
+ public static function encodeWebVideos($file, $dir = null, $async = true, $force = false, $format = 'all')
+ {
+ if (is_null($dir)) {
+ $dir = dirname($file);
+ }
+
+ $videos = array('mp4', 'jpg');
+
+ if (is_string($format)) {
+ if ($format == 'none') {
+ $format = array();
+ } elseif ($format == 'all') {
+ $format = $videos;
+ } else {
+ $format = array($format);
+ }
+ }
+
+ if (!$force) {
+ $format = array();
+ }
+
+ $base = $dir . '/' . cubeFiles::getName($file);
+ $log = $base . '.log';
+
+ foreach ($videos as $v) {
+ $vfile = $base . '.' . $v;
+ if (!file_exists($vfile)) {
+ $force = true;
+ } else if (filemtime($file) > filemtime($vfile) || in_array($v, $format)) {
+ $force = true;
+ unlink($vfile);
+ }
+ }
+
+ if (!$force && file_exists($log) && filemtime($log) > filemtime($file)) {
+ return;
+ }
+
+ $webvideo = new cubeCommandLine('webvideo', $log);
+ $webvideo->setPath(CONVERTER_PATH);
+ if ($async) {
+ $webvideo->setNohup(true);
+ }
+ $webvideo->setArg(null, $file);
+ $webvideo->setArg(null, $dir);
+ $webvideo->execute();
+ }
+
+ public static function colorizeAndRasterizeIcon($iconSet, $icon, $colors, $dest, $scale, &$w, &$h, $makepng = true)
+ {
+ // Init directory
+ if (is_string($colors)) {
+ $colors = array('colorize' => $colors);
+ }
+ $hash = sha1(json_encode($colors));
+ foreach ($colors as $k => $v) {
+ $colors[$k] = wsHTML5::colorToArray($colors[$k]);
+ }
+
+ $e = explode('-', $icon);
+ $type = $e[0];
+
+ if ($type == 'nav') {
+ $svgRef = WS_ICONS . '/' . $iconSet . '/mobile/' . $icon . '.svg';
+ if (!file_exists($svgRef)) {
+ $iconSet = 1;
+ $svgRef = WS_ICONS . '/' . $iconSet . '/mobile/' . $icon . '.svg';
+ }
+
+ $dirColorized = WS_ICONS . '/' . $iconSet . '/mobile/colorized/' . $hash . '/';
+ $svgColorized = $dirColorized . '/' . $icon . '.svg';
+ } else {
+ $dirColorized = WS_ICONS . '/' . $type . '/colorized/' . $hash;
+ $svgRef = WS_ICONS . '/' . $type . '/' . $icon . '.svg';
+ $svgColorized = $dirColorized . '/' . $icon . '.svg';
+ }
+
+ if (!file_exists($dirColorized)) {
+ mkdir($dirColorized, 0777, true);
+ }
+
+
+ // SVG
+ $time = max(filemtime(__FILE__), filemtime($svgRef));
+ if (!file_exists($svgColorized) || filemtime($svgColorized) <= $time) {
+ $svg = file_get_contents($svgRef);
+ // Colorize it
+ foreach ($colors as $k => $v) {
+ $replace = "#" . $v['hex'];
+ if ($v['opacity'] < 1) {
+ $replace .= '" stroke-opacity="' . $v['opacity'];
+ }
+ $svg = str_replace('$s' . $k, $replace, $svg);
+
+
+ $replace = "#" . $v['hex'];
+ if ($v['opacity'] < 1) {
+ $replace .= '" fill-opacity="' . $v['opacity'];
+ }
+ $svg = str_replace('$' . $k, $replace, $svg);
+ }
+ file_put_contents($svgColorized, $svg);
+ }
+ self::copy($svgColorized, $dest . '/' . $icon . '.svg');
+
+ // PNG
+ $png = $dirColorized . '/' . $icon . '.png';
+ $time = max(filemtime(__FILE__), filemtime($svgColorized));
+ if (!file_exists($png) || filemtime($png) <= $time) {
+ $svg = simplexml_load_file($svgColorized);
+ $w = (string)$svg['width'];
+ $h = (string)$svg['height'];
+ $w = rtrim($w, 'px');
+ $h = rtrim($h, 'px');
+ // Finally rasterize it
+ $batik = new cubeCommandLine('inkscape');
+ $batik->setArg('z');
+ $batik->setArg('e', $png);
+ $batik->setArg('w', floatval($w) * $scale);
+ $batik->setArg('h', floatval($h) * $scale);
+ $batik->setManualArg($svgColorized);
+ $batik->execute();
+ }
+
+ if (file_exists($png)) {
+ $dim = getimagesize($png);
+ $w = $dim[0] / $scale;
+ $h = $dim[1] / $scale;
+ }
+
+ if ($makepng) {
+ self::copy($png, $dest . '/' . $icon . '.png');
+ }
+ }
+
+ public static function optimizeSVG($original, $optimized, $resolutions = [], $force = false)
+ {
+
+ if (!file_exists($original)) {
+ return 'doesnt exists';
+ }
+
+ $baseoptimized = str_replace('%s', '', $optimized);
+
+ $expireoriginallimit = max(filemtime($original), filemtime(__FILE__));
+
+ $notexists = !file_exists($baseoptimized);
+ if (!$notexists) {
+ $cleanerexpired = filemtime($baseoptimized) < filemtime('/usr/local/bin/svgcleaner');
+ $originalexpired = filemtime($baseoptimized) < $expireoriginallimit;
+ } else {
+ $cleanerexpired = false;
+ $originalexpired = false;
+ }
+
+ $optimize = $force ||
+ $notexists ||
+ $cleanerexpired ||
+ $originalexpired;
+
+ if ($optimize) {
+ $cmd = "timeout -s 1 120 /usr/local/bin/svgcleaner --allow-bigger-file --paths-coordinates-precision 3 --copy-on-error --stdout $original";
+ $svg = `$cmd`;
+ if ($svg == '') {
+ $svg = file_get_contents($original);
+ }
+ $svg = substr_replace($svg, ' preserveAspectRatio="none" ', 5, 0);
+
+ $fname = $baseoptimized;
+ file_put_contents($fname, $svg);
+
+ if (count($resolutions) > 0) {
+ foreach ($resolutions as $resolution) {
+ self::$_r = $resolution;
+ $osvg = preg_replace_callback('|\<image([^>]*)\>|', 'wsTools::optimizeRaster', $svg);
+ $osvg = preg_replace('/^<svg[^>]*>/', '$0<rect width="100%" height="100%" fill="white" />', $osvg);
+ $ofname = sprintf($optimized, '-' . $resolution);
+ file_put_contents($ofname, $osvg);
+ }
+ }
+ return true;
+ }
+ return false;
+ }
+
+ public static function optimizeRaster($matches)
+ {
+ preg_match_all('/([a-z\:\-]*)="([^"]*)"/', $matches[1], $m);
+
+ foreach ($m[1] as $i => $key) {
+ $attrs[$key] = $m[2][$i];
+ }
+ $e = explode(',', $attrs['xlink:href'], 2);
+ $image = imagecreatefromstring(base64_decode($e[1]));
+ $iw = imagesx($image);
+ $ih = imagesy($image);
+ $scale = 1;
+ if (isset($attrs['transform']) && strpos($attrs['transform'], 'matrix(') === 0) {
+ preg_match_all('/([\d\-\.]+)/', $attrs['transform'], $ma);
+ $values = $ma[0];
+ $scale = max($values[0], $values[1]);
+ }
+
+ $resolutionScale = ($iw / $attrs['width']) * $scale * (self::$_r / 72);
+
+ $dw = round($resolutionScale * $iw);
+ $dh = round($resolutionScale * $ih);
+
+ $im = imagecreatetruecolor($dw, $dh);
+ imagecopyresampled($im, $image, 0, 0, 0, 0, $dw, $dh, $iw, $ih);
+ imagedestroy($image);
+
+ $tmp = CubeIT_Files::tempnam();
+ imagejpeg($im, $tmp, 85);
+ imagedestroy($im);
+
+ $attrs['xlink:href'] = 'data:image/jpeg;base64,' . base64_encode(file_get_contents($tmp));
+ unlink($tmp);
+
+ $res = '<image ';
+ foreach ($attrs as $k => $v) {
+ $res .= $k . '="' . $v . '" ';
+ }
+ $res .= '/>';
+ return $res;
+ }
+
+ public static function copy($source, $dest)
+ {
+ if (!file_exists($source)) {
+ return;
+ }
+ $dir = dirname($dest);
+ if (!file_exists($dir)) {
+ mkdir($dir, 0777, true);
+ }
+ copy($source, $dest);
+ touch($dest, filemtime($source));
+ }
+
+ public static function pages2html($book_id, $page)
+ {
+ global $core;
+ if ($page % 2 == 1) {
+ $page--;
+ }
+
+ $convert = [$page, $page + 1];
+
+ $dao = new wsDAOBook($core->con);
+ $pages = $dao->getPagesOfBook($book_id);
+
+ $svg = '';
+ $left = 0;
+ $css = '';
+ foreach ($convert as $item) {
+
+ if (isset($pages[$item])) {
+ $p = $pages[$item];
+ $dir = wsDocument::getDir($p['document_id']);
+ $f = $dir . '/html/fo' . $p['document_page'] . '-150.svg';
+
+ if (!isset($width)) {
+ $s = CubeIT_Image::getimagesize($f);
+ $width = $s[0];
+ $height = $s[1];
+ }
+
+ $svg .= '<div class="page" id="p' . $item . '">';
+ $svg .= self::_svg(file_get_contents($f), $item);
+ $svg .= '</div>';
+ $css .= '#p' . $item . '{left:' . $left . 'px;}';
+ $left += ($width - 1);
+ }
+ }
+
+ $res = '<html>';
+ $res .= '<head>';
+ $res .= '<meta name="width" value="' . $left . '">';
+ $res .= '<meta name="height" value="' . $height . '">';
+ $res .= '<!-- tweenmax --><script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/2.0.2/TweenMax.min.js"></script><!-- -->';
+ $res .= '<!-- jquery --><script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script><!-- -->';
+ $res .= '<script src="main.js"></script>';
+ $res .= '<style type="text/css">*{padding:0;margin:0}svg{display: block;}.page{position: absolute;top: 0;}.page svg{width:' . $width . 'px;height:' . $height . 'px;}' . $css . '</style></head>';
+ $res .= '<link href="main.css" type="text/css" rel="stylesheet" />';
+ $res .= '<body>';
+ $res .= $svg;
+ $res .= '</body>';
+ $res .= '</html>';
+
+ $n = 'fb_' . $book_id . '_' . $page . '.zip';
+ $zipname = '/tmp/' . $n;
+ $zip = new ZipArchive();
+ $zip->open($zipname, ZipArchive::CREATE);
+ $zip->addFromString('index.html', $res);
+ $zip->close();
+ return ['name' => $n, 'path' => $zipname];
+ }
+
+ protected static function _svg($c, $p)
+ {
+ self::$_i = 0;
+ self::$_e = 0;
+ self::$_u = 0;
+
+ $c = str_replace('id="', 'id="p' . $p . '-', $c);
+ $c = str_replace('url(#', 'url(#p' . $p . '-', $c);
+ $c = str_replace('xlink:href="#', 'xlink:href="#p' . $p . '-', $c);
+ $c = preg_replace_callback('/\<image([^\>]*)\>/m', function ($matches) use ($p) {
+ self::$_i++;
+ return '<g id="p' . $p . '-imageholder-' . self::$_i . '"><image id="p' . $p . '-image-' . self::$_i . '" ' . $matches[1] . '></g>';
+ }, $c);
+ $c = str_replace('</image>', '</image></g></g>', $c);
+
+ $c = preg_replace_callback('/<path /', function () use ($p) {
+ self::$_e++;
+ return '<path id="p' . $p . '-e-' . self::$_e . '" ';
+ }, $c);
+ $c = preg_replace_callback('/<use /', function () use ($p) {
+ self::$_u++;
+ return '<use id="p' . $p . '-u-' . self::$_u . '" ';
+ }, $c);
+
+ return $c;
+ }
+
+
+ public function chiffres()
+ {
+
+ }
+
}