protected $ws_admin;\r
protected $ws_grade;\r
protected $ws_signatures;\r
+ protected $type;\r
// Composés\r
protected $ca;\r
protected $impaye;\r
$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
$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
--- /dev/null
+<?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";
+ }
+ }
+
+}
+
+?>
--- /dev/null
+<?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;
+ }
+
+}
+
+?>
<?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
+}
?>
--- /dev/null
+<?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(' ', '', $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
--- /dev/null
+<?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;
+ }
+
+}
+
+?>
--- /dev/null
+<?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(' ', '', $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