]> _ Git - cubeextranet.git/commitdiff
(no commit message)
authorvincent@cubedesigners.com <vincent@cubedesigners.com@f5622870-0f3c-0410-866d-9cb505b7a8ef>
Tue, 9 Dec 2014 15:24:22 +0000 (15:24 +0000)
committervincent@cubedesigners.com <vincent@cubedesigners.com@f5622870-0f3c-0410-866d-9cb505b7a8ef>
Tue, 9 Dec 2014 15:24:22 +0000 (15:24 +0000)
inc/commons/Metier/class.common.entreprise.php
inc/ws/Controlleur/class.ws.users.tree.php
inc/ws/Metier/class.ws.parametres.php
inc/ws/Util/class.ws.pdf.fontextractor.php [new file with mode: 0644]
inc/ws/Util/class.ws.pdf.fontextractor.php.php [new file with mode: 0644]
inc/ws/Util/packager/class.ws.packager.air.php
inc/ws/Util/packager/class.ws.packager.html5.php [new file with mode: 0644]
inc/ws/Util/packager/html5/class.ws.packager.html5.links.php [new file with mode: 0644]
inc/ws/Util/packager/html5/class.ws.packager.html5.php [new file with mode: 0644]

index bfbb0a2fe0de36d78b605b016dd405c61076a534..c05ba2111bd6670a779ae3c75fe33eabd769049c 100644 (file)
@@ -15,6 +15,7 @@ class commonEntreprise extends cubeMetier {
        protected $ws_admin;\r
        protected $ws_grade;\r
        protected $ws_signatures;\r
+       protected $type;\r
        // Composés\r
        protected $ca;\r
        protected $impaye;\r
index ca377e9545dc554d3eeff7713aaac3c481cca1c1..5754e9b32d92052591d864c5ef99dcc4581353d8 100644 (file)
@@ -64,17 +64,17 @@ class wsUsersTree {
                        $c->facturable_id = $facturable_id;\r
                        $ce->facturable_entreprise_id = $c->facturable_entreprise_id = $this->entreprises[$facturable_id];\r
                        $ce->administrateur_id = $c->administrateur_id = $administrateur_id;\r
-                       try {\r
-                               $c->insert();\r
-                       } catch (Exception $e) {\r
+                       try{\r
+                       $c->insert();\r
+                       }catch(Exception $e){\r
                                fb($e);\r
                        }\r
                        if (isset($evu[$c->entreprise_id])) {\r
                                continue;\r
                        }\r
-                       try {\r
-                               $ce->insert();\r
-                       } catch (Exception $e) {\r
+                       try{\r
+                       $ce->insert();\r
+                       }catch(Exception $e){\r
                                fb($e);\r
                        }\r
                        $evu[$c->entreprise_id] = true;\r
index 5fc7591bcc64ca85272582396681dc6a775ae0af..9ac085d1c3038156cdb0544f4bace4a57ab8fde7 100644 (file)
@@ -107,8 +107,10 @@ class wsParametres extends cubeMetier implements Iterator {
                                $value = cubeMath::fill(ltrim($value, '#'), 6);\r
                                break;\r
                        case 'couleurAlpha':\r
+                               fb($value);\r
                                $value = cubeMath::fill(ltrim($value, '#'), 6);\r
-                               $value = cubeMath::fill($value, 8, 'f');\r
+                               $value = cubeMath::fill($value,8,'f');\r
+                               fb($value);\r
                                break;\r
                        case 'date':\r
                                if (!is_int($value)) {\r
diff --git a/inc/ws/Util/class.ws.pdf.fontextractor.php b/inc/ws/Util/class.ws.pdf.fontextractor.php
new file mode 100644 (file)
index 0000000..bc76aed
--- /dev/null
@@ -0,0 +1,470 @@
+<?php
+
+class wsPDFFontExtractor {
+
+       protected $in;
+       protected $outpdf;
+       protected $outweb;
+       protected $fonts = array();
+       protected $cmaps = array();
+       protected $descendants = array();
+       protected $descendantNames = array();
+       protected $doc;
+
+       public function __construct($in, $doc=null) {
+               $this->doc = $doc;
+               $this->in = $in . '/original.pdf';
+               $this->outpdf = $in . '/fonts/pdf';
+               $this->outweb = $in . '/fonts/web';
+       }
+
+       public function extract() {
+               $this->clean();
+
+               $this->getFonts();
+               $this->getFontsDescriptors();
+               $this->extractFonts();
+               $this->extractCmaps();
+               $this->convertToTTF();
+       }
+
+       public function convertToTTF() {
+
+
+
+               $dr = opendir($this->outpdf);
+               while ($file = readdir($dr)) {
+                       if ($file == '.' || $file == '..' || files::getExtension($file) == 'cmap') {
+                               continue;
+                       }
+
+                       $e = explode('.', $file);
+                       array_pop($e);
+                       $fname = implode('.', $e);
+
+                       $e = explode('-', $fname);
+                       array_pop($e);
+                       $fname = implode('-', $e);
+
+                       if (!isset($collections[$fname])) {
+                               $collections[$fname] = array();
+                       }
+                       $collections[$fname][] = $file;
+               }
+
+               foreach ($collections as $fontname => $files) {
+                       $descendant = array_keys($this->descendantNames, $fontname);
+                       if (count($descendant)) {
+                               $f = array_keys($this->descendants, $descendant[0]);
+                               $fontname = $f[0];
+                       }
+
+
+                       $fontforge = new cubeCommandLine('convert.pe');
+                       $fontforge->setPath(CONVERTER_PATH);
+                       foreach ($files as $file) {
+                               $fontforge->setArg(null, $this->outpdf . '/' . $file);
+                       }
+                       $cmapFile = $this->outpdf . '/' . $fontname . '.cmap';
+                       if (!file_exists($cmapFile)) {
+                               $fontforge->setArg(null, '-');
+                       } else {
+                               $fontforge->setArg(null, $cmapFile);
+                       }
+                       $fontforge->setArg(null, $this->outweb . '/' . $fontname . '.ttf');
+                       $fontforge->execute();
+                       $this->addToLog($fontforge);
+               }
+       }
+
+       public function getFonts() {
+               $pdfinfo = $this->getCommandLine('pdfinfo');
+               $pdfinfo->setArg('f');
+               $pdfinfo->setArg(null, $this->in);
+               $pdfinfo->execute();
+
+               $this->addToLog($pdfinfo);
+
+               /*
+                * /home/extranet/www/fluidbook/docs/100376/original.pdf:
+
+                 PDF-1.7
+                 Info object (9177 0 R):
+                 <<
+                 /CreationDate (D:20110831090005+02'00')
+                 /Creator (Adobe InDesign CS5 \(7.0\))
+                 /ModDate (D:20110901144502+02'00')
+                 /Producer (Adobe PDF Library 9.9)
+                 /Trapped /False
+                 >>
+
+                 Pages: 116
+
+                 Retrieving info from pages 1-116...
+                 Fonts (201):
+                 1 (   9180 0 R): Type1 'QGNYEE+AvantGarde-Book' (9193 0 R)
+                 1 (   9180 0 R): Type1 'QGNYEE+AvantGarde-ExtraLight' (9195 0 R)
+                 2 (      1 0 R): Type1 'QGNYEE+DIN-Light' (7605 0 R)
+                 2 (      1 0 R): Type1 'QGNYEE+AvantGarde-ExtraLightObl' (7608 0 R)
+                 2 (      1 0 R): Type1 'QGNYEE+AvantGarde-MediumObl' (7601 0 R)
+
+                */
+
+               if (preg_match_all("|\s+\d+\s+\(\s+\d+\s+\d+\s+\w+\):\s+\w+\s+'([A-Za-z-+]+)'\s+\((\d+)\s+\d+\s+\w+\)\s|", $pdfinfo->output, $matches)) {
+                       foreach ($matches[1] as $k => $name) {
+                               $this->fonts[$matches[2][$k]] = array('name' => $name);
+                       }
+               }
+       }
+
+       protected function getFontsDescriptors() {
+               $pdfshow = $this->getCommandLine('pdfshow');
+               $pdfshow->setArg(null, $this->in);
+               $pdfshow->setManualArg(implode(' ', array_keys($this->fonts)));
+               $pdfshow->execute();
+               $this->doc->addToLog($pdfshow);
+
+               /*
+                 8677 0 obj
+                 <<
+                 /BaseFont /YIKUMO+Futura-Condensed
+                 /Encoding /WinAnsiEncoding
+                 /FirstChar 32
+                 /FontDescriptor 7690 0 R
+                 /LastChar 119
+                 /Subtype /Type1
+                 /Type /Font
+                 /Widths [ 205 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+                 0 0 0 0 0 0 0 0 0 414 418 0 466 0 342 0 0 0 303 0 0 561 0
+                 0 388 0 0 354 0 0 0 0 0 0 0 0 0 0 0 0 0 380 380 0 380 361
+                 0 382 388 180 0 395 180 590 388 375 380 0 269 276 221 389
+                 0 487 ]
+                 >>
+                 endobj
+
+                 9193 0 obj
+                 <<
+                 /BaseFont /QGNYEE+AvantGarde-Book
+                 /Encoding /WinAnsiEncoding
+                 /FirstChar 32
+                 /FontDescriptor 9192 0 R
+                 /LastChar 201
+                 /Subtype /Type1
+                 /ToUnicode 9185 0 R
+                 /Type /Font
+                 /Widths [ 277 0 0 0 0 0 0 0 0 0 0 0 277 332 0 0 554 554 554
+                 0 0 0 554 554 0 0 0 0 0 0 0 0 0 740 574 813 744 536 485 872
+                 683 226 482 0 462 919 740 869 592 0 607 498 426 655 702 0
+                 0 592 480 0 0 0 0 0 0 683 0 0 0 650 0 0 0 200 0 0 200 0 610
+                 655 0 0 301 388 339 0 554 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1000
+                 0 0 0 0 0 0 0 0 0 0 0 0 351 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+                 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+                 0 740 0 0 0 0 0 0 0 0 536 ]
+                 >>
+                 endobj
+                * 
+                 10 0 obj
+                 <<
+                 /BaseFont /FuturaLT-Bold--Identity-H
+                 /DescendantFonts [ 11 0 R ]
+                 /Encoding /Identity-H
+                 /Name /F0
+                 /Subtype /Type0
+                 /ToUnicode 3881 0 R
+                 /Type /Font
+                 >>
+                 endobj
+
+                */
+
+               $lines = explode("\n", $pdfshow->output);
+               $currentFont = null;
+               foreach ($lines as $line) {
+                       $line = trim($line);
+                       if ($line == '' || $line == '<<' || $line == '>>') {
+                               continue;
+                       }
+                       if ($line == 'endobj') {
+                               $currentFont = null;
+                               continue;
+                       }
+                       $e = explode(' ', $line);
+                       if (count($e) == 3 && $e[2] == 'obj') {
+                               $currentFont = $e[0];
+                               continue;
+                       }
+
+                       if (is_null($currentFont)) {
+                               continue;
+                       }
+
+                       $fontname = $this->fonts[$currentFont]['name'];
+
+                       if ($e[0] == '/ToUnicode') {
+                               $this->fonts[$currentFont]['cmap'] = $e[1];
+                               $this->cmaps[$fontname] = $e[1];
+                       }
+
+                       if ($e[0] == '/DescendantFonts') {
+                               $this->fonts[$currentFont]['descendant'] = $e[1];
+                               $this->descendants[$fontname] = $e[1];
+                       }
+               }
+
+               $this->manageDescendants();
+
+               $this->addToLog(print_r($this->fonts, true));
+       }
+
+       protected function manageDescendants() {
+               if (!count($this->descendants)) {
+                       return;
+               }
+
+               $pdfshow = $this->getCommandLine('pdfshow');
+               $pdfshow->setArg(null, $this->in);
+               $pdfshow->setManualArg(implode(' ', $this->descendants));
+               $pdfshow->execute();
+               $this->doc->addToLog($pdfshow);
+
+               /*
+                 11 0 obj
+                 <<
+                 /BaseFont /EHLOJB+FuturaLT-Bold-OV-JVKOJB
+                 /CIDSystemInfo <<
+                 /Ordering (Identity)
+                 /Registry (Adobe)
+                 /Supplement 0
+                 >>
+                 /DW 343
+                 /FontDescriptor 3878 0 R
+                 /Name /F0
+                 /Subtype /CIDFontType0
+                 /Type /Font
+                 /W [ 1 [ 781 ] 4 [ 781 ] 9 [ 677 660 ] 12 [ 752 550 550 550 ]
+                 17 [ 550 ] 20 [ 542 842 803 324 ] 26 [ 324 ] 28 [ 489 ] 30
+                 [ 495 ] 32 [ 983 881 ] 35 [ 887 ] 43 [ 661 887 680 616 ]
+                 48 [ 533 ] 50 [ 778 ] 55 [ 761 ] 57 [ 789 ] 61 [ 707 ] 63
+                 [ 682 ] 77 [ 682 ] 87 [ 483 ] 93 [ 343 343 ] 97 [ 682 ] 106
+                 [ 610 610 610 ] 111 [ 686 ] 119 [ 388 ] 121 [ 689 ] 124 [
+                 686 ] 126 [ 677 ] 134 [ 661 ] 136 [ 392 ] 138 [ 302 ] 140
+                 [ 302 302 ] 149 [ 989 ] 154 [ 661 ] 156 [ 686 ] 159 [ 662 ]
+                 167 [ 686 ] 175 [ 682 ] 180 [ 343 ] 193 [ 372 ] 196 [ 453 ]
+                 199 [ 513 ] 203 [ 686 686 ] 208 [ 360 ] 210 [ 686 ] 215 [
+                 686 ] 217 [ 659 ] 232 [ 686 ] ]
+                 >>
+                 endobj
+
+                */
+
+               $currentDescendant = null;
+               $lines = explode("\n", $pdfshow->output);
+               foreach ($lines as $line) {
+                       $line = trim($line);
+                       $e = explode(' ', $line);
+                       if (count($e) == 3 && $e[2] == "obj") {
+                               $currentDescendant = $e[0];
+                       }
+                       if ($line == 'endobj') {
+                               $currentDescendant = null;
+                       }
+
+                       if (is_null($currentDescendant)) {
+                               continue;
+                       }
+
+                       if ($e[0] == '/BaseFont') {
+                               $this->descendantNames[$currentDescendant] = trim($e[1], "/");
+                       }
+               }
+
+               $this->addToLog('Descendant names : ' . print_r($this->descendantNames, true));
+       }
+
+       protected function extractFonts() {
+               $descriptors = $this->getUniqueId('descriptor');
+
+               $pdfextract = $this->getCommandLine('pdfextract');
+               $pdfextract->setArg(null, $this->in);
+               $pdfextract->execute();
+               $this->addToLog($pdfextract);
+
+
+               $formats = array('pnm', 'pam', 'pgm', 'jpg', 'gif', 'jpeg', 'png');
+               foreach ($formats as $f) {
+                       `rm $this->outpdf/*.$f`;
+               }
+       }
+
+       protected function extractCmaps() {
+               $cmaps = array_unique($this->cmaps);
+
+               $pdfshow = $this->getCommandLine('pdfshow');
+               $pdfshow->setArg(null, $this->in);
+               $pdfshow->setManualArg(implode(' ', $cmaps));
+               $pdfshow->execute();
+               $this->addToLog($pdfshow);
+
+
+               /* 5266 0 obj
+                 <<
+                 /Filter /FlateDecode
+                 /Length 583
+                 >>
+                 stream
+                 /CIDInit /ProcSet findresource begin
+                 12 dict begin
+                 begincmap
+                 /CIDSystemInfo
+                 << /Registry (Adobe)
+                 /Ordering (UCS) /Supplement 0 >> def
+                 /CMapName /Adobe-Identity-UCS def
+                 /CMapType 2 def
+                 1 begincodespacerange
+                 <0000> <FFFF>
+                 endcodespacerange
+                 81 beginbfchar
+                 <0000> <0020>
+                 <0001> <0021>
+                 <0005> <0025>
+                 <0007> <2019>
+                 <0008> <0028>
+                 <0009> <0029>
+                 <000C> <002C>
+                 <000D> <002D>
+                 <000E> <002E>
+                 <000F> <002F>
+                 endbfchar
+                 endcmap CMapName currentdict /CMap defineresource pop end end
+                 endstream
+                 endobj
+
+                */
+
+               $finalCmaps = array();
+
+               $lines = explode("\n", $pdfshow->output);
+               $currentCmap = null;
+               $inMap = false;
+               foreach ($lines as $line) {
+                       $line = trim($line);
+                       if ($line == '') {
+                               continue;
+                       }
+                       if ($line == 'endobj') {
+                               $currentCmap = null;
+                               continue;
+                       } elseif ($line == 'endbfchar') {
+                               $inMap = false;
+                       }
+
+                       $e = explode(' ', $line);
+                       if (count($e) == 3 && $e[2] == 'obj') {
+                               $currentCmap = $e[0];
+                               continue;
+                       }
+
+                       if (count($e) == 2 && $e[1] == 'beginbfchar') {
+                               $inMap = true;
+                               continue;
+                       }
+
+                       if (!$inMap || is_null($currentCmap)) {
+                               continue;
+                       }
+
+                       $fonts = array_keys($this->cmaps, $currentCmap);
+
+                       $from = trim($e[0], '<>');
+                       $to = trim($e[1], '<>');
+
+                       foreach ($fonts as $fontname) {
+                               if (!isset($finalCmaps[$fontname])) {
+                                       $finalCmaps[$fontname] = array();
+                               }
+
+                               if (strlen($to) >= 8) {
+                                       $toc = $to;
+                                       $to = $this->manageLigatures($to);
+                                       $this->addToLog('Correct ligature ' . $toc . ' -> ' . $to);
+                               }
+
+                               $finalCmaps[$fontname][$from] = $to;
+                       }
+               }
+
+               foreach ($finalCmaps as $fontname => $cmap) {
+                       arsort($cmap);
+                       $data = '';
+                       foreach ($cmap as $from => $to) {
+                               $data.=$from . "\t" . $to . "\n";
+                       }
+
+                       $this->addToLog('Write cmap for font ' . $fontname . ' in ' . $this->outpdf . '/' . $fontname . '.cmap');
+
+                       file_put_contents($this->outpdf . '/' . $fontname . '.cmap', $data);
+               }
+       }
+
+       protected function manageLigatures($code) {
+               $codes = str_split($code, 4);
+               $str = '';
+               foreach ($codes as $c) {
+                       $str.=chr(intval($c, 16));
+               }
+
+               $ligatures = array('AE' => '00C6', 'ae' => '00E6',
+                       'OE' => '0152', 'oe' => '0152',
+                       'IJ' => '0132', 'ij' => '0133',
+                       'ff' => 'fb00',
+                       'fi' => 'fb01',
+                       'fl' => 'fb02',
+                       'ffi' => 'fb03',
+                       'ffl' => 'fb04');
+
+               // Si un couple est une ligature standard
+               if (isset($ligatures[$str])) {
+                       return $ligatures[$str];
+               }
+               // Sinon, on ne retourne que le premier code
+               return $codes[0];
+       }
+
+       protected function getUniqueId($param) {
+               $res = array();
+               foreach ($this->fonts as $f) {
+                       if (isset($f[$param])) {
+                               $res[$id] = $f[$param];
+                       }
+               }
+               return array_unique($res);
+       }
+
+       protected function clean() {
+               `rm -rf $this->outpdf`;
+               `rm -rf $this->outweb`;
+               mkdir($this->outweb, 0777, true);
+               mkdir($this->outpdf, 0777, true);
+       }
+
+       protected function getCommandLine($program) {
+               $res = new cubeCommandLine('/usr/local/mupdf/' . $program);
+               $res->cd($this->outpdf);
+               $res->setPath(CONVERTER_PATH);
+               return $res;
+       }
+
+       protected function addToLog($tolog) {
+               if (!is_null($this->doc)) {
+                       $this->doc->addToLog($tolog);
+               } elseif ($tolog instanceof cubeCommandLine) {
+                       echo $tolog->commande . "\n\n";
+                       echo $tolog->output . "\n\n";
+               } else {
+                       echo $tolog . "\n\n";
+               }
+       }
+
+}
+
+?>
diff --git a/inc/ws/Util/class.ws.pdf.fontextractor.php.php b/inc/ws/Util/class.ws.pdf.fontextractor.php.php
new file mode 100644 (file)
index 0000000..dcb4cfb
--- /dev/null
@@ -0,0 +1,331 @@
+<?php
+
+class wsPDFFontExtractor {
+
+       protected $in;
+       protected $outpdf;
+       protected $outweb;
+       protected $fonts = array();
+       protected $cmaps = array();
+       protected $descriptors = array();
+       protected $doc;
+
+       public function __construct($in, $doc) {
+               $this->doc = $doc;
+               $this->in = $in . '/original.pdf';
+               $this->outpdf = $in . '/fonts/pdf';
+               $this->outweb = $in . '/fonts/web';
+       }
+
+       public function extract() {
+               $this->clean();
+
+               $this->getFonts();
+               $this->getFontsDescriptors();
+               $this->extractFonts();
+               $this->extractCmaps();
+               $this->convertToTTF();
+       }
+
+       public function convertToTTF() {
+
+
+
+               $dr = opendir($this->outpdf);
+               while ($file = readdir($dr)) {
+                       if ($file == '.' || $file == '..' || files::getExtension($file) == 'cmap') {
+                               continue;
+                       }
+
+                       $e = explode('.', $file);
+                       array_pop($e);
+                       $fname = implode('.', $e);
+
+                       $e = explode('-', $fname);
+                       array_pop($e);
+                       $fname = implode('-', $e);
+
+                       if (!isset($collections[$fname])) {
+                               $collections[$fname] = array();
+                       }
+                       $collections[$fname][] = $file;
+               }
+
+               foreach ($collections as $fontname => $files) {
+                       $fontforge = new cubeCommandLine('convert.pe');
+                       $fontforge->setPath(CONVERTER_PATH);
+                       foreach ($files as $file) {
+                               $fontforge->setArg(null, $this->outpdf . '/' . $file);
+                       }
+                       $cmapFile = $this->outpdf . '/' . $fontname . '.cmap';
+                       if (!file_exists()) {
+                               $fontforge->setArg(null, '-');
+                       } else {
+                               $fontforge->setArg(null, $cmapFile);
+                       }
+                       $fontforge->setArg(null, $this->outweb . '/' . $fontname . '.ttf');
+                       $fontforge->execute();
+                       $this->doc->addToLog($fontforge);
+               }
+       }
+
+       public function getFonts() {
+               $pdfinfo = $this->getCommandLine('pdfinfo');
+               $pdfinfo->setArg('f');
+               $pdfinfo->setArg(null, $this->in);
+               $pdfinfo->execute();
+
+               $this->doc->addToLog($pdfinfo);
+
+               /*
+                * /home/extranet/www/fluidbook/docs/100376/original.pdf:
+
+                 PDF-1.7
+                 Info object (9177 0 R):
+                 <<
+                 /CreationDate (D:20110831090005+02'00')
+                 /Creator (Adobe InDesign CS5 \(7.0\))
+                 /ModDate (D:20110901144502+02'00')
+                 /Producer (Adobe PDF Library 9.9)
+                 /Trapped /False
+                 >>
+
+                 Pages: 116
+
+                 Retrieving info from pages 1-116...
+                 Fonts (201):
+                 1 (   9180 0 R): Type1 'QGNYEE+AvantGarde-Book' (9193 0 R)
+                 1 (   9180 0 R): Type1 'QGNYEE+AvantGarde-ExtraLight' (9195 0 R)
+                 2 (      1 0 R): Type1 'QGNYEE+DIN-Light' (7605 0 R)
+                 2 (      1 0 R): Type1 'QGNYEE+AvantGarde-ExtraLightObl' (7608 0 R)
+                 2 (      1 0 R): Type1 'QGNYEE+AvantGarde-MediumObl' (7601 0 R)
+
+                */
+
+               if (preg_match_all("\s+\d+\s+\(\s+\d+\s+\d+\s+\w+\):\s+\w+\s+'([A-Za-z-+]+)'\s+\(\d+\s+\d+\s+\w+\)\s", $pdfinfo->output, $matches)) {
+                       foreach ($matches[1] as $k => $name) {
+                               $this->fonts[$matches[2][$k]] = array('name' => $name);
+                       }
+               }
+       }
+
+       protected function getFontsDescriptors() {
+               $pdfshow = $this->getCommandLine('pdfshow');
+               $pdfshow->setArg(null, $this->in);
+               $pdfshow->setManualArg(implode(' ', array_keys($this->fonts)));
+               $pdfshow->execute();
+               $this->doc->addToLog($pdfshow);
+
+               /*
+                 8677 0 obj
+                 <<
+                 /BaseFont /YIKUMO+Futura-Condensed
+                 /Encoding /WinAnsiEncoding
+                 /FirstChar 32
+                 /FontDescriptor 7690 0 R
+                 /LastChar 119
+                 /Subtype /Type1
+                 /Type /Font
+                 /Widths [ 205 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+                 0 0 0 0 0 0 0 0 0 414 418 0 466 0 342 0 0 0 303 0 0 561 0
+                 0 388 0 0 354 0 0 0 0 0 0 0 0 0 0 0 0 0 380 380 0 380 361
+                 0 382 388 180 0 395 180 590 388 375 380 0 269 276 221 389
+                 0 487 ]
+                 >>
+                 endobj
+
+                 9193 0 obj
+                 <<
+                 /BaseFont /QGNYEE+AvantGarde-Book
+                 /Encoding /WinAnsiEncoding
+                 /FirstChar 32
+                 /FontDescriptor 9192 0 R
+                 /LastChar 201
+                 /Subtype /Type1
+                 /ToUnicode 9185 0 R
+                 /Type /Font
+                 /Widths [ 277 0 0 0 0 0 0 0 0 0 0 0 277 332 0 0 554 554 554
+                 0 0 0 554 554 0 0 0 0 0 0 0 0 0 740 574 813 744 536 485 872
+                 683 226 482 0 462 919 740 869 592 0 607 498 426 655 702 0
+                 0 592 480 0 0 0 0 0 0 683 0 0 0 650 0 0 0 200 0 0 200 0 610
+                 655 0 0 301 388 339 0 554 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1000
+                 0 0 0 0 0 0 0 0 0 0 0 0 351 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+                 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+                 0 740 0 0 0 0 0 0 0 0 536 ]
+                 >>
+                 endobj
+                */
+
+               $lines = explode("\n", $pdfshow->output);
+               $currentFont = null;
+               foreach ($lines as $line) {
+                       $line = trim($line);
+                       if ($line == '' || $line == '<<' || $line == '>>') {
+                               continue;
+                       }
+                       if ($line == 'endobj') {
+                               $currentFont = null;
+                               continue;
+                       }
+                       $e = explode(' ', $line);
+                       if ($e[2] == 'obj') {
+                               $currentFont = $e[0];
+                               continue;
+                       }
+
+                       if (is_null($currentFont)) {
+                               continue;
+                       }
+
+                       $fontname = $this->fonts[$currentFont]['name'];
+
+                       if ($e[0] == '/FontDescriptor') {
+                               $this->fonts[$currentFont]['descriptor'] = $e[1];
+                               if (!isset($this->descriptors[$fontname])) {
+                                       $this->descriptors[$fontname] = array();
+                               }
+                               $this->descriptors[$fontname][] = $e[1];
+                       } else if ($e[0] == 'ToUnicode') {
+                               $this->fonts[$currentFont]['cmap'] = $e[1];
+                               $this->cmaps[$fontname] = $e[1];
+                       }
+               }
+       }
+
+       protected function extractFonts() {
+               $descriptors = $this->getUniqueId('descriptor');
+
+               $pdfextract = $this->getCommandLine('pdfextract');
+               $pdfextract->setArg(null, $this->in);
+               $pdfextract->setManualArg(implode(' ', $descriptors));
+               $pdfextract->execute();
+               $this->doc->addToLog($pdfextract);
+       }
+
+       protected function extractCmaps() {
+               $cmaps = array_unique($this->cmaps);
+
+               $pdfshow = $this->getCommandLine('pdfshow');
+               $pdfshow->setArg(null, $this->in);
+               $pdfshow->setManualArg(implode(' ', $cmaps));
+               $pdfshow->execute();
+               $this->doc->addToLog($pdfshow);
+
+
+               /* 5266 0 obj
+                 <<
+                 /Filter /FlateDecode
+                 /Length 583
+                 >>
+                 stream
+                 /CIDInit /ProcSet findresource begin
+                 12 dict begin
+                 begincmap
+                 /CIDSystemInfo
+                 << /Registry (Adobe)
+                 /Ordering (UCS) /Supplement 0 >> def
+                 /CMapName /Adobe-Identity-UCS def
+                 /CMapType 2 def
+                 1 begincodespacerange
+                 <0000> <FFFF>
+                 endcodespacerange
+                 81 beginbfchar
+                 <0000> <0020>
+                 <0001> <0021>
+                 <0005> <0025>
+                 <0007> <2019>
+                 <0008> <0028>
+                 <0009> <0029>
+                 <000C> <002C>
+                 <000D> <002D>
+                 <000E> <002E>
+                 <000F> <002F>
+                 endbfchar
+                 endcmap CMapName currentdict /CMap defineresource pop end end
+                 endstream
+                 endobj
+
+                */
+
+               $finalCmaps = array();
+
+               $lines = explode("\n", $pdfshow->output);
+               $currentCmap = null;
+               $inMap = false;
+               foreach ($lines as $line) {
+                       $line = trim($line);
+                       if ($line == '') {
+                               continue;
+                       }
+                       if ($line == 'endobj') {
+                               $currentCmap = null;
+                               continue;
+                       } elseif ($line == 'endbfchar') {
+                               $inMap = false;
+                       }
+
+                       $e = explode(' ', $line);
+                       if ($e[2] == 'obj') {
+                               $currentCmap = $e[0];
+                               continue;
+                       }
+
+                       if ($e[1] == 'beginbfchar') {
+                               $inMap = true;
+                               continue;
+                       }
+
+                       if (!$inMap || is_null($currentCmap)) {
+                               continue;
+                       }
+
+                       $fonts = array_keys($this->cmaps, $currentCmap);
+
+                       $from = trim($e[0], '<>');
+                       $to = trim($e[1], '<>');
+
+                       foreach ($fonts as $fontname) {
+                               if (!isset($finalCmaps[$fontname])) {
+                                       $finalCmaps[$fontname] = array();
+                               }
+
+                               $finalCmaps[$fontname][$from] = $to;
+                       }
+               }
+
+               foreach ($finalCmaps as $fontname => $cmap) {
+                       arsort($cmap);
+                       $data = '';
+                       foreach ($cmap as $from => $to) {
+                               $data.=$from . "\t" . $to . "\n";
+                       }
+                       file_put_contents($this->outpdf . '/' . $fontname . '.cmap', $data);
+               }
+       }
+
+       protected function getUniqueId($param) {
+               $res = array();
+               foreach ($this->fonts as $f) {
+                       if (isset($f[$param])) {
+                               $res[$id] = $f[$param];
+                       }
+               }
+               return array_unique($res);
+       }
+
+       protected function clean() {
+               `rm -rf $this->outpdf`;
+               `rm -rf $this->outweb`;
+               mkdir($this->outweb, 0777, true);
+       }
+
+       protected function getCommandLine($program) {
+               $res = new cubeCommandLine('/usr/local/mupdf/' . $program);
+               $res->cd($this->outpdf);
+               $res->setPath(CONVERTER_PATH);
+               return $res;
+       }
+
+}
+
+?>
index 21fec508ba6e397a0c176a7291e3fa019af79e0a..f0d64a8eae1eda9e4e645c94032ad558e0636a94 100644 (file)
@@ -1,7 +1,16 @@
 <?php
 
-class wsPackagerAIR extends wsPackager {
-       
-}
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
 
+/**
+ * Description of class
+ *
+ * @author Cube
+ */
+class class {
+//put your code here
+}
 ?>
diff --git a/inc/ws/Util/packager/class.ws.packager.html5.php b/inc/ws/Util/packager/class.ws.packager.html5.php
new file mode 100644 (file)
index 0000000..3defc0a
--- /dev/null
@@ -0,0 +1,578 @@
+<?php\r
+\r
+class wsPackagerHTML5 extends wsPackager {\r
+\r
+       protected $layouts = array();\r
+       protected $cssSize = array();\r
+       protected $cssColor = array();\r
+       protected $cssOpacity = array();\r
+       protected $cssFont = array();\r
+       protected $cssWordSpacing = array();\r
+       protected $cssLetterSpacing = array();\r
+       protected $cssRotation = array();\r
+       protected $cssX = array();\r
+       protected $cssY = array();\r
+       protected $pdf2htmlRatio;\r
+       protected $scale;\r
+       protected $multiply;\r
+       protected $div = array();\r
+       protected static $resolutions = array(36, 72, 150);\r
+       protected static $uaPrefixes = array('-moz-', '-webkit-', '-o-', '-ms-', '');\r
+\r
+       public function __construct($book_id) {\r
+               parent::__construct($book_id);\r
+               $this->version = 'html5';\r
+       }\r
+\r
+       protected function preparePackage() {\r
+               parent::preparePackage();\r
+\r
+               foreach ($this->pages as $page => $infos) {\r
+                       $file = WS_DOCS . '/' . $infos['document_id'] . '/html/p' . $infos['document_page'] . '.layout';\r
+                       if (file_exists($file)) {\r
+                               $this->layouts[$page] = simplexml_load_file($file, null, LIBXML_ERR_WARNING);\r
+                       }\r
+               }\r
+\r
+               $imagesize = getimagesize(WS_DOCS . '/' . $this->pages[1]['document_id'] . '/html/h72-' . $this->pages[1]['document_page'] . '.jpg');\r
+               $this->pdf2htmlRatio = $imagesize[0] / $this->layouts[1]['width'];\r
+               $this->scale = 4;\r
+               $this->multiply = $this->pdf2htmlRatio * $this->scale;\r
+\r
+               $this->createHTML();\r
+       }\r
+\r
+       public function makePackage() {\r
+               parent::makePackage();\r
+               return $this->zip();\r
+       }\r
+\r
+       protected function createHTML() {\r
+               foreach ($this->layouts as $page => $layout) {\r
+                       $this->div[$page] = array();\r
+                       $document_id = $this->pages[$page]['document_id'];\r
+                       foreach ($layout->l as $line) {\r
+                               $this->div[$page][] = $this->addLine($line, $document_id);\r
+                       }\r
+               }\r
+               mkdir($this->vdir . '/data/images', 0777, true);\r
+               mkdir($this->vdir . '/data/contents', 0777, true);\r
+               mkdir($this->vdir . '/data/background', 0777, true);\r
+               mkdir($this->vdir . '/data/style', 0777, true);\r
+\r
+               foreach ($this->div as $n => $page) {\r
+                       file_put_contents($this->vdir . '/data/contents/p' . $n . '.html', $this->writePage($page));\r
+               }\r
+               $this->writeFonts();\r
+               $this->writeImages();\r
+               $this->writeLinks();\r
+               $this->writeCSS($this->vdir . '/data/style/style_%d.css');\r
+\r
+               file_put_contents($this->vdir . '/data/datas.js', $this->writeConfig());\r
+       }\r
+\r
+       protected function writeLinks() {\r
+               global $core;\r
+               $daoDoc = new wsDAODocument($core->con);\r
+               $daoDoc->getLinksAndRulers($this->book_id, $links, $rulers);\r
+\r
+               foreach ($links as $link) {\r
+                       fb($link);\r
+               }\r
+       }\r
+\r
+       protected function writeConfig() {\r
+               $config = cubeObject::merge($this->book->parametres->toStandardObject(), $this->theme->parametres->toStandardObject());\r
+               $config->id = $this->book->book_id;\r
+               return 'DATAS=' . json_encode($config) . ';';\r
+       }\r
+\r
+       protected function writeFonts() {\r
+               $fext = array('ttf', 'eot', 'svg', 'svgz', 'woff');\r
+               foreach ($this->cssFont as $font => $index) {\r
+                       list($font, $document_id) = explode('//', $font);\r
+                       foreach ($fext as $ext) {\r
+                               copy(WS_DOCS . '/' . $document_id . "/fonts/web/" . $font . '.' . $ext, $this->vdir . '/data/style/F' . $index . '.' . $ext);\r
+                       }\r
+               }\r
+       }\r
+\r
+       protected function writeIcons() {\r
+               $res = array();\r
+               // Get the colors used to colorize graphics\r
+               if ($this->theme->parametres->colorizeIcons) {\r
+                       $couleurI = '#' . $this->theme->parametres->couleurI;\r
+               } else {\r
+                       $couleurI = '#FFFFFF';\r
+               }\r
+               $arrowsColor = '#' . $this->theme->parametres->arrowsColor;\r
+               // Set the icon list with the color\r
+               $icons = array('nav-bookmark' => $couleurI, 'nav-friend' => $couleurI, 'nav-help' => $couleurI, 'nav-index' => $couleurI, 'nav-sommaire' => $couleurI,\r
+                       'next' => $arrowsColor, 'previous' => $arrowsColor, 'search' => $couleurI);\r
+\r
+               foreach ($icons as $icon => $color) {\r
+                       wsTools::colorizeAndRasterizeIcon($this->theme->parametres->iconSet, $icon, $color, $this->vdir . '/data/images/',4, $w, $h);\r
+                       $res[] = '#icon-' . $icon . '{width:' . $w . 'px;height:' . $h . 'px;background-image:url(data/images/' . $icon . '.svg), url(data/images/' . $icon . '.png);background-repeat:no-repeat;background-size:' . $w . 'px ' . $h . 'px}';\r
+               }\r
+               return $res;\r
+       }\r
+\r
+       protected function writeImages() {\r
+\r
+               foreach (self::$resolutions as $r) {\r
+                       mkdir($this->vdir . '/data/background/' . $r, 0777);\r
+               }\r
+               foreach ($this->pages as $page => $infos) {\r
+                       foreach (self::$resolutions as $r) {\r
+                               copy(WS_DOCS . '/' . $infos['document_id'] . '/html/h' . $r . '-' . $infos['document_page'] . '.jpg', $this->vdir . '/data/background/' . $r . '/p' . $page . '.jpg');\r
+                       }\r
+               }\r
+       }\r
+\r
+       protected function writePage($page) {\r
+               $res = '';\r
+               foreach ($page as $line) {\r
+                       $res .= $this->writeLine($line);\r
+               }\r
+               return $res;\r
+       }\r
+\r
+       protected function writeLine($line) {\r
+               $line['x'] = $this->getCSSX($line['x'] * $this->multiply);\r
+               $line['y'] = $this->getCSSY($line['y'] * $this->multiply);\r
+\r
+               $class = array('l');\r
+               if (!is_null($line['rotation'])) {\r
+                       $class[] = 'r' . $line['rotation'];\r
+               }\r
+               if (!is_null($line['x'])) {\r
+                       $class[] = 'x' . $line['x'];\r
+               }\r
+               if (!is_null($line['y'])) {\r
+                       $class[] = 'y' . $line['y'];\r
+               }\r
+               $class = implode(' ', $class);\r
+\r
+\r
+               $res = '<div class="' . $class . '">';\r
+               foreach ($line['groups'] as $group) {\r
+                       $res.=$this->writeGroup($group);\r
+               }\r
+               $res.='</div>';\r
+               return $res;\r
+       }\r
+\r
+       protected function writeGroup($group) {\r
+               if ($group === false) {\r
+                       return '';\r
+               }\r
+\r
+               $group['y'] = $this->getCSSY($group['y'] * $this->multiply);\r
+               $group['x'] = $this->getCSSX($group['x'] * $this->multiply);\r
+\r
+               $class = array('g');\r
+               if (!is_null($group['color'])) {\r
+                       $class[] = 'c' . $group['color'];\r
+               }\r
+               if (!is_null($group['size'])) {\r
+                       $class[] = 's' . $group['size'];\r
+               }\r
+               if (!is_null($group['font'])) {\r
+                       $class[] = 'f' . $group['font'];\r
+               }\r
+               if (!is_null($group['x'])) {\r
+                       $class[] = 'x' . $group['x'];\r
+               }\r
+               if (!is_null($group['y'])) {\r
+                       $class[] = 'y' . $group['y'];\r
+               }\r
+               if (!is_null($group['letterspacing'])) {\r
+                       $class[] = 'l' . $group['letterspacing'];\r
+               }\r
+               if (!is_null($group['wordspacing'])) {\r
+                       $class[] = 'w' . $group['wordspacing'];\r
+               }\r
+               $class = implode(' ', $class);\r
+\r
+               $res = '<div class="' . $class . '">';\r
+               foreach ($group['spans'] as $span) {\r
+                       $res.=$this->writeSpan($span);\r
+               }\r
+               $res.='</div>';\r
+               return $res;\r
+       }\r
+\r
+       protected function writeSpan($span) {\r
+               if ($span === false) {\r
+                       return '';\r
+               }\r
+\r
+               return self::escapeHTML($span['text']);\r
+       }\r
+\r
+       protected function writeCSS($file) {\r
+               $res = array();\r
+\r
+               // General theme\r
+               $h = $this->book->parametres->height . 'px';\r
+               $w2 = ($this->book->parametres->width * 2) . 'px';\r
+               $w = $this->book->parametres->width . 'px';\r
+               $wm = ($this->book->parametres->width * $this->multiply) . 'px';\r
+               $hm = ($this->book->parametres->height * $this->multiply) . 'px';\r
+\r
+\r
+               $navTop = ($this->book->parametres->height - 40 - 100) / 2;\r
+               $res[] = '.portrait #pages,.portrait .doublePage.page,.page,.portrait #shadow,#shadow.single{width:' . $w . ';max-width:' . $w . ';height:' . $h . ';max-height:' . $h . '}';\r
+               $res[] = '.background{' . $this->writeCSSUA('transform-origin', 'top left') . ';}';\r
+               foreach (self::$resolutions as $r) {\r
+                       $ratio = 72 / $r;\r
+                       $wr = $this->book->parametres->width / $ratio;\r
+                       $hr = $this->book->parametres->height / $ratio;\r
+\r
+                       $br = '.background.r' . $r . '{';\r
+                       if ($ratio != 1) {\r
+                               $br.=$this->writeCSSUA('transform', 'scale(' . $ratio . ')') . ';';\r
+                       }\r
+                       $br.='width:' . $wr . 'px;height:' . $hr . 'px;}';\r
+                       $res[] = $br;\r
+               }\r
+               $res[] = '.doublePage,#pages,.landscape #shadow.double{width:' . $w2 . ';max-width:' . $w2 . ';height:' . $h . ';max-height:' . $h . '}';\r
+               $res[] = '.landscape #shadow.single.right{left: ' . $w . ';}';\r
+               $res[] = '.landscape .page.right{left:' . $w . '}';\r
+               $texts = '.texts{' . $this->writeCSSUA('transform-origin', 'top left') . ';';\r
+               $texts.=$this->writeCSSUA('transform', 'scale(' . (1 / $this->multiply) . ')') . ';';\r
+               $texts.='width:' . $wm . '; max-width:' . $wm . ';';\r
+               $texts.='height:' . $hm . '; max-height:' . $hm . ';';\r
+               $texts.='}';\r
+               $res[] = $texts;\r
+\r
+               // Theme\r
+               // Background\r
+               $body = '#main{';\r
+               $body.='background-color:#' . $this->theme->parametres->backgroundColor . ';';\r
+               switch ($this->theme->parametres->repeat) {\r
+                       case wsTheme::REPEAT:\r
+                               $body.='background-repeat:repeat;';\r
+                               break;\r
+                       case wsTheme::NONE:\r
+                               $body.='background-repeat:no-repeat;';\r
+                               break;\r
+                       case wsTheme::RATIO:\r
+                               $body.='background-repeat:no-repeat;';\r
+                               break;\r
+                       case wsTheme::STRETCH:\r
+                               $body.='background-repeat:no-repeat;';\r
+                               $body.='background-size:100% 100%;';\r
+                               break;\r
+               }\r
+               if ($this->theme->parametres->backgroundImage != '') {\r
+                       copy($this->themeRoot . '/' . $this->theme->parametres->backgroundImage, $this->vdir . '/data/images/' . $this->theme->parametres->backgroundImage);\r
+                       $body.='background-image:url(../images/' . $this->theme->parametres->backgroundImage . ');';\r
+                       $body.='background-position:';\r
+\r
+\r
+                       switch ($this->theme->parametres->backgroundVAlign) {\r
+                               case wsTheme::TOP:\r
+                                       $body.='top';\r
+                                       break;\r
+                               case wsTheme::MIDDLE:\r
+                                       $body.='center';\r
+                                       break;\r
+                               case wsTheme::BOTTOM:\r
+                                       $body.='bottom';\r
+                                       break;\r
+                       }\r
+                       $body.=' ';\r
+                       switch ($this->theme->parametres->backgroundHAlign) {\r
+                               case wsTheme::LEFT:\r
+                                       $body.='left';\r
+                                       break;\r
+                               case wsTheme::CENTER:\r
+                                       $body.='center';\r
+                                       break;\r
+                               case wsTheme::RIGHT:\r
+                                       $body.='right';\r
+                                       break;\r
+                       }\r
+                       $body.=';';\r
+               }\r
+\r
+               $body.='}';\r
+               $res[] = $body;\r
+\r
+               // Header\r
+               $header = '#header{';\r
+               $header.='height:' . $this->theme->parametres->menuHeight . 'px;';\r
+               $header.='background-color:' . self::colorToCSS($this->theme->parametres->menuColor) . ';';\r
+               if ($this->theme->parametres->menuImage != '') {\r
+                       copy($this->themeRoot . '/' . $this->theme->parametres->menuImage, $this->vdir . '/data/images/' . $this->theme->parametres->menuImage);\r
+                       $header.='background-image:url(../images/' . $this->theme->parametres->menuImage . ');';\r
+                       $header.='background-repeat:no-repeat;';\r
+                       $header.='background-size:100% ' . $this->theme->parametres->menuHeight . 'px;';\r
+               }\r
+               $header.='}';\r
+               $res[] = $header;\r
+\r
+               //Icons\r
+               $res = array_merge($res, $this->writeIcons());\r
+\r
+               // Logo\r
+               $logo = '#logo{';\r
+               if ($this->theme->parametres->logo) {\r
+                       copy($this->themeRoot . '/' . $this->theme->parametres->logo, $this->vdir . '/data/images/' . $this->theme->parametres->logo);\r
+                       $dim = getimagesize($this->vdir . '/data/images/' . $this->theme->parametres->logo);\r
+                       $logo.='background-image:url(../images/' . $this->theme->parametres->logo . ');width:' . $dim[0] . 'px;height:' . $dim[1] . 'px;';\r
+               }\r
+               $logo.='}';\r
+               $res[] = $logo;\r
+\r
+               // Credits\r
+               $res[] = '#credits,#credits a{color:' . self::colorToCSS($this->theme->parametres->creditsColor) . ';}';\r
+\r
+               // Arrows\r
+               $res[] = '#next,#previous{background-color:' . self::colorToCSS($this->theme->parametres->couleurA) . ';}';\r
+               // Book shadow\r
+               $shadowColor = self::colorToCSS($this->theme->parametres->bookShadeColor);\r
+               if ($shadowColor != 'transparent') {\r
+                       $res[] = '#shadow{' . $this->writeCSSUA('box-shadow', '0 0 20px ' . $shadowColor) . '}';\r
+               }\r
+\r
+               // Pages styles\r
+               foreach ($this->cssColor as $color => $index) {\r
+                       $res[] = '.c' . $index . '{color:#' . $color . '}';\r
+               }\r
+\r
+               foreach ($this->cssSize as $size => $index) {\r
+                       $res[] = '.s' . $index . '{font-size:' . $size . 'px}';\r
+               }\r
+\r
+               foreach ($this->cssLetterSpacing as $letterspacing => $index) {\r
+                       $res[] = '.l' . $index . '{letter-spacing:' . $letterspacing . 'em}';\r
+               }\r
+\r
+               foreach ($this->cssWordSpacing as $wordspacing => $index) {\r
+                       $res[] = '.w' . $index . '{word-spacing:' . $wordspacing . 'em}';\r
+               }\r
+\r
+               foreach ($this->cssX as $x => $index) {\r
+                       $res[] = '.x' . $index . '{left:' . $x . 'px}';\r
+               }\r
+\r
+               foreach ($this->cssY as $y => $index) {\r
+                       $res[] = '.y' . $index . '{top:' . $y . 'px}';\r
+               }\r
+\r
+               foreach ($this->cssRotation as $rotation => $index) {\r
+                       $rotation*= - 1;\r
+\r
+\r
+                       $to = 'transform-origin:left top;';\r
+\r
+                       $css = '.r' . $index . '{';\r
+                       $css.=self::writeCSSUA('transform', 'rotate(' . $rotation . 'deg)') . ';';\r
+                       $css.=self::writeCSSUA('transform-origin', 'left top');\r
+                       $css.='}';\r
+                       $res[] = $css;\r
+               }\r
+\r
+               foreach ($this->cssFont as $font => $index) {\r
+                       list($font, $document_id) = explode('//', $font);\r
+                       $res[] = "@font-face{font-family:F" . $index . ";src:url('F" . $index . ".eot');src:url('F" . $index . ".eot?#iefix') format('eot'),url('F" . $index . ".ttf') format('truetype'),url('F" . $index . ".svgz#" . $font . "') format('svgz'),url('F" . $index . ".svg#" . $font . "') format('svg')}";\r
+                       $res[] = '.f' . $index . '{font-family:F' . $index . ',Arial,Helvetica}';\r
+               }\r
+\r
+               $res = array_chunk($res, 4000);\r
+               foreach ($res as $k => $css) {\r
+                       file_put_contents(sprintf($file, $k), implode("\n", $css));\r
+               }\r
+       }\r
+\r
+       protected function writeCSSUA($property, $value) {\r
+               $res = array();\r
+               foreach (self::$uaPrefixes as $prefix) {\r
+                       $res[] = $prefix . $property . ':' . $value;\r
+               }\r
+               return implode(';', $res);\r
+       }\r
+\r
+       protected function addLine($line, $document_id) {\r
+               $res = array();\r
+               foreach ($line->a as $group) {\r
+                       $res[] = $this->addGroup($group, $document_id);\r
+               }\r
+               return array('x' => $this->normalizeFloatValue($line['x']),\r
+                       'y' => $this->normalizeFloatValue($line['y']),\r
+                       'rotation' => $this->getCSSRotation($this->normalizeFloatValue($line['rotation'], 0)),\r
+                       "groups" => $res);\r
+       }\r
+\r
+       protected function addGroup($group, $document_id) {\r
+               $alpha = intval(substr($group['color'], 1, 2), 16);\r
+               if ($alpha == 0) {\r
+                       return false;\r
+               }\r
+\r
+               $res = array();\r
+\r
+               $first = true;\r
+               foreach ($group->s as $span) {\r
+                       if ($first) {\r
+                               $x = $span['x'];\r
+                               $first = false;\r
+                       }\r
+                       $newSpan = $this->addSpan($span, $document_id);\r
+\r
+                       array_push($res, $newSpan);\r
+               }\r
+\r
+               return array(\r
+                       'color' => $this->getCSSColor($group['color']),\r
+                       'size' => $this->getCSSSize($group['size']),\r
+                       'font' => $this->getCSSFont($group['font'], $document_id),\r
+                       'letterspacing' => $this->getCSSLetterSpacing($group['letterspacing']),\r
+                       'wordspacing' => $this->getCSSWordSpacing($group['wordspacing']),\r
+                       'y' => ($group['size']) / -1.2,\r
+                       'x' => $x,\r
+                       'spans' => $res);\r
+       }\r
+\r
+       protected function addSpan($span, $document_id) {\r
+\r
+               $text = (string) $span;\r
+               if ($text == '') {\r
+                       return false;\r
+               }\r
+               return array('text' => $text);\r
+       }\r
+\r
+       protected function getCSSSize(&$size) {\r
+               $size = $this->normalizeFloatValue($size * $this->multiply, 3);\r
+               $sizer = $size;\r
+               return $this->getIndex($sizer, $this->cssSize);\r
+       }\r
+\r
+       protected function getCSSFont($font, $document_id) {\r
+               return $this->getIndex($font . "//" . $document_id, $this->cssFont);\r
+       }\r
+\r
+       protected function getCSSColor($color) {\r
+               $color = trim($color, '#');\r
+               if (strlen($color) > 6) {\r
+                       $color = substr($color, 2, 6);\r
+               }\r
+               if ($color == '000000') {\r
+                       return null;\r
+               }\r
+               return $this->getIndex($color, $this->cssColor);\r
+       }\r
+\r
+       protected function getCSSLetterSpacing($letterspacing) {\r
+\r
+               $letterspacing = $this->normalizeFloatValue($letterspacing, 5);\r
+\r
+               if ($letterspacing == 0) {\r
+                       return null;\r
+               }\r
+               return $this->getIndex($letterspacing, $this->cssLetterSpacing);\r
+       }\r
+\r
+       protected function getCSSWordSpacing($wordspacing) {\r
+               $wordspacing = $this->normalizeFloatValue($wordspacing, 5);\r
+\r
+               if ($wordspacing == 0) {\r
+                       return null;\r
+               }\r
+               return $this->getIndex($wordspacing, $this->cssWordSpacing);\r
+       }\r
+\r
+       protected function getCSSRotation($rotation) {\r
+               $rotation = $this->normalizeFloatValue($rotation, 0);\r
+               if ($rotation == 0) {\r
+                       return null;\r
+               }\r
+               return $this->getIndex($rotation, $this->cssRotation);\r
+       }\r
+\r
+       protected function getCSSX($x) {\r
+               $x = round($x);\r
+               if ($x == 0) {\r
+                       return null;\r
+               }\r
+               return $this->getIndex($x, $this->cssX);\r
+       }\r
+\r
+       protected function getCSSY($y) {\r
+               $y = round($y);\r
+               if ($y == 0) {\r
+                       return null;\r
+               }\r
+               return $this->getIndex($y, $this->cssY);\r
+       }\r
+\r
+       protected function getIndex($value, &$tab) {\r
+               $value = (string) $value;\r
+               if (isset($tab[$value])) {\r
+                       return $tab[$value];\r
+               }\r
+               $res = $this->base62(count($tab));\r
+               $tab[$value] = $res;\r
+               return $res;\r
+       }\r
+\r
+       protected function normalizeFloatValue($value, $round=3) {\r
+               $value = str_replace(',', '.', $value);\r
+               $value = (float) $value;\r
+               $value = round($value, $round);\r
+               return $value;\r
+       }\r
+\r
+       protected function base62($val) {\r
+               $chars = '0123456789abcdefghijklmnopqrstuvwxyz';\r
+               $base = strlen($chars);\r
+               $str = '';\r
+               do {\r
+                       $i = $val % $base;\r
+                       $str = $chars[$i] . $str;\r
+                       $val = ($val - $i) / $base;\r
+               } while ($val > 0);\r
+               return $str;\r
+       }\r
+\r
+       public static function escapeHTML($in) {\r
+               $in = htmlentities($in, ENT_NOQUOTES, "UTF-8");\r
+               $in = str_replace('&thinsp;', '', $in);\r
+\r
+               return $in;\r
+       }\r
+\r
+       public function __destruct() {\r
+               \r
+       }\r
+\r
+       public static function colorToCSS($color) {\r
+               if (strlen($color) == 6) {\r
+                       return '#' . $color;\r
+               } else {\r
+                       $alpha = substr($color, 0, 2);\r
+                       $red = substr($color, 2, 2);\r
+                       $green = substr($color, 4, 2);\r
+                       $blue = substr($color, 6, 2);\r
+\r
+                       $components = array('alpha', 'red', 'green', 'blue');\r
+                       foreach ($components as $k => $name) {\r
+                               $hex = substr($color, $k * 2, 2);\r
+                               $$name = intval($hex, 16);\r
+                       }\r
+                       $alpha/=255;\r
+                       if ($alpha == 0) {\r
+                               return 'transparent';\r
+                       } elseif ($alpha == 1) {\r
+                               return '#' . substr($color, 2, 6);\r
+                       }\r
+                       return 'rgba(' . $red . ',' . $green . ',' . $blue . ',' . $alpha . ')';\r
+               }\r
+       }\r
+\r
+}\r
+\r
+?>
\ No newline at end of file
diff --git a/inc/ws/Util/packager/html5/class.ws.packager.html5.links.php b/inc/ws/Util/packager/html5/class.ws.packager.html5.links.php
new file mode 100644 (file)
index 0000000..e47b0f4
--- /dev/null
@@ -0,0 +1,334 @@
+<?php
+
+class wsPackagerHTML5Link {
+
+       public $left;
+       public $top;
+       public $width;
+       public $height;
+       public $page;
+       public $type;
+       public $to;
+       public $numerotation;
+       public $target;
+       public $interactive;
+       public $video_loop;
+       public $video_sound_on;
+       public $video_controls;
+       public $video_auto_start;
+       public $video_height;
+       public $video_width;
+       public $video_service;
+       public $inline;
+       public $display_area;
+       public $infobulle;
+       public $id;
+       public $packager;
+
+       public static function getInstance($id, $init, &$packager) {
+               switch ($init['type']) {
+                       case 1:
+                       case 2:
+                               return new webLink($id, $init, $packager);
+                       case 3:
+                               return new mailLink($id, $init, $packager);
+                       case 5:
+                               return new internalLink($id, $init, $packager);
+                       case 4:
+                               if ($init['inline']) {
+                                       return new videoLink($id, $init, $packager);
+                               } else {
+                                       return new videoPopupLink($id, $init, $packager);
+                               }
+                       case 6:
+                               return new multimediaLink($id, $init, $packager);
+                       case 7:
+                       case 8:
+                       case 9:
+                               return null;
+                       case 10:
+                               if ($init['inline']) {
+                                       return new webVideoLink($id, $init, $packager);
+                               } else {
+                                       return new webVideoPopupLink($id, $init, $packager);
+                               }
+                       case 11:
+                               return new actionLink($id, $init, $packager);
+                       case 12:
+                               return new basketLink($id, $init, $packager);
+                       case 13:
+                               return null;
+                       case 14:
+                               return new colorLink($id, $init, $packager);
+                       case 15:
+                               return new imageLink($id, $init, $packager);
+                       case 16:
+                               return new fileLink($id, $init, $packager);
+                       default:
+                               return null;
+               }
+       }
+
+       public function __construct($id, $init, &$packager) {
+               foreach ($init as $k => $v) {
+                       $this->$k = $v;
+               }
+               $this->id = $id;
+               $this->packager = $packager;
+       }
+
+       public function getHTMLContainer() {
+               return '<div class="link" id="link' . $this->id . '">' . $this->getHTMLContent() . '</div>';
+       }
+
+       public function getHTMLContent() {
+               return '';
+       }
+
+       public function copyExternalFile($file, $video=false) {
+               $this->packager->copyLinkFile($file, 'data/links/', $video);
+       }
+
+       public function getCSSContainer() {
+               $css = '#link' . $this->id . '{';
+               $css.='left:' . $this->left . 'px;top:' . $this->top . 'px;';
+               $css.='width:' . $this->width . 'px;height:' . $this->height . 'px;';
+               $css.=$this->getCSS();
+               $css.='}';
+               return $css;
+       }
+
+       public function getCSS() {
+               return '';
+       }
+
+       public static function getUniversalLocation($loc, $css=false) {
+               $datas = parse_url($loc);
+
+               if (isset($datas['scheme']) && !is_null($datas['scheme'])) {
+                       return $loc;
+               } else {
+                       if ($css) {
+                               return '../links/' . $loc;
+                       } else {
+                               return 'data/links/' . $loc;
+                       }
+               }
+       }
+
+}
+
+class normalLink extends wsPackagerHTML5Link {
+
+       public function getHTMLContent() {
+               $class = array();
+               if ($this->display_area) {
+                       $class[] = 'displayArea';
+               }
+               $c = '';
+               if (count($class)) {
+                       $c = ' class="' . implode(' ', $class) . '"';
+               }
+               return '<a href="' . $this->getURL() . '" target="' . $this->getTarget() . '"' . $c . '></a>';
+       }
+
+       public function getURL() {
+               return '#';
+       }
+
+       public function getTarget() {
+               return '_self';
+       }
+
+}
+
+class contentLink extends wsPackagerHTML5Link {
+       
+}
+
+class webLink extends normalLink {
+
+       public function getURL() {
+               return wsPackagerHTML5Link::getUniversalLocation($this->to);
+       }
+
+       public function getTarget() {
+               return $this->target;
+       }
+
+       public function getCSS() {
+               
+       }
+
+}
+
+class mailLink extends normalLink {
+
+       public function getURL() {
+               return 'mailto:' . $this->to;
+       }
+
+       public function getTarget() {
+               return '_self';
+       }
+
+}
+
+class internalLink extends normalLink {
+
+       public function getURL() {
+               return '#/page/' . $this->getPage();
+       }
+
+       public function getPage() {
+               if ($this->numerotation == 'physical') {
+                       return $this->to;
+               } else {
+                       return $this->packager->virtualToPhysical($this->to);
+               }
+       }
+
+}
+
+class videoLink extends wsPackagerHTML5Link {
+
+       public function getHTMLContent() {
+               $file = $this->to;
+               $e = explode('.', $file);
+               $ext = array_pop($e);
+               $basename = implode('.', $e);
+               $w = round($this->width);
+               $h = round($this->height);
+
+               $res = '<video width="' . $w . '" height="' . $h . '"';
+               if ($this->video_auto_start) {
+                       $res.=' autoplay="autoplay"';
+               }
+               if ($this->video_controls) {
+                       $res.=' controls="controls"';
+               }
+               if ($this->video_loop) {
+                       $res.=' loop="loop"';
+               }
+               if (!$this->video_sound_on) {
+                       $res.=' audio="muted"';
+               }
+               $res.=' poster="data/links/' . $basename . '.jpg"';
+               $res.='>';
+
+
+
+               $this->copyExternalFile($this->to, true);
+               $types = array('webm' => 'video/webm; codecs="vp8, vorbis"', 'ogv' => 'video/ogg; codecs="theora, vorbis"', 'mp4' => '');
+               foreach ($types as $ext => $type) {
+                       if ($type != '') {
+                               $type = " type='" . $type . "'";
+                       }
+                       $res.='<source src="' . wsPackagerHTML5Link::getUniversalLocation($basename . '.' . $ext) . '"' . $type . ' />';
+               }
+               $flashvars = array('video' => wsPackagerHTML5Link::getUniversalLocation($basename . '.mp4'),
+                       'poster' => wsPackagerHTML5Link::getUniversalLocation($basename . '.jpg'),
+                       'controls' => $this->video_controls == '1',
+                       'autoPlay' => $this->video_auto_start == '1',
+                       'loop' => $this->video_loop);
+               $res.=cubeMedia::flashObject('swf/video.swf', $w, $h, $flashvars, 'swfplayer-' . $basename, '', 9, '#ffffff', '', 'true', 'noscale', 'normal');
+               $res.='</video>';
+               return $res;
+       }
+
+}
+
+class webVideoLink extends videoLink {
+
+       public function getHTMLContent() {
+               return $this->getEmbed();
+       }
+
+       public function getEmbed() {
+               return '<iframe width="' . $this->width . '" height="' . $this->height . '" src="' . $this->getEmbedURL() . '" frameborder="0" allowfullscreen></iframe>';
+       }
+
+       public function getEmbedURL() {
+               if ($this->video_service == 0) {
+                       $url = 'http://www.youtube.com/embed/' . $this->to . '?html5=1';
+               } else {
+                       $url = 'http://www.dailymotion.com/embed/video/' . $this->to;
+               }
+               return $url;
+       }
+
+}
+
+class actionLink extends internalLink {
+
+       public function getURL() {
+               return '#' . $to;
+       }
+
+}
+
+class basketLink extends wsPackagerHTML5Link {
+       
+}
+
+class colorLink extends contentLink {
+
+       public function getCSS() {
+               return 'background-color:' . wsPackagerHTML5::colorToCSS($this->to) . ';';
+       }
+
+}
+
+class imageLink extends contentLink {
+
+       public function getCSS() {
+               $this->copyExternalFile($this->to);
+               return 'background-image:url(' . wsPackagerHTML5Link::getUniversalLocation($this->to, true) . ');background-size:100% 100%;background-repeat:no-repeat;';
+       }
+
+}
+
+class fileLink extends normalLink {
+
+       public function getURL() {
+               $this->copyExternalFile($this->to);
+               return wsPackagerHTML5Link::getUniversalLocation($this->to);
+       }
+
+       public function getTarget() {
+               return '_blank';
+       }
+
+}
+
+class multimediaLink extends wsPackagerHTML5Link {
+
+       public function getHTMLContent() {
+               return cubeMedia::flashObject(wsPackagerHTML5Link::getUniversalLocation($this->to), $this->width, $this->height, array(), '', '', 9, '#ffffff', '', 'true', 'noscale', 'transparent');
+       }
+
+}
+
+class videoPopupLink extends normalLink {
+
+       public function getURL() {
+               $this->copyExternalFile($this->to, true);
+               return '#/video/' . $this->to;
+       }
+
+}
+
+class webVideoPopupLink extends videoPopupLink {
+
+       public function getURL() {
+               if ($this->video_service == 0) {
+                       $service = 'youtube';
+               } elseif ($this->video_service == 1) {
+                       $service = 'dailymotion';
+               }
+               return '#/webvideo/' . $service . '/' . $this->to;
+       }
+
+}
+
+?>
diff --git a/inc/ws/Util/packager/html5/class.ws.packager.html5.php b/inc/ws/Util/packager/html5/class.ws.packager.html5.php
new file mode 100644 (file)
index 0000000..ac21e91
--- /dev/null
@@ -0,0 +1,903 @@
+<?php\r
+\r
+class wsPackagerHTML5 extends wsPackager {\r
+\r
+       protected $layouts = array();\r
+       protected $cssSize = array();\r
+       protected $cssColor = array();\r
+       protected $cssOpacity = array();\r
+       protected $cssFont = array();\r
+       protected $cssWordSpacing = array();\r
+       protected $cssLetterSpacing = array();\r
+       protected $cssRotation = array();\r
+       protected $cssX = array();\r
+       protected $cssY = array();\r
+       protected $pdf2htmlRatio;\r
+       protected $scale;\r
+       protected $multiply;\r
+       protected $div = array();\r
+       protected $numerotation;\r
+       protected static $resolutions = array(36, 72, 150);\r
+       protected static $uaPrefixes = array('-moz-', '-webkit-', '-o-', '-ms-', '');\r
+       protected $fontDocs = array();\r
+\r
+       public function __construct($book_id) {\r
+               parent::__construct($book_id);\r
+               $this->version = 'html5';\r
+       }\r
+\r
+       protected function preparePackage() {\r
+               parent::preparePackage();\r
+\r
+               foreach ($this->pages as $page => $infos) {\r
+                       $file = WS_DOCS . '/' . $infos['document_id'] . '/html/p' . $infos['document_page'] . '.layout';\r
+                       if (file_exists($file)) {\r
+                               $this->layouts[$page] = simplexml_load_file($file, null, LIBXML_ERR_WARNING);\r
+                       }\r
+               }\r
+\r
+               $imagesize = getimagesize(WS_DOCS . '/' . $this->pages[1]['document_id'] . '/html/h72-' . $this->pages[1]['document_page'] . '.jpg');\r
+               $this->pdf2htmlRatio = round($imagesize[0] / $this->layouts[1]['width'], 2);\r
+               $this->scale = 4;\r
+               $this->multiply = $this->pdf2htmlRatio * $this->scale;\r
+               $this->numerotation = explode(',', $this->book->numerotation);\r
+\r
+               $this->createHTML();\r
+       }\r
+\r
+       public function makePackage() {\r
+               parent::makePackage();\r
+               return $this->zip();\r
+       }\r
+\r
+       public function virtualToPhysical($virtual) {\r
+               if (!in_array($virtual, $this->numerotation)) {\r
+                       return 1;\r
+               }\r
+               $p = array_search($virtual, $this->numerotation);\r
+               return $p + 1;\r
+       }\r
+\r
+       protected function compareLines($a, $b) {\r
+               if ((float) $a['y'] > (float) $b['y']) {\r
+                       return 1;\r
+               } else {\r
+                       return -1;\r
+               }\r
+       }\r
+\r
+       protected function createHTML() {\r
+               foreach ($this->layouts as $page => $layout) {\r
+                       $this->div[$page] = array();\r
+                       $document_id = $this->pages[$page]['document_id'];\r
+                       $lines = array();\r
+                       foreach ($layout->l as $line) {\r
+                               $lines[] = $line;\r
+                       }\r
+                       usort($lines, array($this, 'compareLines'));\r
+\r
+                       foreach ($lines as $line) {\r
+                               $this->div[$page][] = $this->addLine($line, $document_id);\r
+                       }\r
+               }\r
+               mkdir($this->vdir . '/data/images', 0777, true);\r
+               mkdir($this->vdir . '/data/contents', 0777, true);\r
+               mkdir($this->vdir . '/data/background', 0777, true);\r
+               mkdir($this->vdir . '/data/thumbnails', 0777, true);\r
+               mkdir($this->vdir . '/data/style', 0777, true);\r
+               mkdir($this->vdir . '/data/links/pages', 0777, true);\r
+               mkdir($this->vdir . '/data/l10n/', 0777, true);\r
+               mkdir($this->vdir . '/swf', 0777, true);\r
+\r
+               // Copy style folder\r
+               $from = WS_COMPILE_ASSETS . '/_html5/style';\r
+               $to = $this->vdir;\r
+               `cp -r $from $to`;\r
+\r
+               // Copy images folder\r
+               $from = WS_COMPILE_ASSETS . '/_html5/images';\r
+               `cp -r $from $to`;\r
+\r
+               // Copy swf\r
+               copy(WS_COMPILE_ASSETS . '/_html5/swf/video.swf', $this->vdir . '/swf/video.swf');\r
+\r
+               foreach ($this->div as $n => $page) {\r
+                       file_put_contents($this->vdir . '/data/contents/p' . $n . '.html', $this->writePage($page));\r
+               }\r
+               $this->writeFonts();\r
+               $this->writeImages();\r
+               $linksCSS = $this->writeLinks();\r
+               $numCSS = $this->writeCSS($this->vdir . '/data/style/style_%d.css', $linksCSS);\r
+               $this->writeLangs();\r
+               $this->writeJs();\r
+               $this->writeIndex($numCSS);\r
+       }\r
+\r
+       protected function writeIndex($numCSS) {\r
+               $html = file_get_contents(WS_COMPILE_ASSETS . '/_html5/_index.html');\r
+\r
+               $titre = $this->book->parametres->title;\r
+               $credits = '';\r
+               // Google analytics\r
+               $ga = '';\r
+               if ($this->book->parametres->googleAnalytics != '') {\r
+                       $ga = cubePage::googleAnalytics($this->book->parametres->googleAnalytics);\r
+               }\r
+               // Feuilles de style\r
+               $sheets = array('style/fluidbook.css');\r
+               for ($i = 0; $i < $numCSS; $i++) {\r
+                       $sheets[] = 'data/style/style_' . $i . '.css';\r
+               }\r
+               $style = array();\r
+               foreach ($sheets as $sheet) {\r
+                       $style[] = '<link type="text/css" rel="stylesheet" href="' . $sheet . '?junk=' . TIME . '" />';\r
+               }\r
+               $style = implode("\n\t\t", $style);\r
+\r
+               $vars = array('titre', 'credits', 'ga', 'style');\r
+               foreach ($vars as $v) {\r
+                       $html = str_replace('<!-- $' . $v . ' -->', $$v, $html);\r
+               }\r
+               file_put_contents($this->vdir . '/index.html', $html);\r
+       }\r
+\r
+       protected function writeLangs() {\r
+               global $core;\r
+               $daoLang = new wsDAOLang($core->con);\r
+               $lang = $daoLang->selectById($this->book->lang);\r
+               $langs = $daoLang->selectAll();\r
+\r
+\r
+               $traductions = (!count($this->book->traductions)) ? $lang->traductions : $this->book->traductions;\r
+               file_put_contents($this->vdir . '/data/l10n/default.json', json_encode($traductions));\r
+               foreach ($langs as $lang) {\r
+                       file_put_contents($this->vdir . '/data/l10n/' . $lang->lang_id . '.json', json_encode($lang->traductions));\r
+               }\r
+       }\r
+\r
+       protected function writeLinks() {\r
+               global $core;\r
+               $daoDoc = new wsDAODocument($core->con);\r
+               $daoDoc->getLinksAndRulers($this->book_id, $links, $rulers);\r
+\r
+               $i = 0;\r
+               $pages = array();\r
+               $css = array();\r
+               foreach ($links as $linkData) {\r
+                       $link = wsPackagerHTML5Link::getInstance($this->base62($i), $linkData, $this);\r
+                       if (is_null($link)) {\r
+                               continue;\r
+                       }\r
+                       if (!isset($pages[$link->page])) {\r
+                               $pages[$link->page] = '';\r
+                       }\r
+                       $pages[$link->page] .= $link->getHTMLContainer();\r
+                       $css[] = $link->getCSSContainer();\r
+                       $i++;\r
+               }\r
+\r
+               for ($i = 0; $i <= $this->book->parametres->pages + 1; $i++) {\r
+                       $c = '';\r
+                       if (isset($pages[$i])) {\r
+                               $c = $pages[$i];\r
+                       }\r
+                       file_put_contents($this->vdir . 'data/links/pages/p' . $i . '.html', $c);\r
+               }\r
+               return $css;\r
+       }\r
+\r
+       protected function writeJs() {\r
+               $files = array('js/libs/modernizr.js',\r
+                       'js/libs/jquery/jquery.js',\r
+                       'js/libs/jquery/jquery.transform.js',\r
+                       'js/libs/jquery/jquery.mousewheel.js',\r
+                       'js/libs/jquery/jquery.hashchange.js',\r
+                       'js/libs/fluidbook/fluidbook.utils.js',\r
+                       'js/libs/fluidbook/fluidbook.cache.js',\r
+                       'js/libs/fluidbook/fluidbook.support.js',\r
+                       'js/libs/fluidbook/fluidbook.viewport.js',\r
+                       'js/libs/fluidbook/fluidbook.desktop.js',\r
+                       'js/libs/fluidbook/fluidbook.service.js',\r
+                       'js/libs/fluidbook/fluidbook.loader.js',\r
+                       'js/libs/fluidbook/fluidbook.l10n.js',\r
+                       'js/libs/fluidbook/fluidbook.nav.js',\r
+                       'js/libs/fluidbook/fluidbook.js',\r
+                       'js/main.js');\r
+\r
+               $mintime = 0;\r
+               $minimized = WS_COMPILE_ASSETS . '/_html5/js/min.js';\r
+               if (file_exists($minimized)) {\r
+                       $mintime = filemtime($minimized);\r
+               }\r
+               $reminimize = false;\r
+               foreach ($files as $file) {\r
+                       if (filemtime(WS_COMPILE_ASSETS . '/_html5/' . $file) > $mintime) {\r
+                               $reminimize = true;\r
+                               break;\r
+                       }\r
+               }\r
+\r
+               if ($reminimize) {\r
+                       $js = '';\r
+                       foreach ($files as $file) {\r
+                               $js.=file_get_contents(WS_COMPILE_ASSETS . '/_html5/' . $file);\r
+                               $js.="\n\n";\r
+                       }\r
+                       $tmp = cubeFiles::tempnam();\r
+                       file_put_contents($tmp, $js);\r
+\r
+                       $compressor = new cubeCommandLine('yuicompressor');\r
+                       $compressor->setPath(CONVERTER_PATH);\r
+                       $compressor->setArg('charset', 'UTF-8');\r
+                       $compressor->setArg('type', 'js');\r
+                       $compressor->setArg('line-break', 1024);\r
+                       $compressor->setArg('o', $minimized);\r
+                       $compressor->setArg(null, $tmp);\r
+                       $compressor->execute();\r
+               }\r
+\r
+               $js = $this->writeConfig();\r
+               $js.=file_get_contents($minimized);\r
+               file_put_contents($this->vdir . '/data/fluidbook.js', $js);\r
+       }\r
+\r
+       protected function writeConfig() {\r
+               $config = cubeObject::merge($this->book->parametres->toStandardObject(), $this->theme->parametres->toStandardObject());\r
+               $config->numerotation = explode(',', $this->book->numerotation);\r
+               $config->id = $this->book->book_id;\r
+               $config->cacheDate = TIME;\r
+               return 'var DATAS=' . json_encode($config) . ';' . "\n";\r
+       }\r
+\r
+       protected function writeFonts() {\r
+               $formats = array('ttf', 'woff', 'svg');\r
+\r
+               foreach ($this->cssFont as $font => $index) {\r
+\r
+                       foreach ($formats as $format) {\r
+                               $fontforge = new cubeCommandLine('convert.pe');\r
+                               $fontforge->setPath(CONVERTER_PATH);\r
+                               foreach ($this->fontDocs[$font] as $document_id => $dummy) {\r
+                                       $fontforge->setArg(null, WS_DOCS . '/' . $document_id . '/fonts/web/' . $font . '.ttf');\r
+                               }\r
+                               $fontforge->setArg(null, $this->vdir . '/data/style/F' . $index . '.' . $format);\r
+                               $fontforge->execute();\r
+                       }\r
+               }\r
+       }\r
+\r
+       protected function writeIcons() {\r
+               $res = array();\r
+               // Get the colors used to colorize graphics\r
+               if ($this->theme->parametres->colorizeIcons) {\r
+                       $couleurI = '#' . $this->theme->parametres->couleurI;\r
+               } else {\r
+                       $couleurI = '#FFFFFF';\r
+               }\r
+               $arrowsColor = '#' . $this->theme->parametres->arrowsColor;\r
+               // Set the icon list with the color\r
+               $icons = array('nav-bookmark' => $couleurI, 'nav-friend' => $couleurI, 'nav-help' => $couleurI, 'nav-index' => $couleurI, 'nav-sommaire' => $couleurI,\r
+                       'next' => $arrowsColor, 'previous' => $arrowsColor, 'search' => $couleurI, 'nav-facebook' => $couleurI, 'nav-twitter' => $couleurI,\r
+                       'help-fingers' => $couleurI, 'help-mouse' => $couleurI);\r
+\r
+               foreach ($icons as $icon => $color) {\r
+                       wsTools::colorizeAndRasterizeIcon($this->theme->parametres->iconSet, $icon, $color, $this->vdir . '/data/images/', 4, $w, $h);\r
+               }\r
+               return $res;\r
+       }\r
+\r
+       protected function writeImages() {\r
+\r
+               foreach (self::$resolutions as $r) {\r
+                       mkdir($this->vdir . '/data/background/' . $r, 0777);\r
+               }\r
+               foreach ($this->pages as $page => $infos) {\r
+                       foreach (self::$resolutions as $r) {\r
+                               copy(WS_DOCS . '/' . $infos['document_id'] . '/html/h' . $r . '-' . $infos['document_page'] . '.jpg', $this->vdir . '/data/background/' . $r . '/p' . $page . '.jpg');\r
+                       }\r
+                       copy(WS_DOCS . '/' . $infos['document_id'] . '/p' . $infos['document_page'] . '.jpg', $this->vdir . '/data/thumbnails/p' . $page . '.jpg');\r
+               }\r
+       }\r
+\r
+       protected function writePage($page) {\r
+               $res = '';\r
+               foreach ($page as $line) {\r
+                       $res .= $this->writeLine($line);\r
+               }\r
+               return $res;\r
+       }\r
+\r
+       protected function writeLine($line) {\r
+               $res = '';\r
+               foreach ($line['groups'] as $group) {\r
+                       $res.=$this->writeGroup($group, $line);\r
+               }\r
+               return $res;\r
+       }\r
+\r
+       protected function writeGroup($group, $line) {\r
+               if ($group === false) {\r
+                       return '';\r
+               }\r
+\r
+               $group['y'] = $this->getCSSY(($group['y'] + $line['y']) * $this->multiply);\r
+               $group['x'] = $this->getCSSX(($group['x']) * $this->multiply);\r
+\r
+               $class = array('g');\r
+               if (!is_null($group['color'])) {\r
+                       $class[] = 'c' . $group['color'];\r
+               }\r
+               if (!is_null($group['size'])) {\r
+                       $class[] = 's' . $group['size'];\r
+               }\r
+               if (!is_null($group['font'])) {\r
+                       $class[] = 'f' . $group['font'];\r
+               }\r
+               if (!is_null($group['x'])) {\r
+                       $class[] = 'x' . $group['x'];\r
+               }\r
+               if (!is_null($group['y'])) {\r
+                       $class[] = 'y' . $group['y'];\r
+               }\r
+               if (!is_null($line['rotation'])) {\r
+                       $class[] = 'r' . $line['rotation'];\r
+               }\r
+               if (!is_null($group['letterspacing'])) {\r
+                       $class[] = 'l' . $group['letterspacing'];\r
+               }\r
+               if (!is_null($group['wordspacing'])) {\r
+                       $class[] = 'w' . $group['wordspacing'];\r
+               }\r
+               $class = implode(' ', $class);\r
+\r
+               $res = '<div class="' . $class . '">';\r
+               foreach ($group['spans'] as $span) {\r
+                       $res.=$this->writeSpan($span);\r
+               }\r
+               $res.='</div>';\r
+               return $res;\r
+       }\r
+\r
+       protected function writeSpan($span) {\r
+               if ($span === false) {\r
+                       return '';\r
+               }\r
+\r
+               if ($span['space']) {\r
+                       return $span['text'];\r
+               } else {\r
+                       return self::escapeHTML($span['text']);\r
+               }\r
+       }\r
+\r
+       protected function writeCSS($file, $links) {\r
+               $res = array();\r
+\r
+               // General theme\r
+               $h = $this->book->parametres->height . 'px';\r
+               $w2 = ($this->book->parametres->width * 2) . 'px';\r
+               $w = $this->book->parametres->width . 'px';\r
+               $wm = ($this->book->parametres->width * $this->multiply) . 'px';\r
+               $hm = ($this->book->parametres->height * $this->multiply) . 'px';\r
+\r
+\r
+               $navTop = ($this->book->parametres->height - 40 - 100) / 2;\r
+               $res[] = '.portrait #pages,.portrait .doublePage.page,.page,.portrait #shadow,#shadow.single,.page .links{width:' . $w . ';max-width:' . $w . ';height:' . $h . ';max-height:' . $h . '}';\r
+               $res[] = '.background{' . $this->writeCSSUA('transform-origin', 'top left') . ';}';\r
+               foreach (self::$resolutions as $r) {\r
+                       $ratio = round(72 / $r, 2);\r
+                       $wr = $this->book->parametres->width / $ratio;\r
+                       $hr = $this->book->parametres->height / $ratio;\r
+\r
+                       $br = '.background.r' . $r . '{';\r
+                       if ($ratio != 1) {\r
+                               $br.=$this->writeCSSUA('transform', 'scale(' . $ratio . ')') . ';';\r
+                       }\r
+                       $br.='width:' . $wr . 'px;height:' . $hr . 'px;}';\r
+                       $res[] = $br;\r
+               }\r
+               $res[] = '.doublePage,#pages,.landscape #shadow.double{width:' . $w2 . ';max-width:' . $w2 . ';height:' . $h . ';max-height:' . $h . '}';\r
+               $res[] = '.landscape #shadow.single.right{left: ' . $w . ';}';\r
+               $res[] = '.landscape .page.right{left:' . $w . '}';\r
+               if ($this->theme->parametres->displayPageNumber) {\r
+                       $res[] = '#pagesnumbers{top:' . $h . ';color:' . self::colorToCSS($this->theme->parametres->colorPageNumber) . '}';\r
+                       $res[] = '#pagesnumbers div{width:' . $w . '}';\r
+               } else {\r
+                       $res[] = '#pagesnumbers{display:none;}';\r
+               }\r
+\r
+               $texts = '.texts{' . $this->writeCSSUA('transform-origin', 'top left') . ';';\r
+               $texts.=$this->writeCSSUA('transform', 'scale(' . round(1 / $this->multiply, 2) . ')') . ';';\r
+               $texts.='width:' . $wm . '; max-width:' . $wm . ';';\r
+               $texts.='height:' . $hm . '; max-height:' . $hm . ';';\r
+               $texts.='}';\r
+               $res[] = $texts;\r
+\r
+               // Theme\r
+               // Background\r
+               $body = '#deviceView{';\r
+               $body.='background-color:#' . $this->theme->parametres->backgroundColor . ';';\r
+               switch ($this->theme->parametres->repeat) {\r
+                       case wsTheme::REPEAT:\r
+                               $body.='background-repeat:repeat;';\r
+                               break;\r
+                       case wsTheme::NONE:\r
+                               $body.='background-repeat:no-repeat;';\r
+                               break;\r
+                       case wsTheme::RATIO:\r
+                               $body.='background-repeat:no-repeat;';\r
+                               break;\r
+                       case wsTheme::STRETCH:\r
+                               $body.='background-repeat:no-repeat;';\r
+                               $body.='background-size:100% 100%;';\r
+                               break;\r
+               }\r
+               if ($this->theme->parametres->backgroundImage != '') {\r
+                       copy($this->themeRoot . '/' . $this->theme->parametres->backgroundImage, $this->vdir . '/data/images/' . $this->theme->parametres->backgroundImage);\r
+                       $body.='background-image:url(../images/' . $this->theme->parametres->backgroundImage . ');';\r
+                       $body.='background-position:';\r
+\r
+\r
+                       switch ($this->theme->parametres->backgroundVAlign) {\r
+                               case wsTheme::TOP:\r
+                                       $body.='top';\r
+                                       break;\r
+                               case wsTheme::MIDDLE:\r
+                                       $body.='center';\r
+                                       break;\r
+                               case wsTheme::BOTTOM:\r
+                                       $body.='bottom';\r
+                                       break;\r
+                       }\r
+                       $body.=' ';\r
+                       switch ($this->theme->parametres->backgroundHAlign) {\r
+                               case wsTheme::LEFT:\r
+                                       $body.='left';\r
+                                       break;\r
+                               case wsTheme::CENTER:\r
+                                       $body.='center';\r
+                                       break;\r
+                               case wsTheme::RIGHT:\r
+                                       $body.='right';\r
+                                       break;\r
+                       }\r
+                       $body.=';';\r
+               }\r
+\r
+               $body.='}';\r
+               $res[] = $body;\r
+\r
+               // Header\r
+               $header = '#header{';\r
+               $header.='height:' . $this->theme->parametres->menuHeight . 'px;';\r
+               $header.='background-color:' . self::colorToCSS($this->theme->parametres->menuColor) . ';';\r
+               if ($this->theme->parametres->menuImage != '') {\r
+                       copy($this->themeRoot . '/' . $this->theme->parametres->menuImage, $this->vdir . '/data/images/' . $this->theme->parametres->menuImage);\r
+                       $header.='background-image:url(../images/' . $this->theme->parametres->menuImage . ');';\r
+                       $header.='background-repeat:no-repeat;';\r
+                       $header.='background-size:100% ' . $this->theme->parametres->menuHeight . 'px;';\r
+               }\r
+               $header.='}';\r
+               $res[] = $header;\r
+\r
+               //Icons\r
+               $res = array_merge($res, $this->writeIcons());\r
+\r
+               // Logo\r
+               $logo = '#logo{';\r
+               if ($this->theme->parametres->logo) {\r
+                       copy($this->themeRoot . '/' . $this->theme->parametres->logo, $this->vdir . '/data/images/' . $this->theme->parametres->logo);\r
+                       $dim = getimagesize($this->vdir . '/data/images/' . $this->theme->parametres->logo);\r
+                       $logo.='background-image:url(../images/' . $this->theme->parametres->logo . ');width:' . $dim[0] . 'px;height:' . $dim[1] . 'px;';\r
+               }\r
+               $logo.='}';\r
+               $res[] = $logo;\r
+\r
+               // Credits\r
+               $res[] = '#credits,#credits a{color:' . self::colorToCSS($this->theme->parametres->creditsColor) . ';}';\r
+\r
+               // Arrows\r
+               $res[] = '#next,#previous{background-color:' . self::colorToCSS($this->theme->parametres->couleurA) . ';}';\r
+               // Book shadow\r
+               $shadowColor = self::colorToCSS($this->theme->parametres->bookShadeColor);\r
+               if ($shadowColor != 'transparent') {\r
+                       $res[] = '#shadow{' . $this->writeCSSUA('box-shadow', '0 0 20px ' . $shadowColor) . '}';\r
+               }\r
+\r
+               // Links Styles\r
+               $res = array_merge($res, $links);\r
+               $res[] = '.link a.displayArea:hover,.link a.displayArea.animating{background-color:' . self::colorToCSS($this->theme->parametres->linksColor, 0.4) . ';}';\r
+\r
+               // Menus\r
+               # View\r
+               $res[] = '.portrait #view{width:' . $w . ';min-height:' . $h . '}';\r
+               $res[] = '.landscape #view{width:' . $w2 . ';min-height:' . $h . '}';\r
+               $res[] = '#view{background-color:' . self::colorToCSS($this->theme->parametres->couleurB) . ';color:' . self::colorToCSS($this->theme->parametres->subTextColor) . ';}';\r
+               # Index\r
+               $ratio = $this->book->parametres->width / $this->book->parametres->height;\r
+               $thumbh = round(100 / $ratio);\r
+               $res[] = '#index .thumb img{width:100px;height:' . $thumbh . 'px;}';\r
+               $res[] = '#index .doubleThumb{height:' . $thumbh . 'px;' . $this->writeCSSUA('box-shadow', '0 0 3px ' . $shadowColor) . '}';\r
+               $res[] = '#index .doubleThumb .overlay{height:' . $thumbh . 'px;}';\r
+               $res[] = '#index .doubleThumb .hits.yes{background-color:' . self::colorToCSS($this->theme->parametres->subSelectColor) . ';color:' . self::colorToCSS($this->theme->parametres->subTextSelectColor) . '}';\r
+\r
+               // Pages styles\r
+               foreach ($this->cssColor as $color => $index) {\r
+                       $res[] = '.c' . $index . '{color:#' . $color . '}';\r
+               }\r
+\r
+               foreach ($this->cssSize as $size => $index) {\r
+                       $res[] = '.s' . $index . '{font-size:' . $size . 'px}';\r
+               }\r
+\r
+               foreach ($this->cssLetterSpacing as $letterspacing => $index) {\r
+                       $res[] = '.l' . $index . '{letter-spacing:' . $letterspacing . 'em}';\r
+               }\r
+\r
+               foreach ($this->cssWordSpacing as $wordspacing => $index) {\r
+                       $res[] = '.w' . $index . '{word-spacing:' . $wordspacing . 'em}';\r
+               }\r
+\r
+               foreach ($this->cssX as $x => $index) {\r
+                       $res[] = '.x' . $index . '{left:' . $x . 'px}';\r
+               }\r
+\r
+               foreach ($this->cssY as $y => $index) {\r
+                       $res[] = '.y' . $index . '{top:' . $y . 'px}';\r
+               }\r
+\r
+               foreach ($this->cssRotation as $rotation => $index) {\r
+                       $rotation*= - 1;\r
+\r
+\r
+                       $to = 'transform-origin:left top;';\r
+\r
+                       $css = '.r' . $index . '{';\r
+                       $css.=self::writeCSSUA('transform', 'rotate(' . $rotation . 'deg)') . ';';\r
+                       $css.=self::writeCSSUA('transform-origin', 'left top') . ';';\r
+                       $css.='margin-top:' . round(cos(deg2rad($rotation)) * -1, 2) . 'em !important;';\r
+                       $css.='margin-left:' . round(sin(deg2rad($rotation)), 2) . 'em !important;';\r
+                       $css.='}';\r
+                       $res[] = $css;\r
+               }\r
+\r
+               foreach ($this->cssFont as $font => $index) {\r
+                       $res[] = "@font-face{font-family:F" . $index . ";src:url('F" . $index . ".woff') format('woff'),url('F" . $index . ".ttf') format('truetype'),url('F" . $index . ".svg#" . $font . "') format('svg')}";\r
+                       $res[] = '.f' . $index . '{font-family:F' . $index . ',Arial,Helvetica}';\r
+               }\r
+\r
+               $res = array_chunk($res, 3500);\r
+               foreach ($res as $k => $css) {\r
+                       file_put_contents(sprintf($file, $k), implode("\n", $css));\r
+               }\r
+               return count($res);\r
+       }\r
+\r
+       protected function writeCSSUA($property, $value) {\r
+               $res = array();\r
+               foreach (self::$uaPrefixes as $prefix) {\r
+                       $res[] = $prefix . $property . ':' . $value;\r
+               }\r
+               return implode(';', $res);\r
+       }\r
+\r
+       protected function addLine($line, $document_id) {\r
+               $res = array();\r
+               foreach ($line->a as $group) {\r
+                       $res = array_merge($res, $this->addGroup($group, $document_id));\r
+               }\r
+               return array(\r
+                       'y' => $this->normalizeFloatValue($line['y']),\r
+                       'rotation' => $this->getCSSRotation($this->normalizeFloatValue($line['rotation'], 0)),\r
+                       "groups" => $res);\r
+       }\r
+\r
+       protected function addGroup($group, $document_id) {\r
+               $alpha = intval(substr($group['color'], 1, 2), 16);\r
+               if ($alpha == 0) {\r
+                       return false;\r
+               }\r
+\r
+               $first = true;\r
+               $letterSpacing = 0;\r
+               $letterCount = 0;\r
+               $wordSpacing = 0;\r
+               $wordCount = 0;\r
+\r
+               $res = array();\r
+               $spans = array();\r
+\r
+               foreach ($group->s as $span) {\r
+                       if ($first && trim((string) $span) == '') {\r
+                               continue;\r
+                       }\r
+                       if ($first) {\r
+                               $pos = $x = $span['x'];\r
+                               $pos+=$span['width'];\r
+                               $first = false;\r
+                       } else {\r
+                               if ((float) $span['x'] < (float) $newSpan['x']) {\r
+                                       // On change de groupe\r
+                                       $ls = $ws = 0;\r
+                                       if ($letterCount > 0) {\r
+                                               $ls = $letterSpacing / $letterCount;\r
+                                       }\r
+                                       if ($wordCount > 0) {\r
+                                               $ws = $wordSpacing / $wordCount;\r
+                                       }\r
+\r
+                                       $res[] = array(\r
+                                               'color' => $this->getCSSColor($group['color']),\r
+                                               'size' => $this->getCSSSize($group['size']),\r
+                                               'font' => $this->getCSSFont((string) $group['font'], $document_id),\r
+                                               'letterspacing' => $this->getCSSLetterSpacing($ls),\r
+                                               'wordspacing' => $this->getCSSLetterSpacing($ws),\r
+                                               'y' => 0,\r
+                                               'x' => $x,\r
+                                               'spans' => $spans);\r
+\r
+                                       $spans = array();\r
+                                       $pos = $x = $span['x'];\r
+                                       $pos+=$span['width'];\r
+                               } else {\r
+\r
+                                       $diff = $span['x'] - $pos;\r
+                                       if ($diff > $group['size'] / 4) {\r
+                                               $space = round($diff / $group['size'], 4);\r
+                                               if ($space > 2) {\r
+                                                       // On change de groupe\r
+                                                       $ls = $ws = 0;\r
+                                                       if ($letterCount > 0) {\r
+                                                               $ls = $letterSpacing / $letterCount;\r
+                                                       }\r
+                                                       if ($wordCount > 0) {\r
+                                                               $ws = $wordSpacing / $wordCount;\r
+                                                       }\r
+                                                       $res[] = array(\r
+                                                               'color' => $this->getCSSColor($group['color']),\r
+                                                               'size' => $this->getCSSSize($group['size']),\r
+                                                               'font' => $this->getCSSFont($group['font'], $document_id),\r
+                                                               'letterspacing' => $this->getCSSLetterSpacing($ls),\r
+                                                               'wordspacing' => $this->getCSSLetterSpacing($ws),\r
+                                                               'y' => 0,\r
+                                                               'x' => $x,\r
+                                                               'spans' => $spans);\r
+\r
+                                                       $spans = array();\r
+                                                       $pos = $x = $span['x'];\r
+                                                       $pos+=$span['width'];\r
+                                               } else {\r
+\r
+                                                       $newSpan = $this->addSpan('<span style="width:' . $space . 'em;"> </span>', true);\r
+                                                       array_push($spans, $newSpan);\r
+                                               }\r
+                                       }\r
+                               }\r
+                       }\r
+\r
+\r
+                       $newSpan = $this->addSpan($span);\r
+                       $pos = $span['x'] + $span['width'];\r
+\r
+                       array_push($spans, $newSpan);\r
+                       $copy = (string) $span;\r
+                       $len = mb_strlen($copy);\r
+                       str_replace(' ', '-', $copy, $w);\r
+                       $l = $len - $w;\r
+\r
+                       $letterCount+=$l;\r
+                       $wordCount+=$w;\r
+\r
+                       $letterSpacing+=$l * (float) $span['letterspacing'];\r
+                       $wordSpacing+=$w * (float) $span['wordspacing'];\r
+               }\r
+\r
+               if (count($spans)) {\r
+                       $ls = $ws = 0;\r
+                       if ($letterCount > 0) {\r
+                               $ls = $letterSpacing / $letterCount;\r
+                       }\r
+                       if ($wordCount > 0) {\r
+                               $ws = $wordSpacing / $wordCount;\r
+                       }\r
+\r
+                       $res[] = array(\r
+                               'color' => $this->getCSSColor($group['color']),\r
+                               'size' => $this->getCSSSize($group['size']),\r
+                               'font' => $this->getCSSFont($group['font'], $document_id),\r
+                               'letterspacing' => $this->getCSSLetterSpacing($ls),\r
+                               'wordspacing' => $this->getCSSLetterSpacing($ws),\r
+                               'y' => 0,\r
+                               'x' => $x,\r
+                               'spans' => $spans);\r
+               }\r
+\r
+               return $res;\r
+       }\r
+\r
+       protected function addSpan($span, $space=false) {\r
+               $text = (string) $span;\r
+               return array('text' => $text, 'space' => $space, 'x' => $span['x']);\r
+       }\r
+\r
+       protected function getCSSSize($size) {\r
+               $size = $this->normalizeFloatValue($size);\r
+               $size*=$this->multiply;\r
+               return $this->getIndex($size, $this->cssSize);\r
+       }\r
+\r
+       protected function getCSSFont($font, $document_id) {\r
+               $font = (string) $font;\r
+               if (!isset($this->fontDocs[$font])) {\r
+                       $this->fontDocs[$font] = array();\r
+               }\r
+               $this->fontDocs[$font][$document_id] = true;\r
+\r
+               return $this->getIndex($font, $this->cssFont);\r
+       }\r
+\r
+       protected function getCSSColor($color) {\r
+               $color = trim($color, '#');\r
+               if (strlen($color) > 6) {\r
+                       $color = substr($color, 2, 6);\r
+               }\r
+               if ($color == '000000') {\r
+                       return null;\r
+               }\r
+               return $this->getIndex($color, $this->cssColor);\r
+       }\r
+\r
+       protected function getCSSLetterSpacing($letterspacing) {\r
+\r
+               $letterspacing = $this->normalizeFloatValue($letterspacing, 4);\r
+\r
+               if ($letterspacing == 0) {\r
+                       return null;\r
+               }\r
+               return $this->getIndex($letterspacing, $this->cssLetterSpacing);\r
+       }\r
+\r
+       protected function getCSSWordSpacing($wordspacing) {\r
+               $wordspacing = $this->normalizeFloatValue($wordspacing, 4);\r
+\r
+               if ($wordspacing == 0) {\r
+                       return null;\r
+               }\r
+               return $this->getIndex($wordspacing, $this->cssWordSpacing);\r
+       }\r
+\r
+       protected function getCSSRotation($rotation) {\r
+               $rotation = $this->normalizeFloatValue($rotation, 0);\r
+               if ($rotation == 0) {\r
+                       return null;\r
+               }\r
+               return $this->getIndex($rotation, $this->cssRotation);\r
+       }\r
+\r
+       protected function getCSSX($x) {\r
+               $x = round($x);\r
+               if ($x == 0) {\r
+                       return null;\r
+               }\r
+               return $this->getIndex($x, $this->cssX);\r
+       }\r
+\r
+       protected function getCSSY($y) {\r
+               $y = round($y);\r
+               if ($y == 0) {\r
+                       return null;\r
+               }\r
+               return $this->getIndex($y, $this->cssY);\r
+       }\r
+\r
+       protected function getIndex($value, &$tab) {\r
+               $value = (string) $value;\r
+               if (isset($tab[$value])) {\r
+                       return $tab[$value];\r
+               }\r
+               $res = $this->base62(count($tab));\r
+               $tab[$value] = $res;\r
+               return $res;\r
+       }\r
+\r
+       protected function normalizeFloatValue($value, $round=3) {\r
+               $value = str_replace(',', '.', $value);\r
+               $value = (float) $value;\r
+               $value = round($value, $round);\r
+               return $value;\r
+       }\r
+\r
+       protected function base62($val) {\r
+               $chars = '0123456789abcdefghijklmnopqrstuvwxyz';\r
+               $base = strlen($chars);\r
+               $str = '';\r
+               do {\r
+                       $i = $val % $base;\r
+                       $str = $chars[$i] . $str;\r
+                       $val = ($val - $i) / $base;\r
+               } while ($val > 0);\r
+               return $str;\r
+       }\r
+\r
+       public function copyLinkFile($source, $dest, $video=false) {\r
+               // TODO delete that return;\r
+               //return;\r
+               $origDir = WS_BOOKS . '/working/' . $this->book_id . '/';\r
+               $types = array('mp4', 'ogv', 'webm', 'jpg');\r
+               if ($video) {\r
+                       return;\r
+                       wsTools::encodeWebVideos($origDir . $source, null, false);\r
+                       $e = explode('.', $source);\r
+                       array_pop($e);\r
+                       $base = implode('.', $e);\r
+                       $source = array();\r
+                       foreach ($types as $type) {\r
+                               $source[] = $base . '.' . $type;\r
+                       }\r
+               }\r
+\r
+               if (!is_array($source)) {\r
+                       $source = array($source);\r
+               }\r
+\r
+               foreach ($source as $so) {\r
+                       $s = $origDir . $so;\r
+                       if (file_exists($s)) {\r
+                               $d = $this->vdir . '/' . $dest . '/' . $so;\r
+                               if (!file_exists(dirname($d))) {\r
+                                       mkdir(dirname($d), 0777, true);\r
+                               }\r
+                               copy($s, $d);\r
+                       }\r
+               }\r
+       }\r
+\r
+       public static function escapeHTML($in) {\r
+               $in = htmlentities($in, ENT_NOQUOTES, "UTF-8");\r
+               $in = str_replace('&thinsp;', '', $in);\r
+\r
+               return $in;\r
+       }\r
+\r
+       public function __destruct() {\r
+               \r
+       }\r
+\r
+       public static function colorToCSS($color, $forceAlpha=null) {\r
+\r
+               if (!is_null($forceAlpha)) {\r
+                       $a = $forceAlpha * 255;\r
+                       $a = base_convert($a, 10, 16);\r
+                       if (strlen($color) == 6) {\r
+                               $color = $a . $color;\r
+                       } else {\r
+                               $color = $a . substr($color, 2, 6);\r
+                       }\r
+               }\r
+\r
+               if (strlen($color) == 6) {\r
+                       return '#' . $color;\r
+               } else {\r
+                       $alpha = substr($color, 0, 2);\r
+                       $red = substr($color, 2, 2);\r
+                       $green = substr($color, 4, 2);\r
+                       $blue = substr($color, 6, 2);\r
+\r
+                       $components = array('alpha', 'red', 'green', 'blue');\r
+                       foreach ($components as $k => $name) {\r
+                               $hex = substr($color, $k * 2, 2);\r
+                               $$name = intval($hex, 16);\r
+                       }\r
+                       $alpha/=255;\r
+                       if ($alpha == 0) {\r
+                               return 'transparent';\r
+                       } elseif ($alpha == 1) {\r
+                               return '#' . substr($color, 2, 6);\r
+                       }\r
+                       return 'rgba(' . $red . ',' . $green . ',' . $blue . ',' . $alpha . ')';\r
+               }\r
+       }\r
+\r
+}\r
+\r
+?>
\ No newline at end of file