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 0e9b4f08a998269543b1826d6d006d315454173e Author: Miklos Vajna <[email protected]> AuthorDate: Thu Oct 2 10:12:18 2025 +0200 Commit: Caolán McNamara <[email protected]> CommitDate: Thu Oct 2 13:27:47 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/+/191758 Tested-by: Jenkins CollaboraOffice <[email protected]> Tested-by: Caolán McNamara <[email protected]> Reviewed-by: Caolán McNamara <[email protected]> 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 4b6883284216..32bcefc99c28 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> @@ -830,6 +832,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 a475eb3597f7..81ee40177a4b 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> @@ -216,12 +217,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 { @@ -232,7 +242,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); }
