From cf2b418f525599ec6175f9c1d1e3c49925c9740d Mon Sep 17 00:00:00 2001 From: Roberto Butti Date: Tue, 10 Sep 2024 08:55:59 +0200 Subject: [PATCH 1/2] Embed epub images ,and fix relative path for PDF --- CHANGELOG.md | 5 ++ composer.lock | 142 +++++++++++++++--------------- readme.md | 15 +++- src/Commands/BaseBuildCommand.php | 49 ++++++++++- src/Commands/BuildEpubCommand.php | 30 ++++++- src/Commands/BuildPdfCommand.php | 9 +- 6 files changed, 167 insertions(+), 83 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index bee627b..8553691 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,10 @@ # Changelog +## 1.2.0 - 10th September 2024 +- Embed images for EPUB +- Fix loading image via relative path +- Updating dependencies + ## 1.1.2 - 3rd September 2024 - Adding Markdown custom extension for managing attributes (like CSS class) - Updating dependencies diff --git a/composer.lock b/composer.lock index c7be0ef..9d5a4f8 100644 --- a/composer.lock +++ b/composer.lock @@ -2526,20 +2526,20 @@ }, { "name": "symfony/polyfill-ctype", - "version": "v1.30.0", + "version": "v1.31.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-ctype.git", - "reference": "0424dff1c58f028c451efff2045f5d92410bd540" + "reference": "a3cc8b044a6ea513310cbd48ef7333b384945638" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/0424dff1c58f028c451efff2045f5d92410bd540", - "reference": "0424dff1c58f028c451efff2045f5d92410bd540", + "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/a3cc8b044a6ea513310cbd48ef7333b384945638", + "reference": "a3cc8b044a6ea513310cbd48ef7333b384945638", "shasum": "" }, "require": { - "php": ">=7.1" + "php": ">=7.2" }, "provide": { "ext-ctype": "*" @@ -2585,7 +2585,7 @@ "portable" ], "support": { - "source": "https://github.com/symfony/polyfill-ctype/tree/v1.30.0" + "source": "https://github.com/symfony/polyfill-ctype/tree/v1.31.0" }, "funding": [ { @@ -2601,24 +2601,24 @@ "type": "tidelift" } ], - "time": "2024-05-31T15:07:36+00:00" + "time": "2024-09-09T11:45:10+00:00" }, { "name": "symfony/polyfill-intl-grapheme", - "version": "v1.30.0", + "version": "v1.31.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-grapheme.git", - "reference": "64647a7c30b2283f5d49b874d84a18fc22054b7a" + "reference": "b9123926e3b7bc2f98c02ad54f6a4b02b91a8abe" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/64647a7c30b2283f5d49b874d84a18fc22054b7a", - "reference": "64647a7c30b2283f5d49b874d84a18fc22054b7a", + "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/b9123926e3b7bc2f98c02ad54f6a4b02b91a8abe", + "reference": "b9123926e3b7bc2f98c02ad54f6a4b02b91a8abe", "shasum": "" }, "require": { - "php": ">=7.1" + "php": ">=7.2" }, "suggest": { "ext-intl": "For best performance" @@ -2663,7 +2663,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.30.0" + "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.31.0" }, "funding": [ { @@ -2679,24 +2679,24 @@ "type": "tidelift" } ], - "time": "2024-05-31T15:07:36+00:00" + "time": "2024-09-09T11:45:10+00:00" }, { "name": "symfony/polyfill-intl-normalizer", - "version": "v1.30.0", + "version": "v1.31.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-normalizer.git", - "reference": "a95281b0be0d9ab48050ebd988b967875cdb9fdb" + "reference": "3833d7255cc303546435cb650316bff708a1c75c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/a95281b0be0d9ab48050ebd988b967875cdb9fdb", - "reference": "a95281b0be0d9ab48050ebd988b967875cdb9fdb", + "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/3833d7255cc303546435cb650316bff708a1c75c", + "reference": "3833d7255cc303546435cb650316bff708a1c75c", "shasum": "" }, "require": { - "php": ">=7.1" + "php": ">=7.2" }, "suggest": { "ext-intl": "For best performance" @@ -2744,7 +2744,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.30.0" + "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.31.0" }, "funding": [ { @@ -2760,24 +2760,24 @@ "type": "tidelift" } ], - "time": "2024-05-31T15:07:36+00:00" + "time": "2024-09-09T11:45:10+00:00" }, { "name": "symfony/polyfill-mbstring", - "version": "v1.30.0", + "version": "v1.31.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-mbstring.git", - "reference": "fd22ab50000ef01661e2a31d850ebaa297f8e03c" + "reference": "85181ba99b2345b0ef10ce42ecac37612d9fd341" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/fd22ab50000ef01661e2a31d850ebaa297f8e03c", - "reference": "fd22ab50000ef01661e2a31d850ebaa297f8e03c", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/85181ba99b2345b0ef10ce42ecac37612d9fd341", + "reference": "85181ba99b2345b0ef10ce42ecac37612d9fd341", "shasum": "" }, "require": { - "php": ">=7.1" + "php": ">=7.2" }, "provide": { "ext-mbstring": "*" @@ -2824,7 +2824,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.30.0" + "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.31.0" }, "funding": [ { @@ -2840,24 +2840,24 @@ "type": "tidelift" } ], - "time": "2024-06-19T12:30:46+00:00" + "time": "2024-09-09T11:45:10+00:00" }, { "name": "symfony/polyfill-php80", - "version": "v1.30.0", + "version": "v1.31.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php80.git", - "reference": "77fa7995ac1b21ab60769b7323d600a991a90433" + "reference": "60328e362d4c2c802a54fcbf04f9d3fb892b4cf8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/77fa7995ac1b21ab60769b7323d600a991a90433", - "reference": "77fa7995ac1b21ab60769b7323d600a991a90433", + "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/60328e362d4c2c802a54fcbf04f9d3fb892b4cf8", + "reference": "60328e362d4c2c802a54fcbf04f9d3fb892b4cf8", "shasum": "" }, "require": { - "php": ">=7.1" + "php": ">=7.2" }, "type": "library", "extra": { @@ -2904,7 +2904,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php80/tree/v1.30.0" + "source": "https://github.com/symfony/polyfill-php80/tree/v1.31.0" }, "funding": [ { @@ -2920,24 +2920,24 @@ "type": "tidelift" } ], - "time": "2024-05-31T15:07:36+00:00" + "time": "2024-09-09T11:45:10+00:00" }, { "name": "symfony/polyfill-php83", - "version": "v1.30.0", + "version": "v1.31.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php83.git", - "reference": "dbdcdf1a4dcc2743591f1079d0c35ab1e2dcbbc9" + "reference": "2fb86d65e2d424369ad2905e83b236a8805ba491" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php83/zipball/dbdcdf1a4dcc2743591f1079d0c35ab1e2dcbbc9", - "reference": "dbdcdf1a4dcc2743591f1079d0c35ab1e2dcbbc9", + "url": "https://api.github.com/repos/symfony/polyfill-php83/zipball/2fb86d65e2d424369ad2905e83b236a8805ba491", + "reference": "2fb86d65e2d424369ad2905e83b236a8805ba491", "shasum": "" }, "require": { - "php": ">=7.1" + "php": ">=7.2" }, "type": "library", "extra": { @@ -2980,7 +2980,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php83/tree/v1.30.0" + "source": "https://github.com/symfony/polyfill-php83/tree/v1.31.0" }, "funding": [ { @@ -2996,7 +2996,7 @@ "type": "tidelift" } ], - "time": "2024-06-19T12:35:24+00:00" + "time": "2024-09-09T11:45:10+00:00" }, { "name": "symfony/service-contracts", @@ -4042,16 +4042,16 @@ }, { "name": "nunomaduro/termwind", - "version": "v2.0.1", + "version": "v2.1.0", "source": { "type": "git", "url": "https://github.com/nunomaduro/termwind.git", - "reference": "58c4c58cf23df7f498daeb97092e34f5259feb6a" + "reference": "e5f21eade88689536c0cdad4c3cd75f3ed26e01a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nunomaduro/termwind/zipball/58c4c58cf23df7f498daeb97092e34f5259feb6a", - "reference": "58c4c58cf23df7f498daeb97092e34f5259feb6a", + "url": "https://api.github.com/repos/nunomaduro/termwind/zipball/e5f21eade88689536c0cdad4c3cd75f3ed26e01a", + "reference": "e5f21eade88689536c0cdad4c3cd75f3ed26e01a", "shasum": "" }, "require": { @@ -4061,11 +4061,11 @@ }, "require-dev": { "ergebnis/phpstan-rules": "^2.2.0", - "illuminate/console": "^11.0.0", - "laravel/pint": "^1.14.0", - "mockery/mockery": "^1.6.7", - "pestphp/pest": "^2.34.1", - "phpstan/phpstan": "^1.10.59", + "illuminate/console": "^11.1.1", + "laravel/pint": "^1.15.0", + "mockery/mockery": "^1.6.11", + "pestphp/pest": "^2.34.6", + "phpstan/phpstan": "^1.10.66", "phpstan/phpstan-strict-rules": "^1.5.2", "symfony/var-dumper": "^7.0.4", "thecodingmachine/phpstan-strict-rules": "^1.0.0" @@ -4110,7 +4110,7 @@ ], "support": { "issues": "https://github.com/nunomaduro/termwind/issues", - "source": "https://github.com/nunomaduro/termwind/tree/v2.0.1" + "source": "https://github.com/nunomaduro/termwind/tree/v2.1.0" }, "funding": [ { @@ -4126,7 +4126,7 @@ "type": "github" } ], - "time": "2024-03-06T16:17:14+00:00" + "time": "2024-09-05T15:25:50+00:00" }, { "name": "pestphp/pest", @@ -4672,16 +4672,16 @@ }, { "name": "phpstan/phpdoc-parser", - "version": "1.30.0", + "version": "1.30.1", "source": { "type": "git", "url": "https://github.com/phpstan/phpdoc-parser.git", - "reference": "5ceb0e384997db59f38774bf79c2a6134252c08f" + "reference": "51b95ec8670af41009e2b2b56873bad96682413e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/5ceb0e384997db59f38774bf79c2a6134252c08f", - "reference": "5ceb0e384997db59f38774bf79c2a6134252c08f", + "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/51b95ec8670af41009e2b2b56873bad96682413e", + "reference": "51b95ec8670af41009e2b2b56873bad96682413e", "shasum": "" }, "require": { @@ -4713,22 +4713,22 @@ "description": "PHPDoc parser with support for nullable, intersection and generic types", "support": { "issues": "https://github.com/phpstan/phpdoc-parser/issues", - "source": "https://github.com/phpstan/phpdoc-parser/tree/1.30.0" + "source": "https://github.com/phpstan/phpdoc-parser/tree/1.30.1" }, - "time": "2024-08-29T09:54:52+00:00" + "time": "2024-09-07T20:13:05+00:00" }, { "name": "phpstan/phpstan", - "version": "1.12.1", + "version": "1.12.3", "source": { "type": "git", "url": "https://github.com/phpstan/phpstan.git", - "reference": "d8ed7fffa66de1db0d2972267d8ed1d8fa0fe5a2" + "reference": "0fcbf194ab63d8159bb70d9aa3e1350051632009" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan/zipball/d8ed7fffa66de1db0d2972267d8ed1d8fa0fe5a2", - "reference": "d8ed7fffa66de1db0d2972267d8ed1d8fa0fe5a2", + "url": "https://api.github.com/repos/phpstan/phpstan/zipball/0fcbf194ab63d8159bb70d9aa3e1350051632009", + "reference": "0fcbf194ab63d8159bb70d9aa3e1350051632009", "shasum": "" }, "require": { @@ -4773,7 +4773,7 @@ "type": "github" } ], - "time": "2024-09-03T19:55:22+00:00" + "time": "2024-09-09T08:10:35+00:00" }, { "name": "phpunit/php-code-coverage", @@ -5199,21 +5199,21 @@ }, { "name": "rector/rector", - "version": "1.2.4", + "version": "1.2.5", "source": { "type": "git", "url": "https://github.com/rectorphp/rector.git", - "reference": "42a4aa23b48b4cfc8ebfeac2b570364e27744381" + "reference": "e98aa793ca3fcd17e893cfaf9103ac049775d339" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/rectorphp/rector/zipball/42a4aa23b48b4cfc8ebfeac2b570364e27744381", - "reference": "42a4aa23b48b4cfc8ebfeac2b570364e27744381", + "url": "https://api.github.com/repos/rectorphp/rector/zipball/e98aa793ca3fcd17e893cfaf9103ac049775d339", + "reference": "e98aa793ca3fcd17e893cfaf9103ac049775d339", "shasum": "" }, "require": { "php": "^7.2|^8.0", - "phpstan/phpstan": "^1.11.11" + "phpstan/phpstan": "^1.12.2" }, "conflict": { "rector/rector-doctrine": "*", @@ -5246,7 +5246,7 @@ ], "support": { "issues": "https://github.com/rectorphp/rector/issues", - "source": "https://github.com/rectorphp/rector/tree/1.2.4" + "source": "https://github.com/rectorphp/rector/tree/1.2.5" }, "funding": [ { @@ -5254,7 +5254,7 @@ "type": "github" } ], - "time": "2024-08-23T09:03:01+00:00" + "time": "2024-09-08T17:43:24+00:00" }, { "name": "sebastian/cli-parser", diff --git a/readme.md b/readme.md index c4221ab..9d29530 100644 --- a/readme.md +++ b/readme.md @@ -202,12 +202,23 @@ Three quotes can be added: `quote`, `warning`, and `notice`. ### Using images -Images can be stored in the content folder and then brought in like this: +Images can be added into the markdown in two different way: + +1. using a remote image: ~~~markdown -![Screenshot 1](content/screenshot-1.png) +![Ibis Next Cover Image](https://raw.githubusercontent.com/hi-folks/ibis-next/main/art/ibis-next-cover.png) ~~~ +2. using a relative path, in this case the path is realtive to the content directory, where you have your Markdown files (the default is `./content/`): + +~~~markdown +![Ibis Next Cover Image](../assets/images/ibis-next-cover.png) +~~~ + +It also works with absolute paths, but I don't recommend using this option as it's strongly tied to your specific machine. + + ### Adding a cover image To use a cover image, add a `cover.jpg` in the `assets/` directory (or a `cover.html` file if you'd prefer an HTML-based cover page). If you don't want a cover image, delete these files. If your cover is in a PNG format, you can store the file in the `assets/` directory, and then in the `ibis.php` file, you can adjust the `cover` configuration where you can set the cover file name, for example: diff --git a/src/Commands/BaseBuildCommand.php b/src/Commands/BaseBuildCommand.php index 9fe8cf6..52e526e 100644 --- a/src/Commands/BaseBuildCommand.php +++ b/src/Commands/BaseBuildCommand.php @@ -63,8 +63,11 @@ protected function preExecute(InputInterface $input, OutputInterface $output): b } - protected function buildHtml(string $path, array $config): Collection - { + protected function buildHtml( + string $path, + array $config, + bool $extractImages = false, + ): Collection { $this->output->writeln('==> Parsing Markdown ...'); @@ -102,7 +105,7 @@ protected function buildHtml(string $path, array $config): Collection } return collect($fileList) - ->map(function (SplFileInfo $file, $i) use ($converter, $config) { + ->map(function (SplFileInfo $file, $i) use ($converter, $config, $extractImages) { $chapter = collect([]); if ($file->getExtension() !== 'md') { @@ -116,6 +119,12 @@ protected function buildHtml(string $path, array $config): Collection $file->getPathname(), ); + if ($extractImages) { + $pattern = '/!\[.*?\]\((.*?)\)/'; + preg_match_all($pattern, $markdown, $matches); + $chapter->put("images", $matches[1]); + } + $convertedMarkdown = $converter->convert($markdown); $chapter->put("mdfile", $file->getFilename()); $chapter->put("frontmatter", false); @@ -183,4 +192,38 @@ protected function ensureExportDirectoryExists(string $currentPath): void } } + + + public function isAbsolutePath($path) + { + /* + * Check to see if the path is a stream and check to see if its an actual + * path or file as realpath() does not support stream wrappers. + */ + if ((is_dir($path) || is_file($path))) { + return true; + } + + /* + * This is definitive if true but fails if $path does not exist or contains + * a symbolic link. + */ + if (realpath($path) === $path) { + return true; + } + + if ((string) $path === '' || '.' === $path[0]) { + return false; + } + + // Windows allows absolute paths like this. + if (preg_match('#^[a-zA-Z]:\\\\#', (string) $path)) { + return true; + } + + // A path starting with / or \ is absolute; anything else is relative. + return ('/' === $path[0] || '\\' === $path[0]); + } + + } diff --git a/src/Commands/BuildEpubCommand.php b/src/Commands/BuildEpubCommand.php index 43267a4..1d0662b 100644 --- a/src/Commands/BuildEpubCommand.php +++ b/src/Commands/BuildEpubCommand.php @@ -62,7 +62,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int $this->config->config["breakLevel"] = 1; $result = $this->buildEpub( - $this->buildHtml($this->config->contentPath, $this->config->config), + $this->buildHtml($this->config->contentPath, $this->config->config, extractImages: true), $this->config->config, $this->config->workingPath, ); @@ -83,8 +83,11 @@ protected function execute(InputInterface $input, OutputInterface $output): int /** * @throws FileNotFoundException */ - protected function buildEpub(Collection $chapters, array $config, string $currentPath): bool - { + protected function buildEpub( + Collection $chapters, + array $config, + string $currentPath, + ): bool { $content_start = "\n" @@ -152,6 +155,27 @@ protected function buildEpub(Collection $chapters, array $config, string $curren chapterData: $content_start . $chapter["html"] . $content_end, externalReferences: EPub::EXTERNAL_REF_ADD, ); + foreach (Arr::get($chapter, "images", []) as $idxImage => $image) { + if (filter_var($image, FILTER_VALIDATE_URL)) { + continue; + } + + if (! $this->isAbsolutePath($image)) { + $image = $this->config->contentPath . "/" . $image; + } + + if (!file_exists($image)) { + continue; + } + + $book->addLargeFile( + $image, + "image-" . $key . "-" . $idxImage, + $image, + mime_content_type($image), + ); + } + //file_put_contents('export/' . "Chapter" . $key . " .html", $content_start . $chapter["html"] . $content_end); } diff --git a/src/Commands/BuildPdfCommand.php b/src/Commands/BuildPdfCommand.php index 23e876e..5038db6 100644 --- a/src/Commands/BuildPdfCommand.php +++ b/src/Commands/BuildPdfCommand.php @@ -119,7 +119,8 @@ protected function buildPdf(Collection $chapters, array $config, string $current $pdf->SetTitle($this->config->title()); $pdf->SetAuthor($this->config->author()); $pdf->SetCreator($this->config->author()); - + // $pdf->debug = true; + $pdf->SetBasePath(realpath($this->config->contentPath)); $pdf->setAutoTopMargin = 'pad'; $pdf->setAutoBottomMargin = 'pad'; @@ -140,11 +141,11 @@ protected function buildPdf(Collection $chapters, array $config, string $current $coverPosition = $config['cover']['position'] ?? 'position: absolute; left:0; right: 0; top: -.2; bottom: 0;'; $coverDimensions = $config['cover']['dimensions'] ?? 'width: 210mm; height: 297mm; margin: 0;'; - + $coverImageAbsPath = realpath(sprintf('%s/assets/%s', $currentPath, $coverImage)); $pdf->WriteHTML( << - + HTML, ); @@ -169,7 +170,7 @@ protected function buildPdf(Collection $chapters, array $config, string $current $pdf->WriteHTML( $theme, ); - //dd($chapters); + foreach ($chapters as $chapter) { //if ( is_string($chapter) ) { dd($key, $chapter);} $this->output->writeln('==> ❇️ ' . $chapter["mdfile"] . ' ...'); From d31510ec5f2aad8819ca6d112568b71705f31853 Mon Sep 17 00:00:00 2001 From: Roberto Butti Date: Tue, 10 Sep 2024 08:58:27 +0200 Subject: [PATCH 2/2] fix cs rule --- src/Commands/BuildPdfCommand.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Commands/BuildPdfCommand.php b/src/Commands/BuildPdfCommand.php index 5038db6..36363f9 100644 --- a/src/Commands/BuildPdfCommand.php +++ b/src/Commands/BuildPdfCommand.php @@ -121,6 +121,7 @@ protected function buildPdf(Collection $chapters, array $config, string $current $pdf->SetCreator($this->config->author()); // $pdf->debug = true; $pdf->SetBasePath(realpath($this->config->contentPath)); + $pdf->setAutoTopMargin = 'pad'; $pdf->setAutoBottomMargin = 'pad';