<?php\r
+\r
/**\r
* wsDocument\r
*\r
* @access public\r
*/\r
class wsDocument extends cubeMetier {\r
- protected $document_id;\r
- protected $file;\r
- protected $proprietaire;\r
- protected $pages;\r
- protected $trim;\r
- protected $date;\r
- protected $localInfos;\r
- protected $generalInfos;\r
- protected $conversionInfos;\r
- protected $bookmarks;\r
- protected $numberSections;\r
- protected $localHash;\r
- protected $version;\r
- // Crop & cut\r
- protected $autocrop;\r
- protected $manualcrop;\r
- protected $autocut;\r
- protected $manualcut;\r
- // Files\r
- protected $out;\r
- protected $in;\r
- protected $html;\r
- protected $uncompressed;\r
- protected $log;\r
- protected $common_log_pointer;\r
- protected $pages_log_pointers;\r
- protected $infos;\r
- protected $cropped;\r
- protected $uncropped;\r
-\r
- const NORMAL = 0;\r
- const FLATTEN = 1;\r
- const POLY2BITMAP = 2;\r
- const BITMAP = 3;\r
- const BARBARE_PNM = 4;\r
- const BARBARE_GS = 5;\r
-\r
- const MAX = 5;\r
-\r
- const PNM_FILL = 2;\r
-\r
- protected static $resolution2multiply = array(72 => 2, 100 => 2, 150 => 3, 200 => 3, 300 => 3, 450 => 4, 600 => 5);\r
- // Number section styles\r
- protected static\r
- $numberStyles = array('NoNumber' => 'no', 'DecimalArabicNumerals' => 'decimal',\r
- 'UppercaseRomanNumerals' => 'roman_up', 'LowercaseRomanNumerals' => 'roman_low',\r
- 'UppercaseLetters' => 'letters_up', 'LowercaseLetters' => 'letters_low');\r
-\r
- public function init()\r
- {\r
- $this->out = WS_DOCS . '/' . $this->document_id . '/';\r
- $this->log = $this->out . '/logs/';\r
- $this->html = $this->out . '/html/';\r
- $this->in = $this->out . 'original.pdf';\r
- $this->uncompressed = $this->out . 'uncompressed.pdf';\r
- $this->infos = $this->out . 'infos.txt';\r
- if (!file_exists($this->out)) {\r
- mkdir($this->out, 0755, true);\r
- mkdir($this->log, 0755);\r
- }\r
- if (!file_exists($this->html)) {\r
- mkdir($this->html, 0755);\r
- }\r
- $this->cropped = $this->out . 'crop.pdf';\r
- $this->uncropped = $this->out . 'uncrop.pdf';\r
- $this->common_log_pointer = fopen($this->log . '/commons.log', 'ab');\r
- $this->pages_log_pointers = array();\r
-\r
- if (is_null($this->conversionInfos)) {\r
- $this->conversionInfos = new wsDocumentConversionInfos();\r
- }\r
- }\r
-\r
- public function copyOriginalFromUpload($tmp_file)\r
- {\r
- move_uploaded_file($tmp_file, $this->in);\r
- $this->uncropDocument();\r
- }\r
-\r
- public function copyOriginalFromOlderVersion()\r
- {\r
- if (!file_exists($this->in)) {\r
- copy('http://ws.fluidbook.com/docs/' . $this->document_id . '/original.pdf', $this->in);\r
- }\r
- $this->uncropDocument();\r
- }\r
-\r
- public function extractFonts()\r
- {\r
- $out = $this->out . 'fonts/pdf';\r
- if (!file_exists($out)) {\r
- mkdir($out, 0777, true);\r
- }\r
- // Extract fonts from PDF\r
- $gs = new cubeCommandLine('gs');\r
- $gs->setPath(CONVERTER_PATH);\r
- $gs->cd($out);\r
- $gs->setArg('-dBATCH');\r
- $gs->setArg('-dNOPAUSE');\r
- $gs->setArg('-dNOPROMPT');\r
- $gs->setArg('-dNODISPLAY');\r
- $gs->setArg(null, WS_TOOLS . '/extractFonts.ps');\r
- $gs->setManualArg('-c "(' . $this->cropped . ') extractFonts quit"');\r
-\r
- $gs->execute();\r
- $this->addToLog($gs);\r
-\r
- $dr = opendir($out);\r
-\r
- if (!file_exists($this->out . '/fonts/web')) {\r
- mkdir($this->out . '/fonts/web', 0777, true);\r
- }\r
- $formats = array('ttf', 'woff', 'svg', 'svgz', 'eot');\r
- // Fonts conversion\r
- while ($file = readdir($dr)) {\r
- if ($file == '.' || $file == '..') {\r
- continue;\r
- }\r
-\r
- $e = explode('.', $file);\r
- array_pop($e);\r
- $fname = implode('.', $e);\r
-\r
- foreach($formats as $format) {\r
- if ($format == 'eot') {\r
- $ttf2eot = new cubeCommandLine('ttf2eot', $this->out . '/fonts/web/' . $fname . '.eot');\r
- $ttf2eot->setPath(CONVERTER_PATH);\r
- $ttf2eot->setManualArg('< ' . $this->out . '/fonts/web/' . $fname . '.ttf');\r
- $ttf2eot->execute();\r
- } else {\r
- $fontforge = new cubeCommandLine('convert.pe');\r
- $fontforge->setPath(CONVERTER_PATH);\r
- $fontforge->setArg(null, $out . '/' . $file);\r
- $fontforge->setArg(null, $this->out . '/fonts/web/' . $fname . '.' . $format);\r
- $fontforge->execute();\r
- $this->addToLog($fontforge);\r
- }\r
- }\r
- }\r
- }\r
-\r
- public function getInfos($in = null, $force = false)\r
- {\r
- if (is_null($in)) {\r
- $in = $this->in;\r
- }\r
-\r
- $fwstk = new cubeCommandLine('fwstk');\r
- $fwstk->setPath(CONVERTER_PATH);\r
- $fwstk->setArg('--input ' . $in);\r
- $fwstk->setArg('--infos');\r
- $fwstk->execute();\r
- $this->addToLog($fwstk);\r
- $this->parseInfos($fwstk->output);\r
-\r
- $this->conversionInfos->setPageNumber($this->generalInfos['pages']);\r
-\r
- file_put_contents($this->infos, $fwstk->output);\r
- $this->findCutDisposition();\r
- }\r
-\r
- public function findCutDisposition()\r
- {\r
- $this->detectSpreads();\r
- $this->detectPageDifferences();\r
- }\r
-\r
- protected function detectPageDifferences()\r
- {\r
- // Vérifie si la cropbox et la trimbox sont identiques pour toutes les pages\r
- $difference = false;\r
- foreach($this->generalInfos['page'] as $page => $infos) {\r
- if (!isset($infos['crop']) || !isset($infos['crop'])) {\r
- continue;\r
- }\r
- if ($infos['crop'] != $infos['trim']) {\r
- $difference = true;\r
- }\r
- }\r
- if (!$difference) {\r
- return false;\r
- }\r
- // Vérifie si la trimbox définie toutes les pages de la même taille\r
- $heights = array();\r
- $widths = array();\r
- foreach($this->generalInfos['page'] as $page => $infos) {\r
- $heights[] = round($infos['trim']->height);\r
- $widths[] = round($infos['trim']->width);\r
- }\r
- $heights = array_unique($heights);\r
- $widths = array_unique($widths);\r
- if (count($heights) == 1 && count($widths) == 1) {\r
- $this->autocrop = 'trim';\r
- $this->manualcrop = false;\r
- } else {\r
- $this->autocrop = false;\r
- $this->manualcrop = true;\r
- }\r
- }\r
-\r
- protected function detectSpreads()\r
- {\r
- // Détection des spreads\r
- foreach($this->generalInfos['page'] as $page => $infos) {\r
- if ($page == 1) {\r
- $first = $infos['size'];\r
- } elseif ($page == $this->generalInfos['pages']) {\r
- $last = $infos['size'];\r
- } elseif ($page == 2) {\r
- $second = $infos['size'];\r
- }\r
- }\r
-\r
- if ($first == $last && $last == $second) {\r
- $ratio = $first[0] / $first[1];\r
- $this->autocut = false;\r
- if ($ratio <= 1) {\r
- $this->manualcut = false;\r
- } elseif ($ratio >= 6) {\r
- $this->manualcut = 'L8';\r
- } elseif ($ratio >= 3) {\r
- $this->manualcut = 'L4';\r
- } elseif ($ratio >= 2) {\r
- $this->manualcut = 'L3';\r
- } else {\r
- $this->manualcut = '14-23';\r
- }\r
- return;\r
- }\r
- $this->manualcut = false;\r
- if ($first == $last && round($first[0] * 2) == round($second[0])) {\r
- $this->autocut = '1-23-4';\r
- }\r
- if (round($first[0] * 2) == round($second[0]) && $last == $second) {\r
- $this->autocut = '1-23';\r
- }\r
- }\r
-\r
- public function parseInfos($data)\r
- {\r
- // This function get general infos (pages sizes, boxes, number sections and\r
- // bookmarks\r
- // Init arrays\r
- $this->generalInfos = array();\r
- $this->generalInfos['size'] = array(0, 0);\r
- $this->bookmarks = array();\r
- $this->numberSections = '';\r
- $bookmark_id = 0;\r
-\r
- $res['size'] = array(0, 0);\r
- $lines = explode("\n", $data);\r
- foreach($lines as $line) {\r
- $line = trim(cubeText::condenseWhite($line));\r
- $e = explode(':', $line, 2);\r
- $k = trim($e[0]);\r
- if (count($e) < 2) {\r
- continue;\r
- }\r
- $v = trim($e[1]);\r
- if ($k == 'Pages' || $k == 'NumberOfPages') {\r
- $this->pages = $this->generalInfos['pages'] = $v;\r
- $this->generalInfos['page'] = array();\r
- for($i = 1;$i <= $this->pages;$i++) {\r
- $this->generalInfos['page'][$i] = array();\r
- }\r
- } elseif (preg_match('|Page ([0-9]+) (.*)Box: ([0-9.]*) ([0-9.]*) ([0-9.]*) ([0-9.]*)|iu', $line, $m)) {\r
- $this->generalInfos['page'][$m[1]][strtolower($m[2])] = new wsBox($m[3], $m[4], $m[5], $m[6]);\r
- } elseif (preg_match('|Page ([0-9]+) size: ([0-9.]*) pts x ([0-9.]*) pts|iu', $line, $m)) {\r
- $this->generalInfos['page'][$m[1]]['size'] = array($m[2], $m[3]);\r
- if ($m[1] == 1) {\r
- $this->generalInfos['size'][0] = $m[2];\r
- $this->generalInfos['size'][1] = $m[3];\r
- }\r
- } elseif ($k == 'BookmarkTitle') {\r
- $this->bookmarks[$bookmark_id] = array('titre' => str_replace(' ', '', trim($v)));\r
- } elseif ($k == 'BookmarkLevel') {\r
- $this->bookmarks[$bookmark_id]['level'] = $v;\r
- } elseif ($k == 'BookmarkPageNumber') {\r
- $this->bookmarks[$bookmark_id]['page'] = $v;\r
- $bookmark_id++;\r
- } elseif ($k == 'NumberSections') {\r
- $this->numberSections = $v;\r
- }\r
- }\r
-\r
- return $res;\r
- }\r
-\r
- public function getPagesNumber()\r
- {\r
- $this->getInfos();\r
- return $this->generalInfos['pages'];\r
- }\r
-\r
- public function globalOperations()\r
- {\r
- $this->getInfos();\r
- if ($this->CropAndCut()) {\r
- $this->getInfos($this->cropped, true);\r
- }\r
- $this->getLinksAndTexts();\r
- $this->extractFonts();\r
- }\r
-\r
- public function CropAndCut()\r
- {\r
- if (!$this->isCropped()) {\r
- copy($this->in, $this->cropped);\r
- return false;\r
- }\r
- if ($this->autocrop == 'trim') {\r
- $this->trimDocument();\r
- } else {\r
- copy($this->in, $this->cropped);\r
- }\r
-\r
- if ($this->autocut) {\r
- $this->cutDocument($this->autocut);\r
- return true;\r
- }\r
- return false;\r
- }\r
-\r
- public function cutDocument($mode)\r
- {\r
- $fwstk = new cubeCommandLine('fwstk');\r
- $fwstk->setPath(CONVERTER_PATH);\r
- $fwstk->setArg('--input ' . $this->in);\r
- $fwstk->setArg('--cut ' . $mode);\r
- $fwstk->setArg('--output ' . $this->cropped);\r
- $fwstk->execute();\r
- $this->addToLog($fwstk);\r
- }\r
-\r
- public function trimDocument()\r
- {\r
- $fwstk = new cubeCommandLine('fwstk');\r
- $fwstk->setPath(CONVERTER_PATH);\r
- $fwstk->setArg('--input ' . $this->in);\r
- $fwstk->setArg('--trim');\r
- $fwstk->setArg('--output ' . $this->cropped);\r
- $fwstk->execute();\r
- $this->addToLog($fwstk);\r
- }\r
-\r
- public function uncropDocument()\r
- {\r
- $fwstk = new cubeCommandLine('fwstk');\r
- $fwstk->setPath(CONVERTER_PATH);\r
- $fwstk->setArg('--input ' . $this->in);\r
- $fwstk->setArg('--reset');\r
- $fwstk->setArg('--output ' . $this->uncropped);\r
- $fwstk->execute();\r
- $this->addToLog($fwstk);\r
- }\r
-\r
- public function processOnePage($page, $force = true)\r
- {\r
- // $this->makeRealShot($page);\r
- if ($force) {\r
- $this->addToLog('Processing page #' . $page);\r
- $this->makeMiniShot($page);\r
- $this->makeSWFFiles($page);\r
- $this->makeHTML5Files($page);\r
- }\r
- }\r
-\r
- public function processAllPages()\r
- {\r
- for($i = 1;$i <= $this->generalInfos['pages'];$i++) {\r
- $this->processOnePage($i);\r
- }\r
- }\r
-\r
- public function processRange($pages)\r
- {\r
- foreach($pages as $i) {\r
- $this->processOnePage($i);\r
- }\r
- }\r
-\r
- public function getLinksAndTexts()\r
- {\r
- $fwstk = new cubeCommandLine('fwstk');\r
- $fwstk->setPath(CONVERTER_PATH);\r
- $fwstk->setArg('--input ' . $this->cropped);\r
- $fwstk->setArg('--extractTexts ' . $this->out . '%s%d.txt');\r
- $fwstk->setArg('--extractLinks ' . $this->out . 'p%d.csv');\r
- $fwstk->execute();\r
- $this->addToLog($fwstk);\r
-\r
- /*$temp = cubeFiles::tempnam();\r
- $pdftotext = new cubeCommandLine('pdftotext', null, true);\r
- $pdftotext->setPath(CONVERTER_PATH);\r
- $pdftotext->setArg('q');\r
- $pdftotext->setArg('-eol', 'unix');\r
- $pdftotext->setArg('-enc', 'UTF-8');\r
- $pdftotext->setArg(null, $this->cropped);\r
- $pdftotext->setArg(null, $temp);\r
- $pdftotext->execute();\r
- $this->addToLog($pdftotext);\r
-\r
- $pages = explode("\f", file_get_contents($temp));\r
- foreach($pages as $i => $page) {\r
- $i++;\r
- $txt = mb_strtolower($page);\r
- $txt = cubeText::removeAccents($txt);\r
- $txt = trim($txt);\r
-\r
- file_put_contents($this->out . 'p' . $i . '.txt', $txt);\r
- }\r
-\r
- unlink($temp);*/\r
- }\r
-\r
- public function makeMiniShot($page)\r
- {\r
- $this->makeShotFixedWidth($page, 'p', 100, 90, 4, 'PNM');\r
- }\r
-\r
- public function makeRealShot($page)\r
- {\r
- $this->makeShot($page, 'te', 150, 60, 4, 'GS', $this->uncropped);\r
- }\r
-\r
- public function makeShotFixedWidth($page , $prefix = '', $w = 100, $quality = 90, $antialiasing = 4, $method = 'PNM')\r
- {\r
- // Make thumbs of $w width\r
- // resolution 72 make 1pt=1px\r
- $width = $this->generalInfos['size'][0];\r
- $ratio = $width / $w;\r
- $this->makeShot($page, $prefix, round(72 / $ratio, 2), $quality, $antialiasing, $method);\r
- }\r
-\r
- public function makeShotFixedHeight($page , $prefix = '', $h = '', $quality = 90, $antialiasing = 4, $method = 'PNM')\r
- {\r
- // Make thumbs of $w height\r
- // resolution 72 make 1pt=1px\r
- $height = $this->generalInfos['size'][1];\r
- $ratio = $height / $h;\r
- $this->makeShot($page, $prefix, round(72 / $ratio, 2), $quality, $antialiasing, $method);\r
- }\r
-\r
- public function makeShot($page , $prefix = '', $resolution = 72, $quality = 90, $antialiasing = 4, $method = 'PNM', $in = null)\r
- {\r
- $error = false;\r
- if (is_null($in)) {\r
- $in = $this->cropped;\r
- }\r
- // Delete all old files\r
- $res = $this->out . $prefix . $page . '.jpg';\r
- if (file_exists($res)) {\r
- @unlink($res);\r
- }\r
-\r
- if ($method == 'GS') {\r
- $this->makeShotGS($page, $prefix, $resolution, $quality, $antialiasing, $in);\r
- } elseif ($method == 'PNM') {\r
- $this->makeShotPNM($page, $prefix, $resolution, $quality, $antialiasing, $in);\r
- }\r
- // Test the result by checking all files\r
- if (!file_exists($res)) {\r
- $error = true;\r
- }\r
- // If error, we try to make thumbs with other method\r
- if ($error) {\r
- if ($method == 'GS') {\r
- $this->makeShotPNM($page, $prefix, $resolution, $quality, $antialiasing, $in);\r
- } elseif ($method == 'PNM') {\r
- $this->makeShotGS($page, $prefix, $resolution, $quality, $antialiasing, $in);\r
- }\r
- }\r
- }\r
-\r
- protected function makeShotGS($page, $prefix = '', $resolution = 72, $quality = 90, $antialiasing = 4, $in = null)\r
- {\r
- if (is_null($in)) {\r
- $in = $this->cropped;\r
- }\r
- // Fabrication des thumbanails avec ghostscript\r
- $gs = new cubeCommandLine('gs', null, true);\r
- $gs->setPath(CONVERTER_PATH);\r
- $gs->setEnv('GS_FONTPATH', FONT_PATH);\r
- $gs->setArg('-dBATCH');\r
- $gs->setArg('-dNOPAUSE');\r
- $gs->setArg('-dNOPROMPT');\r
- // Antialias\r
- $gs->setArg('-dDOINTERPOLATE');\r
- $gs->setArg('-dTextAlphaBits=' . $antialiasing);\r
- $gs->setArg('-dGraphicsAlphaBits=' . $antialiasing);\r
- // Device\r
- $gs->setArg('-sDEVICE=jpeg');\r
- // Dispotion & colors\r
- // $gs->setArg('-dUseCIEColor');\r
- $gs->setArg('-dAutoRotatePages=/None');\r
- $gs->setArg('-dUseCropBox');\r
- // Resolution & Quality\r
- $gs->setArg('-r' . round($resolution));\r
- $gs->setArg('-dJPEGQ=' . $quality);\r
- // Performances\r
- $gs->setArg('-dNumRenderingThreads=4');\r
- // Page range\r
- $gs->setArg('-dFirstPage=' . $page);\r
- $gs->setArg('-dLastPage=' . $page);\r
- // Files\r
- $gs->setArg('-sOutputFile=' . $this->out . '/' . $prefix . $page . '.jpg');\r
-\r
- $gs->setArg(null, $in);\r
- $gs->execute();\r
- $this->addToLog($gs, true, $page);\r
- }\r
-\r
- protected function makeShotPNM($page, $prefix = '', $resolution = 72, $quality = 90, $antialiasing = 4, $in = null, $texts = true)\r
- {\r
- if (is_null($in)) {\r
- $in = $this->cropped;\r
- }\r
- $antialiasing = $antialiasing?'yes':'no';\r
- $freetype = $texts?'yes':'no';\r
- $resolution = round($resolution);\r
- // Exporte les fichiers\r
- $pdftoppm = new cubeCommandLine('pdftoppm', null, true);\r
- $pdftoppm->setPath(CONVERTER_PATH);\r
-\r
- $pdftoppm->setArg('f', $page);\r
- $pdftoppm->setArg('l', $page);\r
-\r
- $pdftoppm->setArg('-cropbox');\r
- $pdftoppm->setArg('-freetype ' . $freetype);\r
- $pdftoppm->setArg('-jpeg');\r
- $pdftoppm->setArg('-aa ' . $antialiasing);\r
- $pdftoppm->setArg('-aaVector ' . $antialiasing);\r
- $pdftoppm->setArg('r', $resolution);\r
- $pdftoppm->setArg(null, $in);\r
- $pdftoppm->setArg(null, $this->out . 'ppm');\r
- $pdftoppm->execute();\r
- $this->addToLog($pdftoppm, true, $page);\r
-\r
- $jpegfile = $this->out . $prefix . $page . '.jpg';\r
-\r
- $ppmjpgfile = $this->out . 'ppm-' . cubeMath::fill($page, strlen((string)$this->pages)) . '.jpg';\r
- if (file_exists($ppmjpgfile)) {\r
- rename($ppmjpgfile, $jpegfile);\r
- $this->addToLog('Move ' . $ppmjpgfile . ' to ' . $jpegfile, true, $page);\r
- }\r
- }\r
-\r
- protected function isCropped()\r
- {\r
- return $this->autocrop || $this->manualcrop || $this->autocut || $this->manualcut;\r
- }\r
-\r
- public function makeSWFFiles($page, $resolution = null, $quality = null, $storeAllChars = null, $maxObjects = 1800, $method = null)\r
- {\r
- $conversionSettings = $this->conversionInfos->pages[$page];\r
- if (is_null($storeAllChars)) {\r
- $storeAllChars = true;\r
- }\r
- if (is_null($resolution)) {\r
- $resolution = $conversionSettings->resolution;\r
- }\r
- if (is_null($method)) {\r
- $method = $conversionSettings->method;\r
- }\r
- if (is_null($quality)) {\r
- $quality = $conversionSettings->quality;\r
- }\r
- if (is_null($maxObjects)) {\r
- $maxObjects = $conversionSettings->objects;\r
- }\r
-\r
- if ($maxObjects <= 1) {\r
- $method = self::POLY2BITMAP;\r
- }\r
- // Pour les fichiers croppés, on utilise la méthode flatten qui ne prends\r
- // pas en compte les objets hors de la box\r
- if ($this->isCropped()) {\r
- // $method = max($method, self::FLATTEN);\r
- }\r
-\r
- $out = $this->pdf2swf($page, $resolution, $quality, $storeAllChars, $method);\r
- if ($method < self::BARBARE_PNM) {\r
- // Analyse de la sortie pour détecter des typos manquantes\r
- $overflow = false;\r
- $overflowObjects = false;\r
- $written = false;\r
- $missing_fonts = array();\r
- if (file_exists($out)) {\r
- $fp = fopen($out, 'rb');\r
- while ($line = fgets($fp)) {\r
- if (preg_match('|Try putting a TTF version of that font \(named \"([A-Z-_0-9.]*)\"\)|Uui', trim($line), $matches)) {\r
- $missing_fonts[] = $matches[1];\r
- } elseif (stristr($line, 'ID Table overflow')) {\r
- $overflow = true;\r
- } elseif (stristr($line, 'NOTICE SWF written')) {\r
- $written = true;\r
- } elseif (stristr($line, 'NOTICE Writing SWF file')) {\r
- $written = true;\r
- }\r
- }\r
- }\r
- if (!is_null($page) && file_exists($this->out . 'p' . $page . '.swf')) {\r
- $written = true;\r
- }\r
- // On teste si le fichier est écrit et qu'il a été généré par le premier niveau\r
- if ($method < self::POLY2BITMAP && $written) {\r
- $overflowObjects = $this->checkObjectsNumber($this->out . 'p' . $page . '.swf', $maxObjects, $page);\r
- }\r
-\r
- if (!$written || $overflow || $overflowObjects) {\r
- if ($method == self::MAX) {\r
- return;\r
- }\r
- $nextMethod = $method + 1;\r
- return $this->makeSWFFiles($page, $resolution, $quality, $storeAllChars, $maxObjects, $nextMethod);\r
- }\r
- }\r
- }\r
-\r
- public function makeHTML5Files($page)\r
- {\r
- // First, make swf with polytobitmap to rasterize bitmap & vectors\r
- $this->pdf2swf($page, 72, 80, true, self::POLY2BITMAP, 'h');\r
- // Then get the special unicode dump\r
- $dump = $this->dumpSWF($page, 'h');\r
- // Then, process it\r
- $swf2html = new wsSWF2HTML($dump);\r
- $swf2html->process();\r
- $this->addToLog(print_r($swf2html, true), true, $page);\r
- file_put_contents($this->html . '/p' . $page . '.obj', serialize($swf2html));\r
- // Then make HD background shots\r
- $resolutions = array(36 => 80, 72 => 70, 150 => 50);\r
- foreach($resolutions as $r => $q) {\r
- $this->makeShotPNM($page, 'html/h' . $r . '-', $r, $q, 4, null, false);\r
- }\r
- }\r
-\r
- protected function checkObjectsNumber($file, $maxObjects, $page)\r
- {\r
- $swfdump = new cubeCommandLine('swfdump', null, true);\r
- $swfdump->setPath(CONVERTER_PATH);\r
- $swfdump->setArg(null, $file);\r
- $swfdump->execute();\r
- $this->addToLog($swfdump, true, $page);\r
-\r
- str_replace('[01a]', '', $swfdump->output, $nbObjects);\r
- if ($nbObjects > $maxObjects) {\r
- return true;\r
- }\r
- return false;\r
- }\r
-\r
- protected function dumpSWF($page, $prefix = 'p')\r
- {\r
- $swfdump = new cubeCommandLine('/usr/local/swftools/special-swfdump/bin/swfdump', null, true);\r
- $swfdump->setPath(CONVERTER_PATH);\r
- $swfdump->setArg('t');\r
- $swfdump->setArg('p');\r
- $swfdump->setArg('F');\r
- $swfdump->setArg(null, $this->out . $prefix . $page . '.swf');\r
- $swfdump->execute();\r
- $this->addToLog($swfdump, false, $page);\r
- return $swfdump->output;\r
- }\r
-\r
- /**\r
- * wsDocument::pdf2swf()\r
- *\r
- * @param mixed $page\r
- * @param integer $resolution\r
- * @param integer $quality\r
- * @param mixed $storeAllChars\r
- * @param integer $method\r
- * @return\r
- */\r
- protected function pdf2swf($page , $resolution = 150, $quality = 90, $storeAllChars = true, $method = 0, $prefix = 'p')\r
- {\r
- /*\r
--h , --help Print short help message and exit\r
--V , --version Print version info and exit\r
--o , --output file.swf Direct output to file.swf. If file.swf contains '%' (file%.swf), then each page goes to a seperate file.\r
--p , --pages range Convert only pages in range with range e.g. 1-20 or 1,4,6,9-11 or\r
--P , --password password Use password for deciphering the pdf.\r
--v , --verbose Be verbose. Use more than one -v for greater effect.\r
--z , --zlib Use Flash 6 (MX) zlib compression.\r
--i , --ignore Allows pdf2swf to change the draw order of the pdf. This may make the generated\r
--j , --jpegquality quality Set quality of embedded jpeg pictures to quality. 0 is worst (small), 100 is best (big). (default:85)\r
--s , --set param=value Set a SWF encoder specific parameter. See pdf2swf -s help for more information.\r
--w , --samewindow When converting pdf hyperlinks, don't make the links open a new window.\r
--t , --stop Insert a stop() command in each page.\r
--T , --flashversion num Set Flash Version in the SWF header to num.\r
--F , --fontdir directory Add directory to the font search path.\r
--b , --defaultviewer Link a standard viewer to the swf file.\r
--l , --defaultloader Link a standard preloader to the swf file which will be displayed while the main swf is loading.\r
--B , --viewer filename Link viewer filename to the swf file.\r
--L , --preloader filename Link preloader filename to the swf file.\r
--q , --quiet Suppress normal messages. Use -qq to suppress warnings, also.\r
--S , --shapes Don't use SWF Fonts, but store everything as shape.\r
--f , --fonts Store full fonts in SWF. (Don't reduce to used characters).\r
--G , --flatten Remove as many clip layers from file as possible.\r
--I , --info Don't do actual conversion, just display a list of all pages in the PDF.\r
--Q , --maxtime n Abort conversion after n seconds. Only availableon Unix.\r
-\r
-PDF device global parameters:\r
------------------------------\r
-fontdir=<dir> a directory with additional fonts\r
-font=<filename> an additional font filename\r
-pages=<range> the range of pages to convert (example: pages=1-100,210-)\r
-zoom=<dpi> the resultion (default: 72)\r
-languagedir=<dir> Add an xpdf language directory\r
-multiply=<times> Render everything at <times> the resolution\r
-poly2bitmap Convert graphics to bitmaps\r
-bitmap Convert everything to bitmaps\r
-\r
-SWF Parameters :\r
-----------------\r
-SWF layer options :\r
--------------------\r
-\r
-jpegsubpixels=<pixels> resolution adjustment for jpeg images (same as jpegdpi, but in pixels)\r
-ppmsubpixels=<pixels resolution adjustment for lossless images (same asppmdpi, but in pixels)\r
-subpixels=<pixels> shortcut for setting both jpegsubpixels and ppmsubpixels\r
-drawonlyshapes convert everything to shapes (currently broken)\r
-ignoredraworder allow to perform a few optimizations for creating smaller SWFs\r
-linksopennewwindow make links open a new browser window\r
-linktarget target window name of new links\r
-linkcolor=<color) color of links (format: RRGGBBAA)\r
-linknameurl Link buttons will be named like the URL they refer to (handy for iterating through links with actionscript)\r
-storeallcharacters don't reduce the fonts to used characters in the output file\r
-enablezlib switch on zlib compression (also done if flashversion>=7)\r
-bboxvars store the bounding box of the SWF file in actionscript variables\r
-dots Take care to handle dots correctly\r
-reordertags=0/1 (default: 1) perform some tag optimizations\r
-internallinkfunction=<name> when the user clicks a internal link (to a different page) in the converted file, this actionscript function is called\r
-externallinkfunction=<name> when the user clicks an external link (e.g. http://www.foo.bar/) on the converted file, this actionscript function is called\r
-disable_polygon_conversion never convert strokes to polygons (will remove capstyles and joint styles)\r
-caplinewidth=<width> the minimum thichness a line needs to have so that capstyles become visible (and are converted)\r
-insertstop put an ActionScript "STOP" tag in every frame\r
-protect add a "protect" tag to the file, to prevent loading in the Flash editor\r
-flashversion=<version> the SWF fileversion (6)\r
-framerate=<fps> SWF framerate\r
-minlinewidth=<width> convert horizontal/vertical boxes smaller than this width to lines (0.05)\r
-simpleviewer Add next/previous buttons to the SWF\r
-animate insert a showframe tag after each placeobject (animate draw order of PDF files)\r
-jpegquality=<quality> set compression quality of jpeg images\r
-splinequality=<value> Set the quality of spline convertion to value (0-100, default: 100).\r
-disablelinks Disable links.\r
- */\r
-\r
- if (file_exists($this->out . $prefix . $page . '.swf')) {\r
- unlink($this->out . $prefix . $page . '.swf');\r
- }\r
-\r
- if (!in_array($method, array(self::BARBARE_PNM, self::BARBARE_GS))) {\r
- $pdf2swf = new cubeCommandLine('pdf2swf', null, true);\r
- $pdf2swf->setPath(CONVERTER_PATH);\r
-\r
- $pdf2swf->setArg('p', $page);\r
-\r
- if ($method == self::NORMAL) {\r
- // Default\r
- $multiply = 1;\r
- } elseif ($method == self::FLATTEN) {\r
- $pdf2swf->setArg('flatten');\r
- $multiply = 1;\r
- } elseif ($method == self::POLY2BITMAP) {\r
- // Raster graphics, keep texts\r
- $pdf2swf->setArg('set poly2bitmap');\r
- $multiply = self::$resolution2multiply[$resolution];\r
- $pdf2swf->setArg('set multiply', $multiply);\r
- } elseif ($method == self::BITMAP) {\r
- // Raster all\r
- $pdf2swf->setArg('set bitmap');\r
- $multiply = self::$resolution2multiply[$resolution];\r
- $pdf2swf->setArg('set multiply', $multiply);\r
- }\r
-\r
- $pdf2swf->setArg('stop');\r
- // $pdf2swf->setManualArg('-v');\r
- $pdf2swf->setArg('T', 10);\r
- $pdf2swf->setArg('set reordertags', '0');\r
- if ($storeAllChars) {\r
- $pdf2swf->setArg('fonts');\r
- $pdf2swf->setArg('set storeallcharacters');\r
- }\r
- if (DEV) {\r
- $pdf2swf->setArg('F', 'C:/Windows/Fonts');\r
- } else {\r
- $pdf2swf->setArg('F', '/home/typo/fonts');\r
- }\r
- $pdf2swf->setArg('set subpixels', $resolution / 72);\r
- $pdf2swf->setArg('set jpegquality', $quality);\r
- $pdf2swf->setArg('set disablelinks');\r
- $pdf2swf->setArg('set dots');\r
- // $pdf2swf->setManualArg('-vvv');\r
- $pdf2swf->setArg(null, $this->cropped);\r
- $pdf2swf->setArg('output', $this->out . $prefix . '%.swf');\r
- $pdf2swf->execute();\r
-\r
- $this->addToLog($pdf2swf, true, $page);\r
- } else {\r
- $this->pdf2swfBarbare($page, $resolution, $quality, $method);\r
- }\r
- }\r
-\r
- protected function makeAS3($page)\r
- {\r
- $swffile = $this->out . 'p' . $page . '.swf';\r
-\r
- $swfcombine = new cubeCommandLine('swfcombine');\r
- $swfcombine->setPath(CONVERTER_PATH);\r
- $swfcombine->setArg('merge');\r
- $swfcombine->setArg('stack1');\r
- $swfcombine->setArg('z');\r
- $swfcombine->setManualArg('-v');\r
- $swfcombine->setArg('o', $swffile);\r
- $swfcombine->setArg(null, ROOT . '/swf/as3Container.swf');\r
- $swfcombine->setManualArg('content=' . $swffile);\r
- $swfcombine->execute();\r
- $this->addToLog($swfcombine, true, $page);\r
- }\r
-\r
- protected function pdf2swfBarbare($page, $resolution = 150, $quality = 85, $method = 4)\r
- {\r
- // Fabrique les images\r
- if ($method == self::BARBARE_PNM) {\r
- $this->makeShot($page, 'barbare', $resolution, $quality, 4, 'PNM');\r
- } elseif ($method == self::BARBARE_GS) {\r
- $this->makeShot($page, 'barbare', $resolution, $quality, 4, 'GS');\r
- }\r
- // A partir des images, on crée les swf\r
- $jpeg2swf = new cubeCommandLine('jpeg2swf');\r
- $jpeg2swf->setPath(CONVERTER_PATH);\r
- $jpeg2swf->setArg('--quality', $quality);\r
- $jpeg2swf->setArg('--output', $this->out . 'p' . $page . '.swf');\r
- $jpeg2swf->setArg('--fit-to-movie');\r
- $jpeg2swf->setArg('--flashversion', 9);\r
- $jpeg2swf->setArg(null, $this->out . 'barbare' . $page . '.jpg');\r
- $jpeg2swf->execute();\r
- $this->addToLog($jpeg2swf, true, $page);\r
- // Suppression du jpeg\r
- @unlink($this->out . '/barbare' . $page . '.jpg', true, $page) ;\r
-\r
- return '';\r
- }\r
-\r
- public function addToLog($cl, $output = true, $page = null)\r
- {\r
- if ($cl instanceof cubeCommandLine) {\r
- $c = '--- Exécuté en ' . $cl->execTime . " s\n" . $cl->commande . "\n\n";\r
- if ($output) {\r
- $c .= $cl->output . "\n\n";\r
- }\r
- } elseif (is_string($cl)) {\r
- $c = '--- ' . "\n\n";\r
- $c .= $cl . "\n\n";\r
- }\r
-\r
- if (is_null($page)) {\r
- $pointer = $this->common_log_pointer;\r
- } else {\r
- if (isset($this->pages_log_pointers[$page]) && is_resource($this->pages_log_pointers[$page])) {\r
- $pointer = $this->pages_log_pointers[$page];\r
- } else {\r
- $pointer = fopen($this->log . '/p' . $page . '.log', 'wb');\r
- $this->pages_log_pointers[$page] = $pointer;\r
- }\r
- }\r
-\r
- fwrite($pointer, $c);\r
- }\r
- public function __destruct()\r
- {\r
- if (isset($this->common_log_pointer) && is_resource($this->common_log_pointer)) {\r
- fclose($this->common_log_pointer);\r
- }\r
-\r
- foreach($this->pages_log_pointers as $p) {\r
- if (!is_null($p) && is_resource($p)) {\r
- fclose($p);\r
- }\r
- }\r
- }\r
+\r
+ protected $document_id;\r
+ protected $file;\r
+ protected $proprietaire;\r
+ protected $pages;\r
+ protected $trim;\r
+ protected $date;\r
+ protected $localInfos;\r
+ protected $generalInfos;\r
+ protected $conversionInfos;\r
+ protected $bookmarks;\r
+ protected $numberSections;\r
+ protected $localHash;\r
+ protected $version;\r
+ // Crop & cut\r
+ protected $autocrop;\r
+ protected $manualcrop;\r
+ protected $autocut;\r
+ protected $manualcut;\r
+ // Files\r
+ protected $out;\r
+ protected $in;\r
+ protected $html;\r
+ protected $uncompressed;\r
+ protected $log;\r
+ protected $common_log_pointer;\r
+ protected $pages_log_pointers;\r
+ protected $infos;\r
+ protected $cropped;\r
+ protected $uncropped;\r
+\r
+ const NORMAL = 0;\r
+ const FLATTEN = 1;\r
+ const POLY2BITMAP = 2;\r
+ const BITMAP = 3;\r
+ const BARBARE_PNM = 4;\r
+ const BARBARE_GS = 5;\r
+\r
+ const MAX = 5;\r
+\r
+ const PNM_FILL = 2;\r
+\r
+ protected static $resolution2multiply = array(72 => 2, 100 => 2, 150 => 3, 200 => 3, 300 => 3, 450 => 4, 600 => 5);\r
+ // Number section styles\r
+ protected static\r
+ $numberStyles = array('NoNumber' => 'no', 'DecimalArabicNumerals' => 'decimal',\r
+ 'UppercaseRomanNumerals' => 'roman_up', 'LowercaseRomanNumerals' => 'roman_low',\r
+ 'UppercaseLetters' => 'letters_up', 'LowercaseLetters' => 'letters_low');\r
+\r
+ public function init() {\r
+ $this->out = WS_DOCS . '/' . $this->document_id . '/';\r
+ $this->log = $this->out . '/logs/';\r
+ $this->html = $this->out . '/html/';\r
+ $this->in = $this->out . 'original.pdf';\r
+ $this->uncompressed = $this->out . 'uncompressed.pdf';\r
+ $this->infos = $this->out . 'infos.txt';\r
+ if (!file_exists($this->out)) {\r
+ mkdir($this->out, 0755, true);\r
+ mkdir($this->log, 0755);\r
+ }\r
+ if (!file_exists($this->html)) {\r
+ mkdir($this->html, 0755);\r
+ }\r
+ $this->cropped = $this->out . 'crop.pdf';\r
+ $this->uncropped = $this->out . 'uncrop.pdf';\r
+ $this->common_log_pointer = fopen($this->log . '/commons.log', 'ab');\r
+ $this->pages_log_pointers = array();\r
+\r
+ if (is_null($this->conversionInfos)) {\r
+ $this->conversionInfos = new wsDocumentConversionInfos();\r
+ }\r
+ }\r
+\r
+ public function copyOriginalFromUpload($tmp_file) {\r
+ move_uploaded_file($tmp_file, $this->in);\r
+ $this->uncropDocument();\r
+ }\r
+\r
+ public function copyOriginalFromOlderVersion() {\r
+ if (!file_exists($this->in)) {\r
+ copy('http://ws.fluidbook.com/docs/' . $this->document_id . '/original.pdf', $this->in);\r
+ }\r
+ $this->uncropDocument();\r
+ }\r
+\r
+ public function extractFonts() {\r
+ $out = $this->out . 'fonts/pdf';\r
+ if (!file_exists($out)) {\r
+ mkdir($out, 0777, true);\r
+ }\r
+ // Extract fonts from PDF\r
+ $gs = new cubeCommandLine('gs');\r
+ $gs->setPath(CONVERTER_PATH);\r
+ $gs->cd($out);\r
+ $gs->setArg('-dBATCH');\r
+ $gs->setArg('-dNOPAUSE');\r
+ $gs->setArg('-dNOPROMPT');\r
+ $gs->setArg('-dNODISPLAY');\r
+ $gs->setArg(null, WS_TOOLS . '/extractFonts.ps');\r
+ $gs->setManualArg('-c "(' . $this->cropped . ') extractFonts quit"');\r
+\r
+ $gs->execute();\r
+ $this->addToLog($gs);\r
+\r
+ $dr = opendir($out);\r
+\r
+ if (!file_exists($this->out . '/fonts/web')) {\r
+ mkdir($this->out . '/fonts/web', 0777, true);\r
+ }\r
+ $formats = array('ttf', 'woff', 'svg', 'svgz', 'eot');\r
+ // Fonts conversion\r
+ while ($file = readdir($dr)) {\r
+ if ($file == '.' || $file == '..') {\r
+ continue;\r
+ }\r
+\r
+ $e = explode('.', $file);\r
+ array_pop($e);\r
+ $fname = implode('.', $e);\r
+\r
+ foreach ($formats as $format) {\r
+ if ($format == 'eot') {\r
+ $ttf2eot = new cubeCommandLine('ttf2eot', $this->out . '/fonts/web/' . $fname . '.eot');\r
+ $ttf2eot->setPath(CONVERTER_PATH);\r
+ $ttf2eot->setManualArg('< ' . $this->out . '/fonts/web/' . $fname . '.ttf');\r
+ $ttf2eot->execute();\r
+ } else {\r
+ $fontforge = new cubeCommandLine('convert.pe');\r
+ $fontforge->setPath(CONVERTER_PATH);\r
+ $fontforge->setArg(null, $out . '/' . $file);\r
+ $fontforge->setArg(null, $this->out . '/fonts/web/' . $fname . '.' . $format);\r
+ $fontforge->execute();\r
+ $this->addToLog($fontforge);\r
+ }\r
+ }\r
+ }\r
+ }\r
+\r
+ public function getInfos($in = null, $force = false) {\r
+ if (is_null($in)) {\r
+ $in = $this->in;\r
+ }\r
+\r
+ $fwstk = new cubeCommandLine('fwstk');\r
+ $fwstk->setPath(CONVERTER_PATH);\r
+ $fwstk->setArg('--input ' . $in);\r
+ $fwstk->setArg('--infos');\r
+ $fwstk->execute();\r
+ $this->addToLog($fwstk);\r
+ $this->parseInfos($fwstk->output);\r
+\r
+ $this->conversionInfos->setPageNumber($this->generalInfos['pages']);\r
+\r
+ file_put_contents($this->infos, $fwstk->output);\r
+ $this->findCutDisposition();\r
+ }\r
+\r
+ public function findCutDisposition() {\r
+ $this->detectSpreads();\r
+ $this->detectPageDifferences();\r
+ }\r
+\r
+ protected function detectPageDifferences() {\r
+ // Vérifie si la cropbox et la trimbox sont identiques pour toutes les pages\r
+ $difference = false;\r
+ foreach ($this->generalInfos['page'] as $page => $infos) {\r
+ if (!isset($infos['crop']) || !isset($infos['crop'])) {\r
+ continue;\r
+ }\r
+ if ($infos['crop'] != $infos['trim']) {\r
+ $difference = true;\r
+ }\r
+ }\r
+ if (!$difference) {\r
+ return false;\r
+ }\r
+ // Vérifie si la trimbox définie toutes les pages de la même taille\r
+ $heights = array();\r
+ $widths = array();\r
+ foreach ($this->generalInfos['page'] as $page => $infos) {\r
+ $heights[] = round($infos['trim']->height);\r
+ $widths[] = round($infos['trim']->width);\r
+ }\r
+ $heights = array_unique($heights);\r
+ $widths = array_unique($widths);\r
+ if (count($heights) == 1 && count($widths) == 1) {\r
+ $this->autocrop = 'trim';\r
+ $this->manualcrop = false;\r
+ } else {\r
+ $this->autocrop = false;\r
+ $this->manualcrop = true;\r
+ }\r
+ }\r
+\r
+ protected function detectSpreads() {\r
+ // Détection des spreads\r
+ foreach ($this->generalInfos['page'] as $page => $infos) {\r
+ if ($page == 1) {\r
+ $first = $infos['size'];\r
+ } elseif ($page == $this->generalInfos['pages']) {\r
+ $last = $infos['size'];\r
+ } elseif ($page == 2) {\r
+ $second = $infos['size'];\r
+ }\r
+ }\r
+\r
+ if ($first == $last && $last == $second) {\r
+ $ratio = $first[0] / $first[1];\r
+ $this->autocut = false;\r
+ if ($ratio <= 1) {\r
+ $this->manualcut = false;\r
+ } elseif ($ratio >= 6) {\r
+ $this->manualcut = 'L8';\r
+ } elseif ($ratio >= 3) {\r
+ $this->manualcut = 'L4';\r
+ } elseif ($ratio >= 2) {\r
+ $this->manualcut = 'L3';\r
+ } else {\r
+ $this->manualcut = '14-23';\r
+ }\r
+ return;\r
+ }\r
+ $this->manualcut = false;\r
+ if ($first == $last && round($first[0] * 2) == round($second[0])) {\r
+ $this->autocut = '1-23-4';\r
+ }\r
+ if (round($first[0] * 2) == round($second[0]) && $last == $second) {\r
+ $this->autocut = '1-23';\r
+ }\r
+ }\r
+\r
+ public function parseInfos($data) {\r
+ // This function get general infos (pages sizes, boxes, number sections and\r
+ // bookmarks\r
+ // Init arrays\r
+ $this->generalInfos = array();\r
+ $this->generalInfos['size'] = array(0, 0);\r
+ $this->bookmarks = array();\r
+ $this->numberSections = '';\r
+ $bookmark_id = 0;\r
+\r
+ $res['size'] = array(0, 0);\r
+ $lines = explode("\n", $data);\r
+ foreach ($lines as $line) {\r
+ $line = trim(cubeText::condenseWhite($line));\r
+ $e = explode(':', $line, 2);\r
+ $k = trim($e[0]);\r
+ if (count($e) < 2) {\r
+ continue;\r
+ }\r
+ $v = trim($e[1]);\r
+ if ($k == 'Pages' || $k == 'NumberOfPages') {\r
+ $this->pages = $this->generalInfos['pages'] = $v;\r
+ $this->generalInfos['page'] = array();\r
+ for ($i = 1; $i <= $this->pages; $i++) {\r
+ $this->generalInfos['page'][$i] = array();\r
+ }\r
+ } elseif (preg_match('|Page ([0-9]+) (.*)Box: ([0-9.]*) ([0-9.]*) ([0-9.]*) ([0-9.]*)|iu', $line, $m)) {\r
+ $this->generalInfos['page'][$m[1]][strtolower($m[2])] = new wsBox($m[3], $m[4], $m[5], $m[6]);\r
+ } elseif (preg_match('|Page ([0-9]+) size: ([0-9.]*) pts x ([0-9.]*) pts|iu', $line, $m)) {\r
+ $this->generalInfos['page'][$m[1]]['size'] = array($m[2], $m[3]);\r
+ if ($m[1] == 1) {\r
+ $this->generalInfos['size'][0] = $m[2];\r
+ $this->generalInfos['size'][1] = $m[3];\r
+ }\r
+ } elseif ($k == 'BookmarkTitle') {\r
+ $this->bookmarks[$bookmark_id] = array('titre' => str_replace(' ', '', trim($v)));\r
+ } elseif ($k == 'BookmarkLevel') {\r
+ $this->bookmarks[$bookmark_id]['level'] = $v;\r
+ } elseif ($k == 'BookmarkPageNumber') {\r
+ $this->bookmarks[$bookmark_id]['page'] = $v;\r
+ $bookmark_id++;\r
+ } elseif ($k == 'NumberSections') {\r
+ $this->numberSections = $v;\r
+ }\r
+ }\r
+\r
+ return $res;\r
+ }\r
+\r
+ public function getPagesNumber() {\r
+ $this->getInfos();\r
+ return $this->generalInfos['pages'];\r
+ }\r
+\r
+ public function globalOperations() {\r
+ $this->getInfos();\r
+ if ($this->CropAndCut()) {\r
+ $this->getInfos($this->cropped, true);\r
+ }\r
+ $this->getLinksAndTexts();\r
+ $this->extractFonts();\r
+ }\r
+\r
+ public function CropAndCut() {\r
+ if (!$this->isCropped()) {\r
+ copy($this->in, $this->cropped);\r
+ return false;\r
+ }\r
+ if ($this->autocrop == 'trim') {\r
+ $this->trimDocument();\r
+ } else {\r
+ copy($this->in, $this->cropped);\r
+ }\r
+\r
+ if ($this->autocut) {\r
+ $this->cutDocument($this->autocut);\r
+ return true;\r
+ }\r
+ return false;\r
+ }\r
+\r
+ public function cutDocument($mode) {\r
+ $fwstk = new cubeCommandLine('fwstk');\r
+ $fwstk->setPath(CONVERTER_PATH);\r
+ $fwstk->setArg('--input ' . $this->in);\r
+ $fwstk->setArg('--cut ' . $mode);\r
+ $fwstk->setArg('--output ' . $this->cropped);\r
+ $fwstk->execute();\r
+ $this->addToLog($fwstk);\r
+ }\r
+\r
+ public function trimDocument() {\r
+ $fwstk = new cubeCommandLine('fwstk');\r
+ $fwstk->setPath(CONVERTER_PATH);\r
+ $fwstk->setArg('--input ' . $this->in);\r
+ $fwstk->setArg('--trim');\r
+ $fwstk->setArg('--output ' . $this->cropped);\r
+ $fwstk->execute();\r
+ $this->addToLog($fwstk);\r
+ }\r
+\r
+ public function uncropDocument() {\r
+ $fwstk = new cubeCommandLine('fwstk');\r
+ $fwstk->setPath(CONVERTER_PATH);\r
+ $fwstk->setArg('--input ' . $this->in);\r
+ $fwstk->setArg('--reset');\r
+ $fwstk->setArg('--output ' . $this->uncropped);\r
+ $fwstk->execute();\r
+ $this->addToLog($fwstk);\r
+ }\r
+\r
+ public function processOnePage($page, $force = true) {\r
+ // $this->makeRealShot($page);\r
+ if ($force) {\r
+ $this->addToLog('Processing page #' . $page);\r
+ $this->makeMiniShot($page);\r
+ $this->makeSWFFiles($page);\r
+ $this->makeHTML5Files($page);\r
+ }\r
+ }\r
+\r
+ public function processAllPages() {\r
+ for ($i = 1; $i <= $this->generalInfos['pages']; $i++) {\r
+ $this->processOnePage($i);\r
+ }\r
+ }\r
+\r
+ public function processRange($pages) {\r
+ foreach ($pages as $i) {\r
+ $this->processOnePage($i);\r
+ }\r
+ }\r
+\r
+ public function getLinksAndTexts() {\r
+ $fwstk = new cubeCommandLine('fwstk');\r
+ $fwstk->setPath(CONVERTER_PATH);\r
+ $fwstk->setArg('--input ' . $this->cropped);\r
+ $fwstk->setArg('--extractTexts ' . $this->out . '%s%d.txt');\r
+ $fwstk->setArg('--extractLinks ' . $this->out . 'p%d.csv');\r
+ $fwstk->setArg('--layout '.$this->html.'p%d.layout');\r
+ $fwstk->execute();\r
+ $this->addToLog($fwstk);\r
+\r
+ /* $temp = cubeFiles::tempnam();\r
+ $pdftotext = new cubeCommandLine('pdftotext', null, true);\r
+ $pdftotext->setPath(CONVERTER_PATH);\r
+ $pdftotext->setArg('q');\r
+ $pdftotext->setArg('-eol', 'unix');\r
+ $pdftotext->setArg('-enc', 'UTF-8');\r
+ $pdftotext->setArg(null, $this->cropped);\r
+ $pdftotext->setArg(null, $temp);\r
+ $pdftotext->execute();\r
+ $this->addToLog($pdftotext);\r
+\r
+ $pages = explode("\f", file_get_contents($temp));\r
+ foreach($pages as $i => $page) {\r
+ $i++;\r
+ $txt = mb_strtolower($page);\r
+ $txt = cubeText::removeAccents($txt);\r
+ $txt = trim($txt);\r
+\r
+ file_put_contents($this->out . 'p' . $i . '.txt', $txt);\r
+ }\r
+\r
+ unlink($temp); */\r
+ }\r
+\r
+ public function makeMiniShot($page) {\r
+ $this->makeShotFixedWidth($page, 'p', 100, 90, 4, 'PNM');\r
+ }\r
+\r
+ public function makeRealShot($page) {\r
+ $this->makeShot($page, 'te', 150, 60, 4, 'GS', $this->uncropped);\r
+ }\r
+\r
+ public function makeShotFixedWidth($page, $prefix = '', $w = 100, $quality = 90, $antialiasing = 4, $method = 'PNM') {\r
+ // Make thumbs of $w width\r
+ // resolution 72 make 1pt=1px\r
+ $width = $this->generalInfos['size'][0];\r
+ $ratio = $width / $w;\r
+ $this->makeShot($page, $prefix, round(72 / $ratio, 2), $quality, $antialiasing, $method);\r
+ }\r
+\r
+ public function makeShotFixedHeight($page, $prefix = '', $h = '', $quality = 90, $antialiasing = 4, $method = 'PNM') {\r
+ // Make thumbs of $w height\r
+ // resolution 72 make 1pt=1px\r
+ $height = $this->generalInfos['size'][1];\r
+ $ratio = $height / $h;\r
+ $this->makeShot($page, $prefix, round(72 / $ratio, 2), $quality, $antialiasing, $method);\r
+ }\r
+\r
+ public function makeShot($page, $prefix = '', $resolution = 72, $quality = 90, $antialiasing = 4, $method = 'PNM', $in = null) {\r
+ $error = false;\r
+ if (is_null($in)) {\r
+ $in = $this->cropped;\r
+ }\r
+ // Delete all old files\r
+ $res = $this->out . $prefix . $page . '.jpg';\r
+ if (file_exists($res)) {\r
+ @unlink($res);\r
+ }\r
+\r
+ if ($method == 'GS') {\r
+ $this->makeShotGS($page, $prefix, $resolution, $quality, $antialiasing, $in);\r
+ } elseif ($method == 'PNM') {\r
+ $this->makeShotPNM($page, $prefix, $resolution, $quality, $antialiasing, $in);\r
+ }\r
+ // Test the result by checking all files\r
+ if (!file_exists($res)) {\r
+ $error = true;\r
+ }\r
+ // If error, we try to make thumbs with other method\r
+ if ($error) {\r
+ if ($method == 'GS') {\r
+ $this->makeShotPNM($page, $prefix, $resolution, $quality, $antialiasing, $in);\r
+ } elseif ($method == 'PNM') {\r
+ $this->makeShotGS($page, $prefix, $resolution, $quality, $antialiasing, $in);\r
+ }\r
+ }\r
+ }\r
+\r
+ protected function makeShotGS($page, $prefix = '', $resolution = 72, $quality = 90, $antialiasing = 4, $in = null) {\r
+ if (is_null($in)) {\r
+ $in = $this->cropped;\r
+ }\r
+ // Fabrication des thumbanails avec ghostscript\r
+ $gs = new cubeCommandLine('gs', null, true);\r
+ $gs->setPath(CONVERTER_PATH);\r
+ $gs->setEnv('GS_FONTPATH', FONT_PATH);\r
+ $gs->setArg('-dBATCH');\r
+ $gs->setArg('-dNOPAUSE');\r
+ $gs->setArg('-dNOPROMPT');\r
+ // Antialias\r
+ $gs->setArg('-dDOINTERPOLATE');\r
+ $gs->setArg('-dTextAlphaBits=' . $antialiasing);\r
+ $gs->setArg('-dGraphicsAlphaBits=' . $antialiasing);\r
+ // Device\r
+ $gs->setArg('-sDEVICE=jpeg');\r
+ // Dispotion & colors\r
+ // $gs->setArg('-dUseCIEColor');\r
+ $gs->setArg('-dAutoRotatePages=/None');\r
+ $gs->setArg('-dUseCropBox');\r
+ // Resolution & Quality\r
+ $gs->setArg('-r' . round($resolution));\r
+ $gs->setArg('-dJPEGQ=' . $quality);\r
+ // Performances\r
+ $gs->setArg('-dNumRenderingThreads=4');\r
+ // Page range\r
+ $gs->setArg('-dFirstPage=' . $page);\r
+ $gs->setArg('-dLastPage=' . $page);\r
+ // Files\r
+ $gs->setArg('-sOutputFile=' . $this->out . '/' . $prefix . $page . '.jpg');\r
+\r
+ $gs->setArg(null, $in);\r
+ $gs->execute();\r
+ $this->addToLog($gs, true, $page);\r
+ }\r
+\r
+ protected function makeShotPNM($page, $prefix = '', $resolution = 72, $quality = 90, $antialiasing = 4, $in = null, $texts = true) {\r
+ if (is_null($in)) {\r
+ $in = $this->cropped;\r
+ }\r
+ $antialiasing = $antialiasing ? 'yes' : 'no';\r
+ $freetype = $texts ? 'yes' : 'no';\r
+ $resolution = round($resolution);\r
+ // Exporte les fichiers\r
+ $pdftoppm = new cubeCommandLine('pdftoppm', null, true);\r
+ $pdftoppm->setPath(CONVERTER_PATH);\r
+\r
+ $pdftoppm->setArg('f', $page);\r
+ $pdftoppm->setArg('l', $page);\r
+\r
+ $pdftoppm->setArg('-cropbox');\r
+ $pdftoppm->setArg('-freetype ' . $freetype);\r
+ $pdftoppm->setArg('-jpeg');\r
+ $pdftoppm->setArg('-aa ' . $antialiasing);\r
+ $pdftoppm->setArg('-aaVector ' . $antialiasing);\r
+ $pdftoppm->setArg('r', $resolution);\r
+ $pdftoppm->setArg(null, $in);\r
+ $pdftoppm->setArg(null, $this->out . 'ppm');\r
+ $pdftoppm->execute();\r
+ $this->addToLog($pdftoppm, true, $page);\r
+\r
+ $jpegfile = $this->out . $prefix . $page . '.jpg';\r
+\r
+ $ppmjpgfile = $this->out . 'ppm-' . cubeMath::fill($page, strlen((string) $this->pages)) . '.jpg';\r
+ if (file_exists($ppmjpgfile)) {\r
+ rename($ppmjpgfile, $jpegfile);\r
+ $this->addToLog('Move ' . $ppmjpgfile . ' to ' . $jpegfile, true, $page);\r
+ }\r
+ }\r
+\r
+ protected function isCropped() {\r
+ return $this->autocrop || $this->manualcrop || $this->autocut || $this->manualcut;\r
+ }\r
+\r
+ public function makeSWFFiles($page, $resolution = null, $quality = null, $storeAllChars = null, $maxObjects = 1800, $method = null) {\r
+ $conversionSettings = $this->conversionInfos->pages[$page];\r
+ if (is_null($storeAllChars)) {\r
+ $storeAllChars = true;\r
+ }\r
+ if (is_null($resolution)) {\r
+ $resolution = $conversionSettings->resolution;\r
+ }\r
+ if (is_null($method)) {\r
+ $method = $conversionSettings->method;\r
+ }\r
+ if (is_null($quality)) {\r
+ $quality = $conversionSettings->quality;\r
+ }\r
+ if (is_null($maxObjects)) {\r
+ $maxObjects = $conversionSettings->objects;\r
+ }\r
+\r
+ if ($maxObjects <= 1) {\r
+ $method = self::POLY2BITMAP;\r
+ }\r
+ // Pour les fichiers croppés, on utilise la méthode flatten qui ne prends\r
+ // pas en compte les objets hors de la box\r
+ if ($this->isCropped()) {\r
+ // $method = max($method, self::FLATTEN);\r
+ }\r
+\r
+ $out = $this->pdf2swf($page, $resolution, $quality, $storeAllChars, $method);\r
+ if ($method < self::BARBARE_PNM) {\r
+ // Analyse de la sortie pour détecter des typos manquantes\r
+ $overflow = false;\r
+ $overflowObjects = false;\r
+ $written = false;\r
+ $missing_fonts = array();\r
+ if (file_exists($out)) {\r
+ $fp = fopen($out, 'rb');\r
+ while ($line = fgets($fp)) {\r
+ if (preg_match('|Try putting a TTF version of that font \(named \"([A-Z-_0-9.]*)\"\)|Uui', trim($line), $matches)) {\r
+ $missing_fonts[] = $matches[1];\r
+ } elseif (stristr($line, 'ID Table overflow')) {\r
+ $overflow = true;\r
+ } elseif (stristr($line, 'NOTICE SWF written')) {\r
+ $written = true;\r
+ } elseif (stristr($line, 'NOTICE Writing SWF file')) {\r
+ $written = true;\r
+ }\r
+ }\r
+ }\r
+ if (!is_null($page) && file_exists($this->out . 'p' . $page . '.swf')) {\r
+ $written = true;\r
+ }\r
+ // On teste si le fichier est écrit et qu'il a été généré par le premier niveau\r
+ if ($method < self::POLY2BITMAP && $written) {\r
+ $overflowObjects = $this->checkObjectsNumber($this->out . 'p' . $page . '.swf', $maxObjects, $page);\r
+ }\r
+\r
+ if (!$written || $overflow || $overflowObjects) {\r
+ if ($method == self::MAX) {\r
+ return;\r
+ }\r
+ $nextMethod = $method + 1;\r
+ return $this->makeSWFFiles($page, $resolution, $quality, $storeAllChars, $maxObjects, $nextMethod);\r
+ }\r
+ }\r
+ }\r
+\r
+ public function makeHTML5Files($page) {\r
+ // Then make HD background shots\r
+ $resolutions = array(36 => 80, 72 => 70, 150 => 50);\r
+ foreach ($resolutions as $r => $q) {\r
+ $this->makeShotPNM($page, 'html/h' . $r . '-', $r, $q, 4, null, false);\r
+ }\r
+ }\r
+\r
+ protected function checkObjectsNumber($file, $maxObjects, $page) {\r
+ $swfdump = new cubeCommandLine('swfdump', null, true);\r
+ $swfdump->setPath(CONVERTER_PATH);\r
+ $swfdump->setArg(null, $file);\r
+ $swfdump->execute();\r
+ $this->addToLog($swfdump, true, $page);\r
+\r
+ str_replace('[01a]', '', $swfdump->output, $nbObjects);\r
+ if ($nbObjects > $maxObjects) {\r
+ return true;\r
+ }\r
+ return false;\r
+ }\r
+\r
+ protected function dumpSWF($page, $prefix = 'p') {\r
+ $swfdump = new cubeCommandLine('/usr/local/swftools/special-swfdump/bin/swfdump', null, true);\r
+ $swfdump->setPath(CONVERTER_PATH);\r
+ $swfdump->setArg('t');\r
+ $swfdump->setArg('p');\r
+ $swfdump->setArg('F');\r
+ $swfdump->setArg(null, $this->out . $prefix . $page . '.swf');\r
+ $swfdump->execute();\r
+ $this->addToLog($swfdump, false, $page);\r
+ return $swfdump->output;\r
+ }\r
+\r
+ /**\r
+ * wsDocument::pdf2swf()\r
+ *\r
+ * @param mixed $page\r
+ * @param integer $resolution\r
+ * @param integer $quality\r
+ * @param mixed $storeAllChars\r
+ * @param integer $method\r
+ * @return\r
+ */\r
+ protected function pdf2swf($page, $resolution = 150, $quality = 90, $storeAllChars = true, $method = 0, $prefix = 'p') {\r
+ /*\r
+ -h , --help Print short help message and exit\r
+ -V , --version Print version info and exit\r
+ -o , --output file.swf Direct output to file.swf. If file.swf contains '%' (file%.swf), then each page goes to a seperate file.\r
+ -p , --pages range Convert only pages in range with range e.g. 1-20 or 1,4,6,9-11 or\r
+ -P , --password password Use password for deciphering the pdf.\r
+ -v , --verbose Be verbose. Use more than one -v for greater effect.\r
+ -z , --zlib Use Flash 6 (MX) zlib compression.\r
+ -i , --ignore Allows pdf2swf to change the draw order of the pdf. This may make the generated\r
+ -j , --jpegquality quality Set quality of embedded jpeg pictures to quality. 0 is worst (small), 100 is best (big). (default:85)\r
+ -s , --set param=value Set a SWF encoder specific parameter. See pdf2swf -s help for more information.\r
+ -w , --samewindow When converting pdf hyperlinks, don't make the links open a new window.\r
+ -t , --stop Insert a stop() command in each page.\r
+ -T , --flashversion num Set Flash Version in the SWF header to num.\r
+ -F , --fontdir directory Add directory to the font search path.\r
+ -b , --defaultviewer Link a standard viewer to the swf file.\r
+ -l , --defaultloader Link a standard preloader to the swf file which will be displayed while the main swf is loading.\r
+ -B , --viewer filename Link viewer filename to the swf file.\r
+ -L , --preloader filename Link preloader filename to the swf file.\r
+ -q , --quiet Suppress normal messages. Use -qq to suppress warnings, also.\r
+ -S , --shapes Don't use SWF Fonts, but store everything as shape.\r
+ -f , --fonts Store full fonts in SWF. (Don't reduce to used characters).\r
+ -G , --flatten Remove as many clip layers from file as possible.\r
+ -I , --info Don't do actual conversion, just display a list of all pages in the PDF.\r
+ -Q , --maxtime n Abort conversion after n seconds. Only availableon Unix.\r
+\r
+ PDF device global parameters:\r
+ -----------------------------\r
+ fontdir=<dir> a directory with additional fonts\r
+ font=<filename> an additional font filename\r
+ pages=<range> the range of pages to convert (example: pages=1-100,210-)\r
+ zoom=<dpi> the resultion (default: 72)\r
+ languagedir=<dir> Add an xpdf language directory\r
+ multiply=<times> Render everything at <times> the resolution\r
+ poly2bitmap Convert graphics to bitmaps\r
+ bitmap Convert everything to bitmaps\r
+\r
+ SWF Parameters :\r
+ ----------------\r
+ SWF layer options :\r
+ -------------------\r
+\r
+ jpegsubpixels=<pixels> resolution adjustment for jpeg images (same as jpegdpi, but in pixels)\r
+ ppmsubpixels=<pixels resolution adjustment for lossless images (same asppmdpi, but in pixels)\r
+ subpixels=<pixels> shortcut for setting both jpegsubpixels and ppmsubpixels\r
+ drawonlyshapes convert everything to shapes (currently broken)\r
+ ignoredraworder allow to perform a few optimizations for creating smaller SWFs\r
+ linksopennewwindow make links open a new browser window\r
+ linktarget target window name of new links\r
+ linkcolor=<color) color of links (format: RRGGBBAA)\r
+ linknameurl Link buttons will be named like the URL they refer to (handy for iterating through links with actionscript)\r
+ storeallcharacters don't reduce the fonts to used characters in the output file\r
+ enablezlib switch on zlib compression (also done if flashversion>=7)\r
+ bboxvars store the bounding box of the SWF file in actionscript variables\r
+ dots Take care to handle dots correctly\r
+ reordertags=0/1 (default: 1) perform some tag optimizations\r
+ internallinkfunction=<name> when the user clicks a internal link (to a different page) in the converted file, this actionscript function is called\r
+ externallinkfunction=<name> when the user clicks an external link (e.g. http://www.foo.bar/) on the converted file, this actionscript function is called\r
+ disable_polygon_conversion never convert strokes to polygons (will remove capstyles and joint styles)\r
+ caplinewidth=<width> the minimum thichness a line needs to have so that capstyles become visible (and are converted)\r
+ insertstop put an ActionScript "STOP" tag in every frame\r
+ protect add a "protect" tag to the file, to prevent loading in the Flash editor\r
+ flashversion=<version> the SWF fileversion (6)\r
+ framerate=<fps> SWF framerate\r
+ minlinewidth=<width> convert horizontal/vertical boxes smaller than this width to lines (0.05)\r
+ simpleviewer Add next/previous buttons to the SWF\r
+ animate insert a showframe tag after each placeobject (animate draw order of PDF files)\r
+ jpegquality=<quality> set compression quality of jpeg images\r
+ splinequality=<value> Set the quality of spline convertion to value (0-100, default: 100).\r
+ disablelinks Disable links.\r
+ */\r
+\r
+ if (file_exists($this->out . $prefix . $page . '.swf')) {\r
+ unlink($this->out . $prefix . $page . '.swf');\r
+ }\r
+\r
+ if (!in_array($method, array(self::BARBARE_PNM, self::BARBARE_GS))) {\r
+ $pdf2swf = new cubeCommandLine('pdf2swf', null, true);\r
+ $pdf2swf->setPath(CONVERTER_PATH);\r
+\r
+ $pdf2swf->setArg('p', $page);\r
+\r
+ if ($method == self::NORMAL) {\r
+ // Default\r
+ $multiply = 1;\r
+ } elseif ($method == self::FLATTEN) {\r
+ $pdf2swf->setArg('flatten');\r
+ $multiply = 1;\r
+ } elseif ($method == self::POLY2BITMAP) {\r
+ // Raster graphics, keep texts\r
+ $pdf2swf->setArg('set poly2bitmap');\r
+ $multiply = self::$resolution2multiply[$resolution];\r
+ $pdf2swf->setArg('set multiply', $multiply);\r
+ } elseif ($method == self::BITMAP) {\r
+ // Raster all\r
+ $pdf2swf->setArg('set bitmap');\r
+ $multiply = self::$resolution2multiply[$resolution];\r
+ $pdf2swf->setArg('set multiply', $multiply);\r
+ }\r
+\r
+ $pdf2swf->setArg('stop');\r
+ // $pdf2swf->setManualArg('-v');\r
+ $pdf2swf->setArg('T', 10);\r
+ $pdf2swf->setArg('set reordertags', '0');\r
+ if ($storeAllChars) {\r
+ $pdf2swf->setArg('fonts');\r
+ $pdf2swf->setArg('set storeallcharacters');\r
+ }\r
+ if (DEV) {\r
+ $pdf2swf->setArg('F', 'C:/Windows/Fonts');\r
+ } else {\r
+ $pdf2swf->setArg('F', '/home/typo/fonts');\r
+ }\r
+ $pdf2swf->setArg('set subpixels', $resolution / 72);\r
+ $pdf2swf->setArg('set jpegquality', $quality);\r
+ $pdf2swf->setArg('set disablelinks');\r
+ $pdf2swf->setArg('set dots');\r
+ // $pdf2swf->setManualArg('-vvv');\r
+ $pdf2swf->setArg(null, $this->cropped);\r
+ $pdf2swf->setArg('output', $this->out . $prefix . '%.swf');\r
+ $pdf2swf->execute();\r
+\r
+ $this->addToLog($pdf2swf, true, $page);\r
+ } else {\r
+ $this->pdf2swfBarbare($page, $resolution, $quality, $method);\r
+ }\r
+ }\r
+\r
+ protected function makeAS3($page) {\r
+ $swffile = $this->out . 'p' . $page . '.swf';\r
+\r
+ $swfcombine = new cubeCommandLine('swfcombine');\r
+ $swfcombine->setPath(CONVERTER_PATH);\r
+ $swfcombine->setArg('merge');\r
+ $swfcombine->setArg('stack1');\r
+ $swfcombine->setArg('z');\r
+ $swfcombine->setManualArg('-v');\r
+ $swfcombine->setArg('o', $swffile);\r
+ $swfcombine->setArg(null, ROOT . '/swf/as3Container.swf');\r
+ $swfcombine->setManualArg('content=' . $swffile);\r
+ $swfcombine->execute();\r
+ $this->addToLog($swfcombine, true, $page);\r
+ }\r
+\r
+ protected function pdf2swfBarbare($page, $resolution = 150, $quality = 85, $method = 4) {\r
+ // Fabrique les images\r
+ if ($method == self::BARBARE_PNM) {\r
+ $this->makeShot($page, 'barbare', $resolution, $quality, 4, 'PNM');\r
+ } elseif ($method == self::BARBARE_GS) {\r
+ $this->makeShot($page, 'barbare', $resolution, $quality, 4, 'GS');\r
+ }\r
+ // A partir des images, on crée les swf\r
+ $jpeg2swf = new cubeCommandLine('jpeg2swf');\r
+ $jpeg2swf->setPath(CONVERTER_PATH);\r
+ $jpeg2swf->setArg('--quality', $quality);\r
+ $jpeg2swf->setArg('--output', $this->out . 'p' . $page . '.swf');\r
+ $jpeg2swf->setArg('--fit-to-movie');\r
+ $jpeg2swf->setArg('--flashversion', 9);\r
+ $jpeg2swf->setArg(null, $this->out . 'barbare' . $page . '.jpg');\r
+ $jpeg2swf->execute();\r
+ $this->addToLog($jpeg2swf, true, $page);\r
+ // Suppression du jpeg\r
+ @unlink($this->out . '/barbare' . $page . '.jpg', true, $page);\r
+\r
+ return '';\r
+ }\r
+\r
+ public function addToLog($cl, $output = true, $page = null) {\r
+ if ($cl instanceof cubeCommandLine) {\r
+ $c = '--- Exécuté en ' . $cl->execTime . " s\n" . $cl->commande . "\n\n";\r
+ if ($output) {\r
+ $c .= $cl->output . "\n\n";\r
+ }\r
+ } elseif (is_string($cl)) {\r
+ $c = '--- ' . "\n\n";\r
+ $c .= $cl . "\n\n";\r
+ }\r
+\r
+ if (is_null($page)) {\r
+ $pointer = $this->common_log_pointer;\r
+ } else {\r
+ if (isset($this->pages_log_pointers[$page]) && is_resource($this->pages_log_pointers[$page])) {\r
+ $pointer = $this->pages_log_pointers[$page];\r
+ } else {\r
+ $pointer = fopen($this->log . '/p' . $page . '.log', 'wb');\r
+ $this->pages_log_pointers[$page] = $pointer;\r
+ }\r
+ }\r
+\r
+ fwrite($pointer, $c);\r
+ }\r
+\r
+ public function __destruct() {\r
+ if (isset($this->common_log_pointer) && is_resource($this->common_log_pointer)) {\r
+ fclose($this->common_log_pointer);\r
+ }\r
+\r
+ foreach ($this->pages_log_pointers as $p) {\r
+ if (!is_null($p) && is_resource($p)) {\r
+ fclose($p);\r
+ }\r
+ }\r
+ }\r
+\r
}\r
\r
?>
\ No newline at end of file
<?php\r
+\r
class wsPackagerHTML5 extends wsPackager {\r
- protected $layouts = array();\r
\r
+ protected $layouts = array();\r
protected $cssSize = array();\r
protected $cssColor = array();\r
protected $cssOpacity = array();\r
- protected $fonts = array();\r
- protected $fontsNames = array();\r
- protected $fontsCount = 0;\r
-\r
- protected $coef;\r
-\r
+ protected $cssFont = array();\r
+ protected $cssWordSpacing = array();\r
+ protected $cssLetterSpacing = array();\r
+ protected $cssRotation = array();\r
+ protected $pdf2htmlRatio;\r
+ protected $scale;\r
+ protected $multiply;\r
protected $div = array();\r
\r
- public function __construct($book_id)\r
- {\r
+ public function __construct($book_id) {\r
parent::__construct($book_id);\r
$this->version = 'html5';\r
-\r
- $this->coef = 150 / 72;\r
}\r
\r
- protected function preparePackage()\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'] . '.obj';\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] = unserialize(file_get_contents($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/h150-' . $this->pages[1]['document_page'] . '.jpg');\r
+ $this->pdf2htmlRatio = $imagesize[0] / $this->layouts[1]['width'];\r
+ $this->scale = 20;\r
+ $this->multiply = $this->pdf2htmlRatio * $this->scale;\r
+\r
$this->createHTML();\r
}\r
\r
- public function makePackage()\r
- {\r
+ public function makePackage() {\r
parent::makePackage();\r
return $this->zip();\r
}\r
\r
- protected function createHTML()\r
- {\r
- foreach($this->layouts as $page => $infos) {\r
+ protected function createHTML() {\r
+ foreach ($this->layouts as $page => $layout) {\r
$this->div[$page] = array();\r
- foreach($infos->tags as $tag) {\r
- if ($tag instanceof wsSWF2HTMLFont) {\r
- $this->addFont($tag, $this->pages[$page], $page);\r
- } else if ($tag instanceof wsSWF2HTMLParagraph) {\r
- $this->addParagraph($tag, $this->div[$page], $page);\r
- }\r
+ $document_id = $this->pages[$page]['document_id'];\r
+ foreach ($layout->xpath('//a') as $div) {\r
+ $this->div[$page][] = $this->addCSSText($div, $document_id);\r
}\r
}\r
mkdir($this->vdir . '/style', 0777, true);\r
mkdir($this->vdir . '/contents', 0777, true);\r
mkdir($this->vdir . '/images', 0777, true);\r
- mkdir($this->vdir . '/fonts', 0777, true);\r
\r
file_put_contents($this->vdir . '/style/style.css', $this->writeCSS());\r
- foreach($this->div as $n => $page) {\r
+ foreach ($this->div as $n => $page) {\r
file_put_contents($this->vdir . '/contents/p' . $n . '.html', $this->writePage($page));\r
}\r
$this->writeFonts();\r
$this->writeImages();\r
}\r
\r
- protected function writeFonts()\r
- {\r
+ protected function writeFonts() {\r
$fext = array('ttf', 'eot', 'svg', 'svgz', 'woff');\r
- foreach($this->fonts as $font) {\r
- if (!$font['embed']) {\r
- return;\r
- }\r
- foreach($fext as $ext) {\r
- copy($font['file'] . '.' . $ext, $this->vdir . '/fonts/' . $font['name'] . '.' . $ext);\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 . '/style/F' . $index . '.' . $ext);\r
}\r
}\r
}\r
\r
- protected function writeImages()\r
- {\r
+ protected function writeImages() {\r
$resolutions = array(36, 72, 150);\r
- foreach($resolutions as $r) {\r
+ foreach ($resolutions as $r) {\r
mkdir($this->vdir . '/images/' . $r, 0777);\r
}\r
- foreach($this->pages as $page => $infos) {\r
- foreach($resolutions as $r) {\r
+ foreach ($this->pages as $page => $infos) {\r
+ foreach ($resolutions as $r) {\r
copy(WS_DOCS . '/' . $infos['document_id'] . '/html/h' . $r . '-' . $infos['document_page'] . '.jpg', $this->vdir . '/images/' . $r . '/p' . $page . '.jpg');\r
}\r
}\r
}\r
\r
- protected function writePage($page)\r
- {\r
+ protected function writePage($page) {\r
$res = '';\r
- foreach($page as $div) {\r
- $res .= $this->writeDiv($div);\r
+ foreach ($page as $div) {\r
+ $res .= $this->writeSpan($div);\r
}\r
return $res;\r
}\r
\r
- protected function writeDiv($div)\r
- {\r
- $res = '<div style="left:' . ($div['left'] * $this->coef) . 'px;top:' . ($div['top'] * $this->coef) . 'px;">';\r
- foreach($div['span'] as $span) {\r
- $res .= $this->writeSpan($span);\r
+ protected function writeSpan($span) {\r
+ if ($span === false) {\r
+ return '';\r
}\r
- $res .= '</div>';\r
- return $res;\r
- }\r
\r
- protected function writeSpan($span)\r
- {\r
- $res = '<span ';\r
- $res .= 'style="left:' . ($span['left'] * $this->coef) . 'px;top:' . ($span['top'] * $this->coef) . 'px" ';\r
- $res .= 'class="c' . $span['color'] . ' s' . $span['size'] . ' f' . $span['font'] . '"';\r
- $res .= '>';\r
+ $top = round($span['y'] * $this->multiply, 2);\r
+ $left = round($span['x'] * $this->multiply, 2);\r
+\r
+ $class = '';\r
+ if (!is_null($span['color'])) {\r
+ $class.=' c' . $span['color'];\r
+ }\r
+ if (!is_null($span['size'])) {\r
+ $class.=' s' . $span['size'];\r
+ }\r
+ if (!is_null($span['font'])) {\r
+ $class.=' f' . $span['font'];\r
+ }\r
+ if (!is_null($span['wordSpacing'])) {\r
+ $class.=' w' . $span['wordSpacing'];\r
+ }\r
+ if (!is_null($span['letterSpacing'])) {\r
+ $class.=' l' . $span['letterSpacing'];\r
+ }\r
+ if (!is_null($span['rotation'])) {\r
+ $class.=' r' . $span['rotation'];\r
+ }\r
+\r
+ $class = trim($class);\r
+\r
+ $res = '<div ';\r
+ $res .= 'style="left:' . $left . 'px;top:' . $top . 'px" ';\r
+ $res .= 'class="' . $class . '"><span class="r">';\r
$res .= htmlentities($span['text'], ENT_NOQUOTES, 'UTF-8');\r
- $res .= '</span>';\r
+ $res .= '</span></div>';\r
return $res;\r
}\r
\r
- protected function writeCSS()\r
- {\r
+ protected function writeCSS() {\r
$res = array();\r
- foreach($this->cssColor as $color => $index) {\r
- $res[] = '.c' . $index . '{color:' . $color . ';}';\r
- }\r
-\r
- foreach($this->cssSize as $size => $index) {\r
- $size = ($size/(20*16))*$this->coef;\r
- $res[] = '.s' . $index . '{font-size:' . $size . 'em;}';\r
- }\r
-\r
- foreach($this->fonts as $id => $font) {\r
- if ($font['embed']) {\r
- $svg = simplexml_load_file($font['file'] . '.svg');\r
- foreach($svg->defs->font as $f) {\r
- $svgid = $f['id'];\r
- break;\r
- }\r
- $res[] = "@font-face{font-family:'" . $font['name'] . "';src:url('" . $font['url'] . ".eot');src:url('" . $font['url'] . ".eot?#iefix') format('eot'),url('" . $font['url'] . ".woff') format('woff'),url('" . $font['url'] . ".ttf') format('truetype'),url('" . $font['url'] . ".svgz#" . $svgid . "') format('svgz'),url('" . $font['url'] . ".svg#" . $svgid . "') format('svg');font-weight:normal;font-style:normal;}";\r
- $res[] = '.f' . $font['index'] . '{font-family:' . $font['name'] . ',Arial,Helvetica;}';\r
- } else {\r
- $res[] = '.f' . $font['index'] . '{font-family:' . $font['realname'] . ',Arial,Helvetica;}';\r
- }\r
+ foreach ($this->cssColor as $color => $index) {\r
+ $res[] = '.c' . $index . '{color:#' . $color . '}';\r
}\r
- return implode("\n", $res);\r
- }\r
\r
- protected function addFont($tag, $infos, $page)\r
- {\r
- $this->fontsNames[$tag->id . ',' . $page] = $tag->name;\r
- if (isset($this->fonts[$tag->name])) {\r
- return;\r
+ foreach ($this->cssSize as $size => $index) {\r
+ $size*=$this->multiply;\r
+ // Point to pixel conversion\r
+ $res[] = '.s' . $index . '{font-size:' . $size . 'px}';\r
}\r
- $index = $this->fontsCount;\r
- $file = WS_DOCS . '/' . $infos['document_id'] . '/fonts/web/' . $tag->name;\r
- $embed = file_exists($file . '.ttf');\r
- $this->fonts[$tag->name] = array('index' => $index, 'realname' => $tag->name, 'name' => 'FB' . $index, 'file' => $file, 'embed' => $embed, 'url' => '../fonts/FB' . $index);\r
- $this->fontsCount++;\r
- }\r
\r
- protected function addParagraph($tag, &$div, $page)\r
- {\r
- $d = array('span' => array(), 'left' => $tag->left, 'top' => $tag->top);\r
- foreach($tag->textes as $text) {\r
- $s = $this->addCSSText($text, $page);\r
- if ($s === false) {\r
- continue;\r
- }\r
- $d['span'][] = $s;\r
+ foreach ($this->cssLetterSpacing as $letterspacing => $index) {\r
+ $letterspacing*=$this->multiply;\r
+ $res[] = '.l' . $index . '{letter-spacing:' . $letterspacing . 'px}';\r
}\r
- $div[] = $d;\r
+\r
+ foreach ($this->cssWordSpacing as $wordspacing => $index) {\r
+ $wordspacing*=$this->multiply;\r
+ $res[] = '.w' . $index . '{word-spacing:' . $wordspacing . 'px}';\r
+ }\r
+\r
+ foreach ($this->cssRotation as $rotation => $index) {\r
+ $rotation*= - 1;\r
+ $res[] = '.r' . $index . '{-webkit-transform: rotate(' . $rotation . 'deg);-moz-transform: rotate(' . $rotation . 'deg)}';\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 . ".woff') format('woff'),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
+ return implode("\n", $res);\r
}\r
\r
- protected function addCSSText($text, $page)\r
- {\r
- $alpha = intval(substr($text->color, -2), 16);\r
+ protected function addCSSText($l, $document_id) {\r
+ $alpha = intval(substr($l['color'], 1, 2), 16);\r
+ $text = (string) $l;\r
+ if ($text == '') {\r
+ return false;\r
+ }\r
if ($alpha == 0) {\r
return false;\r
}\r
- return array('text' => $text->text,\r
- 'color' => $this->getCSSColor($text->color),\r
- 'size' => $this->getCSSSize($text->size),\r
- 'font' => $this->getCSSFont($text->font, $page),\r
- 'left' => $text->x,\r
- 'top' => $text->y);\r
+ return array('text' => $text,\r
+ 'color' => $this->getCSSColor($l['color']),\r
+ 'size' => $this->getCSSSize($l['size']),\r
+ 'font' => $this->getCSSFont($l['font'], $document_id),\r
+ 'letterSpacing' => $this->getCSSLetterSpacing($l['letterspacing']),\r
+ 'wordSpacing' => $this->getCSSWordSpacing($l['wordspacing']),\r
+ 'rotation' => $this->getCSSRotation($l['rotation']),\r
+ 'x' => $this->normalizeFloatValue($l['x']),\r
+ 'y' => $this->normalizeFloatValue($l['y']));\r
}\r
\r
- protected function getCSSSize($size)\r
- {\r
+ protected function getCSSSize($size) {\r
+ $size = $this->normalizeFloatValue($size);\r
return $this->getIndex($size, $this->cssSize);\r
}\r
\r
- protected function getCSSFont($font, $page)\r
- {\r
- $name = $this->fontsNames[$font . ',' . $page];\r
+ protected function getCSSFont($font, $document_id) {\r
\r
- return $this->fonts[$name]['index'];\r
+ return $this->getIndex($font . "//" . $document_id, $this->cssFont);\r
}\r
\r
- protected function getCSSColor($color)\r
- {\r
- if (strlen($color) > 7) {\r
- $color = substr($color, 0, 7);\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 getIndex($value, &$tab)\r
- {\r
- $value = (string)$value;\r
+ protected function getCSSLetterSpacing($letterspacing) {\r
+ $letterspacing = $this->normalizeFloatValue($letterspacing);\r
+ if ($letterspacing == 0) {\r
+ return null;\r
+ }\r
+\r
+ return $this->getIndex($letterspacing, $this->cssLetterSpacing);\r
+ }\r
+\r
+ protected function getCSSWordSpacing($wordspacing) {\r
+ $wordspacing = $this->normalizeFloatValue($wordspacing);\r
+ if ($wordspacing == 0) {\r
+ return null;\r
+ }\r
+ return $this->getIndex($wordspacing, $this->cssWordSpacing);\r
+ }\r
+\r
+ protected function getCSSRotation($rotation) {\r
+ $rotation = round($rotation);\r
+ if ($rotation == 0) {\r
+ return null;\r
+ }\r
+ return $this->getIndex($rotation, $this->cssRotation);\r
+ }\r
+\r
+ protected function getIndex($value, &$tab) {\r
+ $value = (string) $value;\r
if (isset($tab[$value])) {\r
return $tab[$value];\r
}\r
- $res = count($tab);\r
+ $res = $this->base36(count($tab));\r
$tab[$value] = $res;\r
return $res;\r
}\r
\r
- public function __destruct()\r
- {\r
+ protected function normalizeFloatValue($value) {\r
+ $value = str_replace(',', '.', $value);\r
+ $value = (float) $value;\r
+ $value = round($value, 3);\r
+ return $value;\r
+ }\r
+\r
+ protected function base36($val) {\r
+ $base = 36;\r
+ $chars = '0123456789abcdefghijklmnopqrstuvwxyz';\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 __destruct() {\r
+ \r
+ }\r
+\r
}\r
\r
?>
\ No newline at end of file