mirror of
https://github.com/BookStackApp/BookStack.git
synced 2025-08-07 23:03:00 +03:00
Added SVG support to the image gallery.
This commit is contained in:
@@ -219,6 +219,6 @@ abstract class Controller extends BaseController
|
|||||||
*/
|
*/
|
||||||
protected function getImageValidationRules(): array
|
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)];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -30,7 +30,7 @@ class ImageService
|
|||||||
protected $image;
|
protected $image;
|
||||||
protected $fileSystem;
|
protected $fileSystem;
|
||||||
|
|
||||||
protected static $supportedExtensions = ['jpg', 'jpeg', 'png', 'gif', 'webp'];
|
protected static $supportedExtensions = ['jpg', 'jpeg', 'png', 'gif', 'webp', 'svg'];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ImageService constructor.
|
* ImageService constructor.
|
||||||
@@ -230,6 +230,14 @@ class ImageService
|
|||||||
return strtolower(pathinfo($image->path, PATHINFO_EXTENSION)) === 'gif';
|
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.
|
* Check if the given image and image data is apng.
|
||||||
*/
|
*/
|
||||||
@@ -255,8 +263,8 @@ class ImageService
|
|||||||
*/
|
*/
|
||||||
public function getThumbnail(Image $image, ?int $width, ?int $height, bool $keepRatio = false): string
|
public function getThumbnail(Image $image, ?int $width, ?int $height, bool $keepRatio = false): string
|
||||||
{
|
{
|
||||||
// Do not resize GIF images where we're not cropping
|
// Do not resize GIF images where we're not cropping or SVG images.
|
||||||
if ($keepRatio && $this->isGif($image)) {
|
if (($keepRatio && $this->isGif($image)) || $this->isSvg($image)) {
|
||||||
return $this->getPublicUrl($image->path);
|
return $this->getPublicUrl($image->path);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -74,6 +74,23 @@ class ImageTest extends TestCase
|
|||||||
$this->assertStringNotContainsString('thumbs-', $imgDetails['response']->thumbs->display);
|
$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()
|
public function test_image_edit()
|
||||||
{
|
{
|
||||||
$editor = $this->getEditor();
|
$editor = $this->getEditor();
|
||||||
|
@@ -3,6 +3,7 @@
|
|||||||
namespace Tests\Uploads;
|
namespace Tests\Uploads;
|
||||||
|
|
||||||
use BookStack\Entities\Models\Page;
|
use BookStack\Entities\Models\Page;
|
||||||
|
use BookStack\Uploads\Image;
|
||||||
use Illuminate\Http\UploadedFile;
|
use Illuminate\Http\UploadedFile;
|
||||||
use stdClass;
|
use stdClass;
|
||||||
|
|
||||||
@@ -84,21 +85,19 @@ trait UsesImages
|
|||||||
* Returns the image name.
|
* Returns the image name.
|
||||||
* Can provide a page to relate the image to.
|
* Can provide a page to relate the image to.
|
||||||
*
|
*
|
||||||
* @param Page|null $page
|
|
||||||
*
|
|
||||||
* @return array{name: string, path: string, page: Page, response: stdClass}
|
* @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) {
|
if ($page === null) {
|
||||||
$page = Page::query()->first();
|
$page = Page::query()->first();
|
||||||
}
|
}
|
||||||
|
|
||||||
$imageName = $testDataFileName ?? 'first-image.png';
|
$imageName = $testDataFileName;
|
||||||
$relPath = $this->getTestImagePath('gallery', $imageName);
|
$relPath = $this->getTestImagePath('gallery', $imageName);
|
||||||
$this->deleteImage($relPath);
|
$this->deleteImage($relPath);
|
||||||
|
|
||||||
$upload = $this->uploadImage($imageName, $page->id, 'image/png', $testDataFileName);
|
$upload = $this->uploadImage($imageName, $page->id, $contentType, $testDataFileName);
|
||||||
$upload->assertStatus(200);
|
$upload->assertStatus(200);
|
||||||
|
|
||||||
return [
|
return [
|
||||||
|
3
tests/test-data/diagram.svg
Normal file
3
tests/test-data/diagram.svg
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
<?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>
|
After Width: | Height: | Size: 1.9 KiB |
Reference in New Issue
Block a user