sw/qa/filter/md/data/test.png |binary sw/qa/filter/md/md.cxx | 35 +++++++++++++++++++++++++++++++++++ sw/source/filter/md/wrtmd.cxx | 21 ++++++++++++++++----- 3 files changed, 51 insertions(+), 5 deletions(-)
New commits: commit 8d60fcdac9bc79c7b8956ed3cd9e9f518b28c119 Author: Miklos Vajna <[email protected]> AuthorDate: Thu Oct 2 10:12:18 2025 +0200 Commit: Miklos Vajna <[email protected]> CommitDate: Thu Oct 2 16:34:10 2025 +0200 sw markdown filter: export non-linked inline images Open sw/qa/filter/md/data/embedded-image.md, save as markdown, the image is lost. What happens is that we have a check if the image is linked (which is the usual case if the document was imported from markdown), and only then export its URL. Fix the problem similar to what the HTML export does in OutHTML_ImageStart() for the rWrt.mbEmbedImages case: use XOutBitmap::GraphicToBase64() to construct a 'data:' URL and write the image embedded, since it doesn't really have a URL. Also don't try to convert this "URL" to a relative one, which makes no sense for the 'data:' protocol, but does produce a warning during export. Change-Id: I48ea76c83ac98869cb65830167733a6395e5f80d Reviewed-on: https://gerrit.libreoffice.org/c/core/+/191778 Reviewed-by: Miklos Vajna <[email protected]> Tested-by: Jenkins diff --git a/sw/qa/filter/md/data/test.png b/sw/qa/filter/md/data/test.png new file mode 100644 index 000000000000..5ae85192b3b6 Binary files /dev/null and b/sw/qa/filter/md/data/test.png differ diff --git a/sw/qa/filter/md/md.cxx b/sw/qa/filter/md/md.cxx index 847ad0bf5ad1..81461b7822cf 100644 --- a/sw/qa/filter/md/md.cxx +++ b/sw/qa/filter/md/md.cxx @@ -13,6 +13,8 @@ #include <com/sun/star/style/ParagraphAdjust.hpp> +#include <vcl/graphicfilter.hxx> + #include <docsh.hxx> #include <wrtsh.hxx> #include <view.hxx> @@ -840,6 +842,39 @@ CPPUNIT_TEST_FIXTURE(Test, testEmbeddedImageMdImport) CPPUNIT_ASSERT_EQUAL(static_cast<SwTwips>(960), rSize.GetHeight()); } +CPPUNIT_TEST_FIXTURE(Test, testEmbeddedImageMdExport) +{ + // Given a document with an embedded inline image: + createSwDoc(); + SwDocShell* pDocShell = getSwDocShell(); + SwDoc* pDoc = pDocShell->GetDoc(); + SwWrtShell* pWrtShell = pDocShell->GetWrtShell(); + pWrtShell->Insert(u"A "_ustr); + SfxItemSet aFrameSet(pDoc->GetAttrPool(), svl::Items<RES_FRMATR_BEGIN, RES_FRMATR_END - 1>); + SwFormatAnchor aAnchor(RndStdIds::FLY_AS_CHAR); + aFrameSet.Put(aAnchor); + OUString aImageURL = createFileURL(u"test.png"); + SvFileStream aImageStream(aImageURL, StreamMode::READ); + GraphicFilter& rFilter = GraphicFilter::GetGraphicFilter(); + Graphic aGraphic = rFilter.ImportUnloadedGraphic(aImageStream); + IDocumentContentOperations& rIDCO = pDoc->getIDocumentContentOperations(); + SwCursor* pCursor = pWrtShell->GetCursor(); + SwFlyFrameFormat* pFlyFormat + = rIDCO.InsertGraphic(*pCursor, /*rGrfName=*/OUString(), OUString(), &aGraphic, &aFrameSet, + /*pGrfAttrSet=*/nullptr, /*SwFrameFormat=*/nullptr); + pFlyFormat->SetObjDescription(u"mydesc"_ustr); + pWrtShell->Insert(u" B"_ustr); + + // When saving that to markdown: + save(mpFilter); + + // Then make sure that the embedded image is exported: + std::string aActual = TempFileToString(); + // Without the accompanying fix in place, this test would have failed, aActual was 'A B '. + CPPUNIT_ASSERT(aActual.starts_with("A ); + CPPUNIT_ASSERT(aActual.ends_with(") B" SAL_NEWLINE_STRING)); +} + CPPUNIT_PLUGIN_IMPLEMENT(); /* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/sw/source/filter/md/wrtmd.cxx b/sw/source/filter/md/wrtmd.cxx index 6bc5dc8444c2..5ec4008939a2 100644 --- a/sw/source/filter/md/wrtmd.cxx +++ b/sw/source/filter/md/wrtmd.cxx @@ -31,6 +31,7 @@ #include <editeng/fontitem.hxx> #include <comphelper/string.hxx> #include <svl/urihelper.hxx> +#include <svx/xoutbmp.hxx> #include <officecfg/Office/Writer.hxx> @@ -226,12 +227,21 @@ void ApplyItem(SwMDWriter& rWrt, FormattingStatus& rChange, const SfxPoolItem& r { SwGrfNode* pGrfNode = rWrt.m_pDoc->GetNodes()[nStart]->GetGrfNode(); aGraphic = pGrfNode->GetGraphic(); - if (!pGrfNode->IsLinkedFile()) + if (pGrfNode->IsLinkedFile()) { - // Not linked, ignore for now. - break; + pGrfNode->GetFileFilterNms(&aGraphicURL, /*pFilterNm=*/nullptr); + } + else + { + // Not linked, image data goes into the "URL". + OUString aGraphicInBase64; + if (!XOutBitmap::GraphicToBase64(aGraphic, aGraphicInBase64)) + { + break; + } + + aGraphicURL = "data:" + aGraphicInBase64; } - pGrfNode->GetFileFilterNms(&aGraphicURL, /*pFilterNm=*/nullptr); } else { @@ -242,7 +252,8 @@ void ApplyItem(SwMDWriter& rWrt, FormattingStatus& rChange, const SfxPoolItem& r } const OUString& rBaseURL = rWrt.GetBaseURL(); - if (!rBaseURL.isEmpty()) + INetURLObject aGraphicURLObject(aGraphicURL); + if (!rBaseURL.isEmpty() && aGraphicURLObject.GetProtocol() != INetProtocol::Data) { aGraphicURL = URIHelper::simpleNormalizedMakeRelative(rBaseURL, aGraphicURL); }
