From a27a7656ea88776a1f85b84890bde3c5440bb999 Mon Sep 17 00:00:00 2001 From: Artur Wieczorek Date: Thu, 31 Dec 2020 12:14:08 +0100 Subject: [PATCH] Provide support for storing PNG files on the clipboard (wxMSW) PNG is a custom clipboard format but images stored in this format are supported by e.g. MS Excel, MS PowerPoint, GIMP (including image transparency). See #17631. --- include/wx/defs.h | 1 + interface/wx/dataobj.h | 2 ++ src/msw/clipbrd.cpp | 38 +++++++++++++++++++++++++++++++++++++- src/msw/ole/dataobj.cpp | 35 +++++++++++++++++++++-------------- 4 files changed, 61 insertions(+), 15 deletions(-) diff --git a/include/wx/defs.h b/include/wx/defs.h index 101a016727..1881ac247f 100644 --- a/include/wx/defs.h +++ b/include/wx/defs.h @@ -2153,6 +2153,7 @@ enum wxDataFormatId wxDF_LOCALE = 16, wxDF_PRIVATE = 20, wxDF_HTML = 30, /* Note: does not correspond to CF_ constant */ + wxDF_PNG = 31, /* Note: does not correspond to CF_ constant */ wxDF_MAX }; diff --git a/interface/wx/dataobj.h b/interface/wx/dataobj.h index d01b84d5d4..3b64f30169 100644 --- a/interface/wx/dataobj.h +++ b/interface/wx/dataobj.h @@ -34,6 +34,8 @@ A list of filenames.} @itemdef{wxDF_HTML, An HTML string. This is currently only valid on Mac and MSW.} + @itemdef{wxDF_PNG, + A PNG file. This is valid only on MSW.} @endDefList As mentioned above, these standard formats may be passed to any function diff --git a/src/msw/clipbrd.cpp b/src/msw/clipbrd.cpp index 9df2a53c38..f349449fbd 100644 --- a/src/msw/clipbrd.cpp +++ b/src/msw/clipbrd.cpp @@ -73,6 +73,7 @@ static bool gs_wxClipboardIsOpen = false; static int gs_htmlcfid = 0; +static int gs_pngcfid = 0; bool wxOpenClipboard() { @@ -136,6 +137,8 @@ bool wxIsClipboardFormatAvailable(wxDataFormat dataFormat) wxDataFormat::NativeFormat cf = dataFormat.GetFormatId(); if (cf == wxDF_HTML) cf = gs_htmlcfid; + else if ( cf == wxDF_PNG ) + cf = gs_pngcfid; if ( ::IsClipboardFormatAvailable(cf) ) { @@ -162,6 +165,15 @@ bool wxIsClipboardFormatAvailable(wxDataFormat dataFormat) #if !wxUSE_OLE_CLIPBOARD +namespace +{ +struct wxRawImageData +{ + size_t m_size; + void* m_data; +}; +} + bool wxSetClipboardData(wxDataFormat dataFormat, const void *data, int width, int height) @@ -414,6 +426,16 @@ bool wxSetClipboardData(wxDataFormat dataFormat, delete [] buf; break; } + + case wxDF_PNG: + { + const wxRawImageData* imgData = reinterpret_cast(data); + + GlobalPtr hImage(imgData->m_size, GMEM_MOVEABLE | GMEM_DDESHARE); + memcpy(GlobalPtrLock(hImage).Get(), imgData->m_data, imgData->m_size); + handle = ::SetClipboardData(gs_pngcfid, hImage); + break; + } } if ( handle == 0 ) @@ -515,9 +537,11 @@ bool wxClipboard::Flush() bool wxClipboard::Open() { - // Get clipboard id for HTML format... + // Get clipboard id for HTML and PNG formats... if(!gs_htmlcfid) gs_htmlcfid = RegisterClipboardFormat(wxT("HTML Format")); + if ( !gs_pngcfid ) + gs_pngcfid = ::RegisterClipboardFormat(wxT("PNG")); // OLE opens clipboard for us m_isOpened = true; @@ -636,6 +660,16 @@ bool wxClipboard::AddData( wxDataObject *data ) } break; + case wxDF_PNG: + { + wxCustomDataObject* imageDataObject = reinterpret_cast(data); + wxRawImageData imgData; + imgData.m_size = imageDataObject->GetDataSize(); + imgData.m_data = imageDataObject->GetData(); + bRet = wxSetClipboardData(format, &imgData); + } + break; + #if wxUSE_METAFILE case wxDF_METAFILE: { @@ -768,6 +802,8 @@ bool wxClipboard::GetData( wxDataObject& data ) if (cf == wxDF_HTML) cf = gs_htmlcfid; + else if ( cf == wxDF_PNG ) + cf = gs_pngcfid; // if the format is not available, try the next one // this test includes implicit / sythetic formats if ( !::IsClipboardFormatAvailable(cf) ) diff --git a/src/msw/ole/dataobj.cpp b/src/msw/ole/dataobj.cpp index bb55833eca..f323893bd4 100644 --- a/src/msw/ole/dataobj.cpp +++ b/src/msw/ole/dataobj.cpp @@ -64,15 +64,15 @@ namespace { -wxDataFormat HtmlFormatFixup(wxDataFormat format) +wxDataFormat NonStandardFormatsFixup(wxDataFormat format) { - // Since the HTML format is dynamically registered, the wxDF_HTML - // format does not match the native constant in the way other formats do, + // Since the HTML and PNG formats are dynamically registered, the wxDF_HTML and wxDF_PNG + // formats do not match the native constants in the way other formats do, // so for the format checks below to work, we must change the native - // id to the wxDF_HTML constant. + // id to the wxDF_HTML or wxDF_PNG constant. // // But skip this for the standard constants which are never going to match - // wxDF_HTML anyhow. + // wxDF_HTML or wxDF_PNG anyhow. if ( !format.IsStandard() ) { wxChar szBuf[256]; @@ -80,6 +80,8 @@ wxDataFormat HtmlFormatFixup(wxDataFormat format) { if ( wxStrcmp(szBuf, wxT("HTML Format")) == 0 ) format = wxDF_HTML; + else if ( wxStrcmp(szBuf, wxT("PNG")) == 0 ) + format = wxDF_PNG; } } @@ -347,7 +349,7 @@ wxIDataObject::SaveSystemData(FORMATETC *pformatetc, bool wxDataFormat::operator==(wxDataFormatId format) const { - return HtmlFormatFixup(*this).m_format == (NativeFormat)format; + return NonStandardFormatsFixup(*this).m_format == (NativeFormat)format; } bool wxDataFormat::operator!=(wxDataFormatId format) const @@ -357,7 +359,7 @@ bool wxDataFormat::operator!=(wxDataFormatId format) const bool wxDataFormat::operator==(const wxDataFormat& format) const { - return HtmlFormatFixup(*this).m_format == HtmlFormatFixup(format).m_format; + return NonStandardFormatsFixup(*this).m_format == NonStandardFormatsFixup(format).m_format; } bool wxDataFormat::operator!=(const wxDataFormat& format) const @@ -367,7 +369,7 @@ bool wxDataFormat::operator!=(const wxDataFormat& format) const bool wxDataFormat::operator==(NativeFormat format) const { - return HtmlFormatFixup(*this).m_format == format; + return NonStandardFormatsFixup(*this).m_format == format; } bool wxDataFormat::operator!=(NativeFormat format) const @@ -422,10 +424,12 @@ wxIEnumFORMATETC::wxIEnumFORMATETC(const wxDataFormat *formats, ULONG nCount) m_nCount = nCount; m_formats = new CLIPFORMAT[nCount]; for ( ULONG n = 0; n < nCount; n++ ) { - if (formats[n].GetFormatId() != wxDF_HTML) - m_formats[n] = formats[n].GetFormatId(); - else + if ( formats[n].GetFormatId() == wxDF_HTML ) m_formats[n] = ::RegisterClipboardFormat(wxT("HTML Format")); + else if ( formats[n].GetFormatId() == wxDF_PNG ) + m_formats[n] = ::RegisterClipboardFormat(wxT("PNG")); + else + m_formats[n] = formats[n].GetFormatId(); } } @@ -540,7 +544,7 @@ STDMETHODIMP wxIDataObject::GetData(FORMATETC *pformatetcIn, STGMEDIUM *pmedium) // for the bitmaps and metafiles we use the handles instead of global memory // to pass the data wxDataFormat format = (wxDataFormat::NativeFormat)pformatetcIn->cfFormat; - format = HtmlFormatFixup(format); + format = NonStandardFormatsFixup(format); // is this system data? if ( GetSystemData(format, pmedium) ) @@ -690,7 +694,7 @@ STDMETHODIMP wxIDataObject::SetData(FORMATETC *pformatetc, { wxDataFormat format = pformatetc->cfFormat; - format = HtmlFormatFixup(format); + format = NonStandardFormatsFixup(format); // check if this format is supported if ( !m_pDataObject->IsSupported(format, wxDataObject::Set) ) { @@ -737,6 +741,9 @@ STDMETHODIMP wxIDataObject::SetData(FORMATETC *pformatetc, size = sizeof(METAFILEPICT); break; + case wxDF_PNG: + wxFALLTHROUGH; + default: size = ptr.GetSize(); @@ -816,7 +823,7 @@ STDMETHODIMP wxIDataObject::QueryGetData(FORMATETC *pformatetc) // and now check the type of data requested wxDataFormat format = pformatetc->cfFormat; - format = HtmlFormatFixup(format); + format = NonStandardFormatsFixup(format); if ( m_pDataObject->IsSupportedFormat(format) ) { wxLogTrace(wxTRACE_OleCalls, wxT("wxIDataObject::QueryGetData: %s ok"),