From: vincent@cubedesigners.com Date: Mon, 9 May 2011 15:54:38 +0000 (+0000) Subject: (no commit message) X-Git-Url: http://git.cubedesigners.com/?a=commitdiff_plain;h=1192a419b8756a6603de0275d3aec822bcfa622c;p=cubeextranet.git --- diff --git a/inc/ws/Metier/class.ws.document.php b/inc/ws/Metier/class.ws.document.php index 427433e80..262f28dc2 100644 --- a/inc/ws/Metier/class.ws.document.php +++ b/inc/ws/Metier/class.ws.document.php @@ -11,846 +11,874 @@ */ class wsDocument extends cubeMetier { - 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->in . ') 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); - } - } - } + 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->in . ') 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 + + $this->addToLog('Making barbare swf', true, $page); + + 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', 10); + $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); + + $pdf2swf = new cubeCommandLine('pdf2swf', null, true); + $pdf2swf->setPath(CONVERTER_PATH); + $pdf2swf->setArg('set poly2bitmap'); + $pdf2swf->setArg('p', $page); + $pdf2swf->setArg('stop'); + $pdf2swf->setArg('T', 10); + $pdf2swf->setArg('set reordertags', '0'); + $pdf2swf->setArg('fonts'); + $pdf2swf->setArg('set storeallcharacters'); + if (DEV) { + $pdf2swf->setArg('F', 'C:/Windows/Fonts'); + } else { + $pdf2swf->setArg('F', '/home/typo/fonts'); + } + if (file_exists($this->out . 't' . $page . '.swf')) { + unlink($this->out . 't' . $page . '.swf'); + } + $pdf2swf->setArg('set subpixels', '0.01'); + $pdf2swf->setArg('set jpegquality', '1'); + $pdf2swf->setArg('set disablelinks'); + $pdf2swf->setArg(null, $this->cropped); + $pdf2swf->setArg('output', $this->out . 't' . $page . '.swf'); + $pdf2swf->execute(); + $this->addToLog($pdf2swf, 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); + } + } + } }