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