From a27a7656ea88776a1f85b84890bde3c5440bb999 Mon Sep 17 00:00:00 2001 From: Artur Wieczorek Date: Thu, 31 Dec 2020 12:14:08 +0100 Subject: [PATCH 1/4] 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"), From e09c35efb5458b5fd07a31eec93cfaaed7271778 Mon Sep 17 00:00:00 2001 From: Artur Wieczorek Date: Wed, 30 Dec 2020 10:04:48 +0100 Subject: [PATCH 2/4] Implement wxImageDataObject Using this object we can put an wxImage on or retrieve it from the clipboard. wxImage is stored internally as a blob with either a PNG file (wxMSW, wxGTK) or a TIFF file (wxOSX) and therefore some its metadata (like resolution) is stored on the clipboard too (what is not the case for wxBitmap stored with wxBitmapDataObject). wxImages stored with wxImageDataObject can be used by native applications. Closes #17631. --- include/wx/dataobj.h | 20 +++++++++++++++- interface/wx/dataobj.h | 39 +++++++++++++++++++++++++++++- src/common/dobjcmn.cpp | 54 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 111 insertions(+), 2 deletions(-) diff --git a/include/wx/dataobj.h b/include/wx/dataobj.h index 4091f7b766..ef0c385df5 100644 --- a/include/wx/dataobj.h +++ b/include/wx/dataobj.h @@ -36,7 +36,9 @@ wxTextDataObject | wxBitmapDataObject | wxCustomDataObject - + | + | + wxImageDataObject */ // ============================================================================ @@ -545,6 +547,22 @@ private: wxDECLARE_NO_COPY_CLASS(wxCustomDataObject); }; +// ---------------------------------------------------------------------------- +// wxImageDataObject - data object for wxImage +// ---------------------------------------------------------------------------- + +class WXDLLIMPEXP_CORE wxImageDataObject : public wxCustomDataObject +{ +public: + explicit wxImageDataObject(const wxImage& image = wxNullImage); + + void SetImage(const wxImage& image); + wxImage GetImage() const; + +private: + wxDECLARE_NO_COPY_CLASS(wxImageDataObject); +}; + // ---------------------------------------------------------------------------- // include platform-specific declarations of wxXXXBase classes // ---------------------------------------------------------------------------- diff --git a/interface/wx/dataobj.h b/interface/wx/dataobj.h index 3b64f30169..90a6b7766f 100644 --- a/interface/wx/dataobj.h +++ b/interface/wx/dataobj.h @@ -35,7 +35,8 @@ @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.} + A PNG file. This is valid only on MSW. This constant is available + since wxWidgets 3.1.5.} @endDefList As mentioned above, these standard formats may be passed to any function @@ -622,6 +623,42 @@ public: +/** + @class wxImageDataObject + + wxImageDataObject is a specialization of wxDataObject for image data. + It can be used e.g. when you need to put on and retrieve from the clipboard + a wxImage with its metadata (like image resolution). + + @since 3.1.5 + + @library{wxcore} + @category{dnd} + + @see @ref overview_dnd, wxDataObject, wxCustomDataObject, wxBitmapDataObject +*/ +class wxImageDataObject : public wxCustomDataObject +{ +public: + /** + Constructor, optionally passing an image (otherwise use SetImage() + later). + */ + explicit wxImageDataObject(const wxImage& image = wxNullImage); + + /** + Returns the image associated with the data object. + */ + wxImage GetImage() const; + + /** + Sets the image stored by the data object. + */ + void SetImage(const wxImage& image); +}; + + + /** @class wxURLDataObject diff --git a/src/common/dobjcmn.cpp b/src/common/dobjcmn.cpp index d963ac4cbe..20ce23217d 100644 --- a/src/common/dobjcmn.cpp +++ b/src/common/dobjcmn.cpp @@ -20,6 +20,7 @@ #include "wx/app.h" #endif +#include "wx/mstream.h" #include "wx/textbuf.h" // ---------------------------------------------------------------------------- @@ -620,6 +621,59 @@ bool wxCustomDataObject::SetData(size_t size, const void *buf) return true; } +// ---------------------------------------------------------------------------- +// wxImageDataObject +// ---------------------------------------------------------------------------- + +#if defined(__WXMSW__) +#define wxIMAGE_FORMAT_DATA wxDF_PNG +#define wxIMAGE_FORMAT_BITMAP_TYPE wxBITMAP_TYPE_PNG +#define wxIMAGE_FORMAT_NAME "PNG" +#elif defined(__WXGTK__) +#define wxIMAGE_FORMAT_DATA wxDF_BITMAP +#define wxIMAGE_FORMAT_BITMAP_TYPE wxBITMAP_TYPE_PNG +#define wxIMAGE_FORMAT_NAME "PNG" +#elif defined(__WXOSX__) +#define wxIMAGE_FORMAT_DATA wxDF_BITMAP +#define wxIMAGE_FORMAT_BITMAP_TYPE wxBITMAP_TYPE_TIFF +#define wxIMAGE_FORMAT_NAME "TIFF" +#else +#define wxIMAGE_FORMAT_DATA wxDF_BITMAP +#define wxIMAGE_FORMAT_BITMAP_TYPE wxBITMAP_TYPE_PNG +#define wxIMAGE_FORMAT_NAME "PNG" +#endif + +wxImageDataObject::wxImageDataObject(const wxImage& image) + : wxCustomDataObject(wxIMAGE_FORMAT_DATA) +{ + if ( image.IsOk() ) + { + SetImage(image); + } +} + +void wxImageDataObject::SetImage(const wxImage& image) +{ + wxCHECK_RET(wxImage::FindHandler(wxIMAGE_FORMAT_BITMAP_TYPE) != NULL, + wxIMAGE_FORMAT_NAME " image handler must be installed to use clipboard with image"); + + wxMemoryOutputStream mem; + image.SaveFile(mem, wxIMAGE_FORMAT_BITMAP_TYPE); + + SetData(mem.GetLength(), mem.GetOutputStreamBuffer()->GetBufferStart()); +} + +wxImage wxImageDataObject::GetImage() const +{ + wxCHECK_MSG(wxImage::FindHandler(wxIMAGE_FORMAT_BITMAP_TYPE) != NULL, wxNullImage, + wxIMAGE_FORMAT_NAME " image handler must be installed to use clipboard with image"); + + wxMemoryInputStream mem(GetData(), GetSize()); + wxImage image; + image.LoadFile(mem, wxIMAGE_FORMAT_BITMAP_TYPE); + return image; +} + // ============================================================================ // some common dnd related code // ============================================================================ From 51cd4ceb5c2c727b88b7bc546ab58ddb5696dba5 Mon Sep 17 00:00:00 2001 From: Artur Wieczorek Date: Thu, 31 Dec 2020 12:58:23 +0100 Subject: [PATCH 3/4] Demonstrate storing wxImage to clipboard in image sample --- samples/image/image.cpp | 122 +++++++++++++++++++++++++++++++++++++--- 1 file changed, 114 insertions(+), 8 deletions(-) diff --git a/samples/image/image.cpp b/samples/image/image.cpp index 51bbdd4165..4ecbf16203 100644 --- a/samples/image/image.cpp +++ b/samples/image/image.cpp @@ -91,6 +91,8 @@ public: #if wxUSE_CLIPBOARD void OnCopy(wxCommandEvent& event); void OnPaste(wxCommandEvent& event); + void OnCopyImage(wxCommandEvent& evt); + void OnPasteImage(wxCommandEvent& evt); #endif // wxUSE_CLIPBOARD MyCanvas *m_canvas; @@ -124,8 +126,39 @@ class MyImageFrame : public wxFrame public: MyImageFrame(wxFrame *parent, const wxString& desc, const wxImage& image, double scale = 1.0) { - Create(parent, desc, wxBitmap(image, wxBITMAP_SCREEN_DEPTH, scale), - image.GetImageCount(desc)); + // Retrieve image info + wxString info; + int xres, yres; + switch ( GetResolutionFromOptions(image, &xres, &yres) ) + { + case wxIMAGE_RESOLUTION_NONE: + break; + + case wxIMAGE_RESOLUTION_CM: + // convert to DPI + xres = wxRound(xres / 10.0 * inches2mm); + yres = wxRound(yres / 10.0 * inches2mm); + wxFALLTHROUGH; + + case wxIMAGE_RESOLUTION_INCHES: + info = wxString::Format("DPI %i x %i", xres, yres); + break; + + default: + wxFAIL_MSG("unexpected image resolution units"); + break; + } + + int numImages = desc.StartsWith("Clipboard") ? 1 : image.GetImageCount(desc); + if ( numImages > 1 ) + { + if ( !info.empty() ) + info += ", "; + + info += wxString::Format("%d images", numImages); + } + + Create(parent, desc, wxBitmap(image, wxBITMAP_SCREEN_DEPTH, scale), info); } MyImageFrame(wxFrame *parent, const wxString& desc, const wxBitmap& bitmap) @@ -137,7 +170,7 @@ private: bool Create(wxFrame *parent, const wxString& desc, const wxBitmap& bitmap, - int numImages = 1) + wxString info = wxString()) { if ( !wxFrame::Create(parent, wxID_ANY, wxString::Format("Image from %s", desc), @@ -169,8 +202,7 @@ private: mbar->Check(ID_PAINT_BG, true); CreateStatusBar(2); - if ( numImages != 1 ) - SetStatusText(wxString::Format("%d images", numImages), 1); + SetStatusText(info, 1); SetClientSize(bitmap.GetWidth(), bitmap.GetHeight()); @@ -439,6 +471,41 @@ private: Refresh(); } + // This is a copy of protected wxImageHandler::GetResolutionFromOptions() + static wxImageResolution GetResolutionFromOptions(const wxImage& image, int* x, int* y) + { + wxCHECK_MSG(x && y, wxIMAGE_RESOLUTION_NONE, wxT("NULL pointer")); + + if ( image.HasOption(wxIMAGE_OPTION_RESOLUTIONX) && + image.HasOption(wxIMAGE_OPTION_RESOLUTIONY) ) + { + *x = image.GetOptionInt(wxIMAGE_OPTION_RESOLUTIONX); + *y = image.GetOptionInt(wxIMAGE_OPTION_RESOLUTIONY); + } + else if ( image.HasOption(wxIMAGE_OPTION_RESOLUTION) ) + { + *x = + *y = image.GetOptionInt(wxIMAGE_OPTION_RESOLUTION); + } + else // no resolution options specified + { + *x = + *y = 0; + + return wxIMAGE_RESOLUTION_NONE; + } + + // get the resolution unit too + int resUnit = image.GetOptionInt(wxIMAGE_OPTION_RESOLUTIONUNIT); + if ( !resUnit ) + { + // this is the default + resUnit = wxIMAGE_RESOLUTION_INCHES; + } + + return (wxImageResolution)resUnit; + } + wxBitmap m_bitmap; double m_zoom; @@ -631,7 +698,9 @@ enum ID_INFO, ID_SHOWRAW, ID_GRAPHICS, - ID_SHOWTHUMBNAIL + ID_SHOWTHUMBNAIL, + ID_COPY_IMAGE, + ID_PASTE_IMAGE }; wxIMPLEMENT_DYNAMIC_CLASS( MyFrame, wxFrame ); @@ -651,6 +720,8 @@ wxBEGIN_EVENT_TABLE(MyFrame, wxFrame) #if wxUSE_CLIPBOARD EVT_MENU(wxID_COPY, MyFrame::OnCopy) EVT_MENU(wxID_PASTE, MyFrame::OnPaste) + EVT_MENU(ID_COPY_IMAGE, MyFrame::OnCopyImage) + EVT_MENU(ID_PASTE_IMAGE, MyFrame::OnPasteImage) #endif // wxUSE_CLIPBOARD EVT_UPDATE_UI(ID_NEW_HIDPI, MyFrame::OnUpdateNewFrameHiDPI) wxEND_EVENT_TABLE() @@ -686,8 +757,11 @@ MyFrame::MyFrame() #if wxUSE_CLIPBOARD wxMenu *menuClipboard = new wxMenu; - menuClipboard->Append(wxID_COPY, "&Copy test image\tCtrl-C"); - menuClipboard->Append(wxID_PASTE, "&Paste image\tCtrl-V"); + menuClipboard->Append(wxID_COPY, "&Copy test image as wxBitmap\tCtrl-C"); + menuClipboard->Append(wxID_PASTE, "&Paste image as wxBitmap\tCtrl-V"); + menuClipboard->AppendSeparator(); + menuClipboard->Append(ID_COPY_IMAGE, "Copy image as wxImage"); + menuClipboard->Append(ID_PASTE_IMAGE, "Paste image as wxImage"); menu_bar->Append(menuClipboard, "&Clipboard"); #endif // wxUSE_CLIPBOARD @@ -945,6 +1019,38 @@ void MyFrame::OnPaste(wxCommandEvent& WXUNUSED(event)) wxTheClipboard->Close(); } +void MyFrame::OnCopyImage(wxCommandEvent& WXUNUSED(evt)) +{ + wxImage img; + wxString filename = LoadUserImage(img); + if ( filename.empty() ) + return; + + wxImageDataObject* dobjImage = new wxImageDataObject; + dobjImage->SetImage(img); + + wxClipboardLocker clipOpener; + if ( !wxTheClipboard->SetData(dobjImage) ) + { + wxLogError("Failed to copy wxImage to clipboard"); + } +} + +void MyFrame::OnPasteImage(wxCommandEvent& WXUNUSED(evt)) +{ + wxImageDataObject dobjImage; + + wxClipboardLocker clipOpener; + if ( !wxTheClipboard->GetData(dobjImage) ) + { + wxLogMessage("No wxImage data in the clipboard"); + } + else + { + new MyImageFrame(this, "Clipboard (wxImage)", dobjImage.GetImage()); + } +} + #endif // wxUSE_CLIPBOARD void MyFrame::OnThumbnail( wxCommandEvent &WXUNUSED(event) ) From 0a06a5066a428de1c5105468d221af1a5707f11c Mon Sep 17 00:00:00 2001 From: Artur Wieczorek Date: Thu, 31 Dec 2020 13:58:04 +0100 Subject: [PATCH 4/4] Add test of putting wxImage on and retrieving it from clipboard --- tests/image/image.cpp | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/tests/image/image.cpp b/tests/image/image.cpp index 43d493beb9..bebc9921ee 100644 --- a/tests/image/image.cpp +++ b/tests/image/image.cpp @@ -26,6 +26,8 @@ #include "wx/mstream.h" #include "wx/zstream.h" #include "wx/wfstream.h" +#include "wx/clipbrd.h" +#include "wx/dataobj.h" #include "testimage.h" @@ -1942,6 +1944,32 @@ TEST_CASE("wxImage::RGBtoHSV", "[image][rgb][hsv]") } } +TEST_CASE("wxImage::Clipboard", "[image][clipboard]") +{ +#if wxUSE_CLIPBOARD && wxUSE_DATAOBJ + wxInitAllImageHandlers(); + + wxImage imgOriginal; + REQUIRE(imgOriginal.LoadFile("horse.png") == true); + + wxImageDataObject* dobj1 = new wxImageDataObject(imgOriginal); + { + wxClipboardLocker lockClip; + REQUIRE(wxTheClipboard->SetData(dobj1) == true); + } + + wxImageDataObject dobj2; + { + wxClipboardLocker lockClip; + REQUIRE(wxTheClipboard->GetData(dobj2) == true); + } + wxImage imgRetrieved = dobj2.GetImage(); + REQUIRE(imgRetrieved.IsOk()); + + CompareImage(*wxImage::FindHandler(wxBITMAP_TYPE_PNG), imgRetrieved, 0, &imgOriginal); +#endif // wxUSE_CLIPBOARD && wxUSE_DATAOBJ +} + /* TODO: add lots of more tests to wxImage functions */