From d83f95d4f8b927fff38da6918ff0a2a3b346e189 Mon Sep 17 00:00:00 2001 From: Greg Payne Date: Thu, 30 Mar 2017 16:44:06 -0500 Subject: [PATCH] #92 - Convert pptx to a Carousel-based HTML slideshow --- src/Configuration/ConfigurationDefaults.php | 28 +++- src/Engine/Chain.php | 24 ++- src/Engine/Convert/ImageMagick.php | 14 +- src/Engine/Convert/NativeMeta.php | 6 +- src/Engine/Convert/NativeSlideshow.php | 148 ++++++++++++++++++ .../Convert/Resources/Slideshow/index.htm | 35 +++++ .../Convert/Resources/Slideshow/slideshow.css | 0 .../Convert/Resources/Slideshow/slideshow.js | 81 ++++++++++ src/Engine/EngineBase.php | 2 +- src/Engine/Helper/Archive.php | 3 + 10 files changed, 325 insertions(+), 16 deletions(-) create mode 100644 src/Engine/Convert/NativeSlideshow.php create mode 100644 src/Engine/Convert/Resources/Slideshow/index.htm create mode 100644 src/Engine/Convert/Resources/Slideshow/slideshow.css create mode 100644 src/Engine/Convert/Resources/Slideshow/slideshow.js diff --git a/src/Configuration/ConfigurationDefaults.php b/src/Configuration/ConfigurationDefaults.php index 164f100..cefc4f1 100644 --- a/src/Configuration/ConfigurationDefaults.php +++ b/src/Configuration/ConfigurationDefaults.php @@ -36,8 +36,8 @@ public function __construct(&$settings) { $lsb = trim(`which lsb_release`); if ($lsb !== '') { $lsb = escapeshellarg($lsb); - $settings['operating_system'] = trim(`$lsb -is`); - $settings['operating_system_version'] = trim(`$lsb -rs`); + $settings['operating_system'] = trim(`$lsb -is`); + $settings['operating_system_version'] = trim(`$lsb -rs`); } } elseif ($settings['operating_system'] === 'Windows NT') { @@ -123,10 +123,21 @@ public function __construct(&$settings) { "flatten" => 1, ), ), + 'pdf->(zip/jpg|directory/jpg)' => array( + 'imagemagick:default' => array( + '#engine' => 'Convert\\ImageMagick', + "colorspace" => "sRGB", + // Double-resolution output + 'density' => '144', + ), + ), 'pdf->(zip/png|directory/png)' => array( 'imagemagick:default' => array( '#engine' => 'Convert\\ImageMagick', "colorspace" => "sRGB", + // Supersampling with double-resolution output + 'density' => '288', + 'resize' => '50%', ), ), 'ps->pdf' => array( @@ -152,11 +163,24 @@ public function __construct(&$settings) { '#engine' => 'Convert\\Unoconv', ), ), + '(ppt|pptx)->(directory/jpg|zip/jpg)' => array( + 'pptx->pdf->img' => array( + '#engine' => 'Chain', + 'chain' => 'pptx->pdf->*', + ), + ), 'pptx->json' => array( 'nativemeta:default' => array( '#engine' => 'Convert\\NativeMeta', ), ), + 'pptx->(directory/slideshow|zip/slideshow)' => array( + 'nativeslideshow:schedule' => array( + '#engine' => 'Convert\\NativeSlideshow', + 'mode' => 'schedule', + 'captions' => FALSE, + ), + ), 'rtf->pdf' => array( 'unoconv:default' => array( '#engine' => 'Convert\\Unoconv', diff --git a/src/Engine/Chain.php b/src/Engine/Chain.php index 7547b46..81143b3 100644 --- a/src/Engine/Chain.php +++ b/src/Engine/Chain.php @@ -23,27 +23,35 @@ public function convertFile($source, $destination) { } // Iterate through the chain. - $s_path = $this->getTempFile(array_shift($links)); + $c0 = array_shift($links); + $s_path = $this->getTempFile($c0); copy($source, $s_path); while (!empty($links)) { try { - $d_path = $this->getTempFile(array_shift($links)); - $this->converter->convertFile($s_path, $d_path); + $c1 = array_shift($links); + if (empty($links)) { + $d_path = $destination; + } + else { + $d_path = $this->getTempFile($c1); + } + $this->converter->convertFile($s_path, $d_path, "$c0->$c1"); unlink($s_path); - if (!is_file($d_path)) { + if (!is_file($d_path) && !is_dir($d_path)) { throw new \ErrorException("Conversion failed."); } $s_path = $d_path; + $c0 = $c1; } catch (\Exception $e) { - unlink($s_path); - if (is_file($d_path)) { + if (is_file($s_path) && $s_path !== $source) { + unlink($s_path); + } + if (is_file($d_path) && $d_path !== $destination) { unlink($d_path); } throw $e; } } - - rename($d_path, $destination); return $this; } diff --git a/src/Engine/Convert/ImageMagick.php b/src/Engine/Convert/ImageMagick.php index 133d8f9..5f6dd4e 100644 --- a/src/Engine/Convert/ImageMagick.php +++ b/src/Engine/Convert/ImageMagick.php @@ -15,6 +15,16 @@ use FileConverter\Engine\Helper\Archive; class ImageMagick extends EngineBase { protected $cmd_options = array( + array( + 'name' => 'density', + 'mode' => Shell::SHELL_ARG_BASIC_SGL, + // Density is important when converting from PDF or vector + // System default: 72 + // Higher density effectively increases the image size + // Higher density can combine with `-resize 50%` for "supersampling" + 'default' => NULL, + 'group' => 1, + ), array( 'name' => 'resize', 'mode' => Shell::SHELL_ARG_BASIC_SGL, @@ -65,14 +75,14 @@ public function convertFile($source, $destination) { $tmp = $archive->getTempDirectory(); // Rename the multiple image files in a standardized way if (is_file("$imagePath/page.$ext")) { - $path = "$tmp/img/page1.$ext"; + $path = "$tmp/page1.$ext"; $this->isTempWritable($path); rename("$imagePath/page.$ext", $path); } else { $i = 0; while (is_file("$imagePath/page-$i.$ext")) { - $path = "$tmp/img/page" . ($i + 1) . ".$ext"; + $path = "$tmp/page" . ($i + 1) . ".$ext"; $this->isTempWritable($path); rename("$imagePath/page-$i.$ext", $path); ++$i; diff --git a/src/Engine/Convert/NativeMeta.php b/src/Engine/Convert/NativeMeta.php index 80866b9..c394c5c 100644 --- a/src/Engine/Convert/NativeMeta.php +++ b/src/Engine/Convert/NativeMeta.php @@ -37,7 +37,7 @@ public function convertFile($source, $destination) { $files = Splash::fromArray($files); // Build the slides. - $meta['slides'] = array(); + $meta['items'] = array(); foreach ($files->regex("@ppt/slides/slide\d+.xml$@") as $file) { $slide = array(); $number = preg_replace('@^ppt/slides/slide(\d+)\.xml$@s', '\1', $file); @@ -74,9 +74,9 @@ public function convertFile($source, $destination) { $slide['notes'] = $note; } - $meta['slides'][$number - 1] = $slide; + $meta['items'][$number - 1] = $slide; } - ksort($meta['slides']); + ksort($meta['items']); break; diff --git a/src/Engine/Convert/NativeSlideshow.php b/src/Engine/Convert/NativeSlideshow.php new file mode 100644 index 0000000..7983ec3 --- /dev/null +++ b/src/Engine/Convert/NativeSlideshow.php @@ -0,0 +1,148 @@ +configuration = array_replace(array( + 'mode' => 'default', + ), (array) $this->configuration); + + // Create a folder containing all of the images + $imageArchive = new Archive($this); + $imagePath = $imageArchive->getTempDirectory(); + $this->converter->convertFile($source, $imagePath, $this->conversion[0] + . '->directory/jpg'); + + // Build the slideshow configuration + $slideshow = array( + 'title' => 'Slideshow', + 'items' => array(), + ); + foreach ($this->configuration as $k => $v) { + if ($k{0} !== '#') { + $slideshow[$k] = $v; + } + } + try { + // Get the configuration for the slides. + $tmpJson = $this->getTempFile('.json'); + $this->converter->convertFile($source, $tmpJson, $this->conversion[0] + . '->json'); + $slideshow = array_replace($slideshow, (array) json_decode(file_get_contents($tmpJson), TRUE)); + + // Apply the slideshow mode. + foreach ($slideshow['items'] as $i => &$slide) { + if (!isset($slide['notes'])) { + if ($slideshow['mode'] === 'schedule') { + unset($slideshow['items'][$i]); + } + } + else { + // Extract settings from the slide notes. + $keys = array( + '@(?SLIDESHOW\.[^:]+):(?[^\n]+)(?:\n|$)@s', + '@(?BEGIN):(?[^\n]+)(?:\n|$)@s', + '@(?TITLE):(?[^\n]+)(?:\n|$)@s', + '@(?DESCRIPTION):(?[^\n]+)(?:\n|$)@s', + ); + foreach ($keys as $match) { + if (preg_match($match, $slide['notes'], $arr)) { + if (strpos($arr['k'], 'SLIDESHOW.') === 0) { + $slideshow[strtolower(substr($arr['k'], 10))] = $arr['v']; + } + else { + $slide[strtolower($arr['k'])] = $arr['v']; + } + } + } + unset($slide['notes']); + } + } + unset($slide); + $slideshow['items'] = array_values($slideshow['items']); + } catch (\Exception $e) { + // Build the default meta data based on the images. + $slideshow['mode'] = 'default'; + $i = 1; + while (is_file("$imagePath/page$i.jpg")) { + $slideshow['items'][] = array( + 'number' => $i, + 'title' => "Slide $i", + ); + ++$i; + } + } + + // Build the actual slideshow archive. + $archive = new Archive($this); + $tmp = $archive->getTempDirectory(); + file_put_contents("$tmp/meta.json", json_encode($slideshow)); + + // Copy the images as appropriate. + foreach ($slideshow['items'] as $slide) { + $from = "$imagePath/page$slide[number].jpg"; + $to = "$tmp/img/slide$slide[number].jpg"; + $this->isTempWritable($to); + copy($from, $to); + } + + // Copy the slideshow resources. + $to = "$tmp/js/slideshow.js"; + $this->isTempWritable($to); + copy(__DIR__ . '/Resources/Slideshow/slideshow.js', $to); + $to = "$tmp/css/slideshow.css"; + $this->isTempWritable($to); + copy(__DIR__ . '/Resources/Slideshow/slideshow.css', $to); + + // The index file involves template variables. + // Provide a raw + $to = "$tmp/index.htm"; + $this->isTempWritable($to); + $content = file_get_contents(__DIR__ . '/Resources/Slideshow/index.htm'); + $content = strtr($content, array( + '{{ slideshow.title|escape }}' => htmlspecialchars($slideshow['title']), + '{{ slideshow|json_encode() }}' => json_encode($slideshow), + )); + file_put_contents($to, $content); + + // Save the slideshow. + $archive->save($destination); + } + + protected function getHelpInstallation($os, $os_version) { + $help = array( + 'title' => 'Native Slideshow Extractor', + ); + switch ($os) { + case 'Ubuntu': + $help['os'] = 'confirmed on Ubuntu 16.04'; + $help['notes'] = array( + 'composer update', + ); + return $help; + } + + return parent::getHelpInstallation($os, $os_version); + } + + public function isAvailable() { + return TRUE; + } + +} \ No newline at end of file diff --git a/src/Engine/Convert/Resources/Slideshow/index.htm b/src/Engine/Convert/Resources/Slideshow/index.htm new file mode 100644 index 0000000..0734126 --- /dev/null +++ b/src/Engine/Convert/Resources/Slideshow/index.htm @@ -0,0 +1,35 @@ + + + + + + + + + + {{ slideshow.title|escape }} + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/Engine/Convert/Resources/Slideshow/slideshow.css b/src/Engine/Convert/Resources/Slideshow/slideshow.css new file mode 100644 index 0000000..e69de29 diff --git a/src/Engine/Convert/Resources/Slideshow/slideshow.js b/src/Engine/Convert/Resources/Slideshow/slideshow.js new file mode 100644 index 0000000..db64ce5 --- /dev/null +++ b/src/Engine/Convert/Resources/Slideshow/slideshow.js @@ -0,0 +1,81 @@ +function slideshow(s) { + var $ = jQuery; + var $carousel = $('