Skip to content

Commit

Permalink
Merge pull request #251 from Roave/support-markdown-images
Browse files Browse the repository at this point in the history
New feature: support images in markdown
  • Loading branch information
Ocramius authored Sep 22, 2022
2 parents 453dbf5 + 903832c commit 2bdd81e
Show file tree
Hide file tree
Showing 16 changed files with 345 additions and 69 deletions.
11 changes: 11 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ RUN \
php8.1-mbstring \
php8.1-xml \
php8.1-curl \
php8.1-gd \
nodejs \
openjdk-18-jre \
xfonts-75dpi \
Expand Down Expand Up @@ -123,6 +124,16 @@ RUN \
--mount=type=cache,target=/root/.composer,id=composer \
composer install

FROM development AS test-output-builder

COPY --link ./test/fixture/templates /docs-src/templates
COPY --link ./test/fixture/docbook /docs-src/book
COPY --link ./test/fixture/feature /docs-src/features
RUN bin/docbook-tool --html --pdf

FROM scratch AS test-output

COPY --from=test-output-builder /docs-package /

FROM development AS tested

Expand Down
5 changes: 5 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -21,5 +21,10 @@ cs: build ## Run coding standards checks
static-analysis: build ## Run the static analysis checks
docker run --rm --entrypoint=php ghcr.io/roave/docbooktool:test-image vendor/bin/psalm

test-output: ## Write the test fixture outputs to build/ directory - useful for manual visual inspection
rm -Rf build
mkdir -p build
docker buildx build --output=build --target=test-output --tag=ghcr.io/roave/docbooktool:test-image .

production: ## Build and tag a production image
docker buildx build --load --target=production --tag=ghcr.io/roave/docbooktool:latest .
2 changes: 2 additions & 0 deletions bin/docbook-tool.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
use Monolog\Logger;
use Roave\DocbookTool\Formatter\AggregatePageFormatter;
use Roave\DocbookTool\Formatter\ExtractFrontMatter;
use Roave\DocbookTool\Formatter\InlineExternalImages;
use Roave\DocbookTool\Formatter\InlineFeatureFile;
use Roave\DocbookTool\Formatter\MarkdownToHtml;
use Roave\DocbookTool\Formatter\RenderPlantUmlDiagramInline;
Expand Down Expand Up @@ -40,6 +41,7 @@

$pageFormatters = [
new ExtractFrontMatter(),
new InlineExternalImages($contentPath),
new RenderPlantUmlDiagramInline(),
new MarkdownToHtml(),
];
Expand Down
1 change: 1 addition & 0 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
],
"require": {
"php": "~8.1.3",
"ext-gd": "*",
"guzzlehttp/guzzle": "^7.5",
"guzzlehttp/psr7": "^2.4",
"jasny/twig-extensions": "^1.3",
Expand Down
195 changes: 129 additions & 66 deletions composer.lock

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions phpcs.xml.dist
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

<file>bin</file>
<file>src</file>
<file>test/unit</file>
<file>test/integration</file>

<rule ref="Doctrine">
Expand Down
1 change: 1 addition & 0 deletions psalm.xml.dist
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
<projectFiles>
<directory name="src" />
<directory name="bin" />
<directory name="test/unit" />
<directory name="test/integration" />
<ignoreFiles>
<directory name="vendor" />
Expand Down
57 changes: 57 additions & 0 deletions src/Formatter/InlineExternalImages.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
<?php

declare(strict_types=1);

namespace Roave\DocbookTool\Formatter;

use Roave\DocbookTool\DocbookPage;
use RuntimeException;

use function array_key_exists;
use function base64_encode;
use function getimagesize;
use function is_array;
use function is_string;
use function preg_replace_callback;
use function Safe\file_get_contents;
use function sprintf;

final class InlineExternalImages implements PageFormatter
{
public function __construct(private readonly string $docbookPath)
{
}

/** @throws RuntimeException */
public function __invoke(DocbookPage $page): DocbookPage
{
return $page->withReplacedContent(
preg_replace_callback(
'/!\[([^]]+)]\(([^)]*?)\)/',
function (array $m) {
/** @var array{1: string, 2: string} $m */
$altText = $m[1];
$imagePath = $m[2];

$fullImagePath = $this->docbookPath . '/' . $imagePath;

$imageContent = file_get_contents($fullImagePath);

$imageInfo = getimagesize($fullImagePath);

if (! is_array($imageInfo) || ! array_key_exists('mime', $imageInfo) || ! is_string($imageInfo['mime'])) {
throw new RuntimeException('Unable to determine mime type of ' . $fullImagePath);
}

return sprintf(
'![%s](data:%s;base64,%s)',
$altText,
$imageInfo['mime'],
base64_encode($imageContent),
);
},
$page->content(),
),
);
}
}
Binary file added test/fixture/docbook/smile.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added test/fixture/docbook/smile.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added test/fixture/docbook/smile.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
10 changes: 10 additions & 0 deletions test/fixture/docbook/test.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,3 +36,13 @@ Bob->Alice : hello
hexagon TestingHexagon
@enduml
```

## Some images

Here are some images:

![A smiley face in PNG](./smile.png)
![A smiley face in JPG](./smile.jpg)
![A smiley face in GIF](./smile.gif)

They are hand drawn, that's why they look rubbish.
10 changes: 10 additions & 0 deletions test/fixture/expectations/out.html
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,16 @@ <h2>A diagram</h2>

<p><img src="data:image/png;base64,iVBORw%s" alt="Diagram" /></p>

<h2>Some images</h2>

<p>Here are some images:</p>

<p><img src="data:image/png;base64,iVBORw%s" alt="A smiley face in PNG" />
<img src="data:image/jpeg;base64,/9j/4A%s" alt="A smiley face in JPG" />
<img src="data:image/gif;base64,R0lGOD%s" alt="A smiley face in GIF" /></p>

<p>They are hand drawn, that's why they look rubbish.</p>

<br />
</section>
</div>
Expand Down
2 changes: 2 additions & 0 deletions test/integration/DocbookToolGeneratorTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
use Psr\Log\NullLogger;
use Roave\DocbookTool\Formatter\AggregatePageFormatter;
use Roave\DocbookTool\Formatter\ExtractFrontMatter;
use Roave\DocbookTool\Formatter\InlineExternalImages;
use Roave\DocbookTool\Formatter\InlineFeatureFile;
use Roave\DocbookTool\Formatter\MarkdownToHtml;
use Roave\DocbookTool\Formatter\RenderPlantUmlDiagramInline;
Expand Down Expand Up @@ -47,6 +48,7 @@ public function testGeneration(): void
[
new AggregatePageFormatter([
new ExtractFrontMatter(),
new InlineExternalImages(self::CONTENT_PATH),
new RenderPlantUmlDiagramInline(),
new MarkdownToHtml(),
new InlineFeatureFile(self::FEATURES_PATH),
Expand Down
12 changes: 9 additions & 3 deletions test/unit/Formatter/ExtractFrontMatterTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,16 @@

namespace Roave\DocbookToolUnitTest\Formatter;

use PHPUnit\Framework\TestCase;
use Roave\DocbookTool\DocbookPage;
use Roave\DocbookTool\Formatter\AggregatePageFormatter;
use Roave\DocbookTool\Formatter\ExtractFrontMatter;
use PHPUnit\Framework\TestCase;
use Roave\DocbookTool\Formatter\MarkdownToHtml;

/** @covers \Roave\DocbookTool\Formatter\ExtractFrontMatter */
final class ExtractFrontMatterTest extends TestCase
{
/** @return array<string,array{content:non-empty-string,expectedTitle:non-empty-string}> */
public function titleProvider(): array
{
return [
Expand Down Expand Up @@ -70,15 +71,20 @@ public function titleProvider(): array
];
}

/** @dataProvider titleProvider */
/**
* @param non-empty-string $content
* @param non-empty-string $expectedTitle
*
* @dataProvider titleProvider
*/
public function testTitleCanBeSetInFrontMatter(string $content, string $expectedTitle): void
{
self::assertSame(
$expectedTitle,
(new AggregatePageFormatter([
new ExtractFrontMatter(),
new MarkdownToHtml(),
]))(DocbookPage::fromSlugAndContent('slug', $content))->title()
]))(DocbookPage::fromSlugAndContent('slug', $content))->title(),
);
}
}
Loading

0 comments on commit 2bdd81e

Please sign in to comment.