*/
protected function getImageValidationRules(): array
{
- return ['image_extension', 'mimes:jpeg,png,gif,webp', 'max:' . (config('app.upload_limit') * 1000)];
+ return ['image_extension', 'mimes:jpeg,png,gif,webp,svg', 'max:' . (config('app.upload_limit') * 1000)];
}
}
protected $image;
protected $fileSystem;
- protected static $supportedExtensions = ['jpg', 'jpeg', 'png', 'gif', 'webp'];
+ protected static $supportedExtensions = ['jpg', 'jpeg', 'png', 'gif', 'webp', 'svg'];
/**
* ImageService constructor.
return strtolower(pathinfo($image->path, PATHINFO_EXTENSION)) === 'gif';
}
+ /**
+ * Check if the given image is an SVG image file.
+ */
+ protected function isSvg(Image $image): bool
+ {
+ return strtolower(pathinfo($image->path, PATHINFO_EXTENSION)) === 'svg';
+ }
+
/**
* Check if the given image and image data is apng.
*/
*/
public function getThumbnail(Image $image, ?int $width, ?int $height, bool $keepRatio = false): string
{
- // Do not resize GIF images where we're not cropping
- if ($keepRatio && $this->isGif($image)) {
+ // Do not resize GIF images where we're not cropping or SVG images.
+ if (($keepRatio && $this->isGif($image)) || $this->isSvg($image)) {
return $this->getPublicUrl($image->path);
}
$this->assertStringNotContainsString('thumbs-', $imgDetails['response']->thumbs->display);
}
+ public function test_svg_upload()
+ {
+ /** @var Page $page */
+ $page = Page::query()->first();
+ $admin = $this->getAdmin();
+ $this->actingAs($admin);
+
+ $imgDetails = $this->uploadGalleryImage($page, 'diagram.svg', 'image/svg+xml');
+ $this->assertFileExists(public_path($imgDetails['path']));
+ $this->assertTrue(
+ $imgDetails['response']->url === $imgDetails['response']->thumbs->gallery
+ && $imgDetails['response']->url === $imgDetails['response']->thumbs->display,
+ );
+
+ $this->deleteImage($imgDetails['path']);
+ }
+
public function test_image_edit()
{
$editor = $this->getEditor();
namespace Tests\Uploads;
use BookStack\Entities\Models\Page;
+use BookStack\Uploads\Image;
use Illuminate\Http\UploadedFile;
use stdClass;
* Returns the image name.
* Can provide a page to relate the image to.
*
- * @param Page|null $page
- *
* @return array{name: string, path: string, page: Page, response: stdClass}
*/
- protected function uploadGalleryImage(Page $page = null, ?string $testDataFileName = null)
+ protected function uploadGalleryImage(Page $page = null, string $testDataFileName = 'first-image.png', string $contentType = 'image/png')
{
if ($page === null) {
$page = Page::query()->first();
}
- $imageName = $testDataFileName ?? 'first-image.png';
+ $imageName = $testDataFileName;
$relPath = $this->getTestImagePath('gallery', $imageName);
$this->deleteImage($relPath);
- $upload = $this->uploadImage($imageName, $page->id, 'image/png', $testDataFileName);
+ $upload = $this->uploadImage($imageName, $page->id, $contentType, $testDataFileName);
$upload->assertStatus(200);
return [
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg xmlns="http://www.w3.org/2000/svg" style="background-color: rgb(255, 255, 255);" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="121px" height="141px" viewBox="-0.5 -0.5 121 141"><defs/><g><ellipse cx="25" cy="87.5" rx="7.5" ry="7.5" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" pointer-events="all"/><path d="M 25 95 L 25 120 M 25 100 L 10 100 M 25 100 L 40 100 M 25 120 L 10 140 M 25 120 L 40 140" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><path d="M 0 0 L 120 0 L 120 50 L 80 50 L 60 80 L 60 50 L 0 50 Z" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 25px; margin-left: 1px;"><div style="box-sizing: border-box; font-size: 0px; text-align: center;" data-drawio-colors="color: rgb(0, 0, 0); "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">Hello!</div></div></div></foreignObject><text x="60" y="29" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">Hello!</text></switch></g></g><switch><g requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"/><a transform="translate(0,-5)" xlink:href="https://www.diagrams.net/doc/faq/svg-export-text-problems" target="_blank"><text text-anchor="middle" font-size="10px" x="50%" y="100%">Text is not SVG - cannot display</text></a></switch></svg>
\ No newline at end of file