From: Dan Brown Date: Sun, 22 May 2022 11:38:50 +0000 (+0100) Subject: Updated draw.io code to support SVGs as primary data type X-Git-Url: http://source.bookstackapp.com/bookstack/commitdiff_plain/d926ca5f71314c40058932ac7886c5fe9e2c8a6b Updated draw.io code to support SVGs as primary data type --- diff --git a/app/Http/Controllers/Images/DrawioImageController.php b/app/Http/Controllers/Images/DrawioImageController.php index cab1c925e..31c375c25 100644 --- a/app/Http/Controllers/Images/DrawioImageController.php +++ b/app/Http/Controllers/Images/DrawioImageController.php @@ -76,8 +76,11 @@ class DrawioImageController extends Controller return $this->jsonError('Image data could not be found'); } + $isSvg = strtolower(pathinfo($image->path, PATHINFO_EXTENSION)) === 'svg'; + $uriPrefix = $isSvg ? 'data:image/svg+xml;base64,' : 'data:image/png;base64,'; + return response()->json([ - 'content' => base64_encode($imageData), + 'content' => $uriPrefix . base64_encode($imageData), ]); } } diff --git a/app/Uploads/ImageRepo.php b/app/Uploads/ImageRepo.php index bfe4b5977..24cd8c33d 100644 --- a/app/Uploads/ImageRepo.php +++ b/app/Uploads/ImageRepo.php @@ -148,7 +148,8 @@ class ImageRepo */ public function saveDrawing(string $base64Uri, int $uploadedTo): Image { - $name = 'Drawing-' . user()->id . '-' . time() . '.png'; + $isSvg = strpos($base64Uri, 'data:image/svg+xml;') === 0; + $name = 'Drawing-' . user()->id . '-' . time() . ($isSvg ? '.svg' : '.png'); return $this->imageService->saveNewFromBase64Uri($base64Uri, $name, 'drawio', $uploadedTo); } diff --git a/resources/js/components/markdown-editor.js b/resources/js/components/markdown-editor.js index 297d9c8ec..71a56af55 100644 --- a/resources/js/components/markdown-editor.js +++ b/resources/js/components/markdown-editor.js @@ -445,10 +445,10 @@ class MarkdownEditor { DrawIO.show(url,() => { return Promise.resolve(''); - }, (pngData) => { + }, (drawingData) => { const data = { - image: pngData, + image: drawingData, uploaded_to: Number(this.pageId), }; @@ -480,10 +480,10 @@ class MarkdownEditor { DrawIO.show(drawioUrl, () => { return DrawIO.load(drawingId); - }, (pngData) => { + }, (drawingData) => { let data = { - image: pngData, + image: drawingData, uploaded_to: Number(this.pageId), }; diff --git a/resources/js/services/drawio.js b/resources/js/services/drawio.js index dfca83211..141b61c72 100644 --- a/resources/js/services/drawio.js +++ b/resources/js/services/drawio.js @@ -55,7 +55,7 @@ function drawEventExport(message) { } function drawEventSave(message) { - drawPostMessage({action: 'export', format: 'xmlpng', xml: message.xml, spin: 'Updating drawing'}); + drawPostMessage({action: 'export', format: 'xmlsvg', xml: message.xml, spin: 'Updating drawing'}); } function drawEventInit() { @@ -96,7 +96,7 @@ async function upload(imageData, pageUploadedToId) { */ async function load(drawingId) { const resp = await window.$http.get(window.baseUrl(`/images/drawio/base64/${drawingId}`)); - return `data:image/png;base64,${resp.data.content}`; + return resp.data.content; } export default {show, close, upload, load}; \ No newline at end of file diff --git a/resources/js/wysiwyg/plugin-drawio.js b/resources/js/wysiwyg/plugin-drawio.js index 6b0167a70..c270c5d20 100644 --- a/resources/js/wysiwyg/plugin-drawio.js +++ b/resources/js/wysiwyg/plugin-drawio.js @@ -34,7 +34,7 @@ function showDrawingEditor(mceEditor, selectedNode = null) { DrawIO.show(options.drawioUrl, drawingInit, updateContent); } -async function updateContent(pngData) { +async function updateContent(drawingData) { const id = "image-" + Math.random().toString(16).slice(2); const loadingImage = window.baseUrl('/loading.gif'); @@ -52,7 +52,7 @@ async function updateContent(pngData) { DrawIO.close(); let imgElem = currentNode.querySelector('img'); try { - const img = await DrawIO.upload(pngData, options.pageId); + const img = await DrawIO.upload(drawingData, options.pageId); pageEditor.dom.setAttrib(imgElem, 'src', img.url); pageEditor.dom.setAttrib(currentNode, 'drawio-diagram', img.id); } catch (err) { @@ -65,7 +65,7 @@ async function updateContent(pngData) { pageEditor.insertContent(`
`); DrawIO.close(); try { - const img = await DrawIO.upload(pngData, options.pageId); + const img = await DrawIO.upload(drawingData, options.pageId); pageEditor.dom.setAttrib(id, 'src', img.url); pageEditor.dom.get(id).parentNode.setAttribute('drawio-diagram', img.id); } catch (err) { diff --git a/tests/Uploads/DrawioTest.php b/tests/Uploads/DrawioTest.php index 2ed4da7ca..232904275 100644 --- a/tests/Uploads/DrawioTest.php +++ b/tests/Uploads/DrawioTest.php @@ -10,7 +10,7 @@ class DrawioTest extends TestCase { use UsesImages; - public function test_get_image_as_base64() + public function test_get_image_as_base64_with_png_content() { $page = Page::first(); $this->asAdmin(); @@ -23,11 +23,27 @@ class DrawioTest extends TestCase $imageGet = $this->getJson("/images/drawio/base64/{$image->id}"); $imageGet->assertJson([ - 'content' => 'iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAIAAAACDbGyAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH4gEcDCo5iYNs+gAAAB1pVFh0Q29tbWVudAAAAAAAQ3JlYXRlZCB3aXRoIEdJTVBkLmUHAAAAFElEQVQI12O0jN/KgASYGFABqXwAZtoBV6Sl3hIAAAAASUVORK5CYII=', + 'content' => 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAIAAAACDbGyAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH4gEcDCo5iYNs+gAAAB1pVFh0Q29tbWVudAAAAAAAQ3JlYXRlZCB3aXRoIEdJTVBkLmUHAAAAFElEQVQI12O0jN/KgASYGFABqXwAZtoBV6Sl3hIAAAAASUVORK5CYII=', ]); } - public function test_drawing_base64_upload() + public function test_get_image_as_base64_with_svg_content() + { + $page = Page::first(); + $this->asAdmin(); + + $this->uploadImage('my-drawing.svg', $page->id, 'image/svg+xml', 'diagram.svg'); + $image = Image::first(); + $image->type = 'drawio'; + $image->save(); + + $imageGet = $this->getJson("/images/drawio/base64/{$image->id}"); + $imageGet->assertJson([ + 'content' => 'data:image/svg+xml;base64,' . base64_encode(file_get_contents($this->getTestImageFilePath('diagram.svg'))), + ]); + } + + public function test_drawing_base64_upload_with_png() { $page = Page::first(); $editor = $this->getEditor(); @@ -35,7 +51,7 @@ class DrawioTest extends TestCase $upload = $this->postJson('images/drawio', [ 'uploaded_to' => $page->id, - 'image' => 'image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAIAAAACDbGyAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH4gEcDCo5iYNs+gAAAB1pVFh0Q29tbWVudAAAAAAAQ3JlYXRlZCB3aXRoIEdJTVBkLmUHAAAAFElEQVQI12O0jN/KgASYGFABqXwAZtoBV6Sl3hIAAAAASUVORK5CYII=', + 'image' => 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAIAAAACDbGyAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH4gEcDCo5iYNs+gAAAB1pVFh0Q29tbWVudAAAAAAAQ3JlYXRlZCB3aXRoIEdJTVBkLmUHAAAAFElEQVQI12O0jN/KgASYGFABqXwAZtoBV6Sl3hIAAAAASUVORK5CYII=', ]); $upload->assertStatus(200); @@ -54,6 +70,34 @@ class DrawioTest extends TestCase $this->assertTrue($testImageData === $uploadedImageData, 'Uploaded image file data does not match our test image as expected'); } + public function test_drawing_base64_upload_with_svg() + { + $page = Page::first(); + $editor = $this->getEditor(); + $this->actingAs($editor); + + $upload = $this->postJson('images/drawio', [ + 'uploaded_to' => $page->id, + 'image' => 'data:image/svg+xml;base64,' . base64_encode(file_get_contents($this->getTestImageFilePath('diagram.svg'))), + ]); + + $upload->assertStatus(200); + $upload->assertJson([ + 'type' => 'drawio', + 'uploaded_to' => $page->id, + 'created_by' => $editor->id, + 'updated_by' => $editor->id, + ]); + + $image = Image::where('type', '=', 'drawio')->first(); + $this->assertStringEndsWith('.svg', $image->path); + $this->assertTrue(file_exists(public_path($image->path)), 'Uploaded image not found at path: ' . public_path($image->path)); + + $testImageData = file_get_contents($this->getTestImageFilePath('diagram.svg')); + $uploadedImageData = file_get_contents(public_path($image->path)); + $this->assertTrue($testImageData === $uploadedImageData, 'Uploaded image file data does not match our test image as expected'); + } + public function test_drawio_url_can_be_configured() { config()->set('services.drawio', 'http://cats.com?dog=tree');