RichEdit 不显示图片

Posted

技术标签:

【中文标题】RichEdit 不显示图片【英文标题】:RichEdit doesn't show pictures 【发布时间】:2021-12-14 11:08:52 【问题描述】:

我在写字板中创建了一个简单的 RTF 文档,截图如下:

看来,除了图片,RTF 的所有格式都可以正常工作,图片替换为空字符串。这是 RichEdit 的截图:

我尝试了 .bmp 和 .png。我还尝试了不同版本的 RichEdit 库: Riched20.dll 和 Msftedit.dll。在我的 .rtf 文件中有一个字符串 \*\generator Riched20 10.0.19041,我想它是一个库和 SDK 版本,在 Visual Studio 中我使用相同的。

我用来加载 RTF 的代码很流行,取自互联网:

    static DWORD CALLBACK FileStreamCallback(DWORD dwCookie, LPBYTE pbBuff,    LONG cb, LONG* pcb)
    
        std::ifstream* pFile = (std::ifstream*)dwCookie;
        pFile->read((char*)pbBuff, cb);
        return 0;
    

    // ...
    std::fstream file filePath ;
    EDITSTREAM   editStream =  0 ;
    editStream.dwCookie = (DWORD)&file;
    editStream.pfnCallback = FileStreamCallback;
    SendMessage(hwndEdit, EM_STREAMIN, SF_RTF, (LPARAM)&editStream);

为了简洁起见,这里是带有剪切图像数据的 RTF:

\rtf1\ansi\ansicpg1251\deff0\nouicompat\deflang1049\deflangfe1049\fonttbl\f0\fswiss\fprq2\fcharset204 Calibri;\f1\fswiss\fprq2\fcharset0 Calibri;
\colortbl ;\red0\green0\blue255;
\*\generator Riched20 10.0.19041\*\mmathPr\mdispDef1\mwrapIndent1440 \viewkind4\uc1 
\pard\nowidctlpar\sa200\sl240\slmult1\f0\fs22\pict\*\picprop\wmetafile8\picw1323\pich1323\picwgoal750\pichgoal750 
010009000003260300000000fd02000000000400000003010800050000000b0200000000050000
// intermediate data
0000002701ffff030000000000
\par
\strike Hello\strike0 .\par

\pard 
\pntext\f0 a.\tab\*\pn\pnlvlbody\pnf0\pnindent0\pnstart1\pnlcltr\pntxta.
\nowidctlpar\fi-360\li720\sa200\sl240\slmult1\f1\lang1033 34\f0\lang1049\par
\pntext\f0 b.\tab\f1\lang1033 28\f0\lang1049\par

\pard\nowidctlpar\sa200\sl240\slmult1 \f1\lang1033\field\*\fldinstHYPERLINK www.google.com \fldrsltwww.google.com\ul0\cf0\f0\fs22\par


我也发现了一些指控,即 RichEdit 实际上无法使用上述方法处理图像。我不知道如何对待他们。

【问题讨论】:

【参考方案1】:

要在 Richedit 中插入位图,请参阅 example (InsertObject(HWND hRichEdit, LPCTSTR pszFileName))

否则,写字板 rtf 文件中的位图将保存为十进制格式的数字。要阅读它,需要IRichEditOleCallback 接口。

创建一个名为"cole_callback.h" 的新文件,如下所示:

#include <richole.h>

interface cole_callback : public IRichEditOleCallback

public:
    IStorage* pstorage;
    DWORD m_ref;
    int grfmode;
    cole_callback() : grfmode(STGM_TRANSACTED | STGM_READWRITE | STGM_SHARE_EXCLUSIVE | STGM_CREATE)
    
        pstorage = nullptr;
        m_ref = 0;
        (void)StgCreateDocfile(NULL, grfmode, 0, &pstorage);
    

    HRESULT STDMETHODCALLTYPE GetNewStorage(LPSTORAGE* lplpstg)
    
        wchar_t name[256] =  0 ;
        return pstorage->CreateStorage(name, grfmode, 0, 0, lplpstg);
    

    HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, void** lplpObj)
    
        *lplpObj = NULL;
        if (iid == IID_IUnknown || iid == IID_IRichEditOleCallback)
        
            *lplpObj = this;
            AddRef();
            return NOERROR;
        
        return E_NOINTERFACE;
    

    ULONG STDMETHODCALLTYPE AddRef()
    
        return ++m_ref;
    

    ULONG STDMETHODCALLTYPE Release()
    
        if (--m_ref == 0)  delete this; return 0; 
        return m_ref;
    

    STDMETHOD(GetInPlaceContext) (LPOLEINPLACEFRAME FAR*, LPOLEINPLACEUIWINDOW FAR*, LPOLEINPLACEFRAMEINFO)  return S_OK; 
    STDMETHOD(ShowContainerUI) (BOOL)  return S_OK; 
    STDMETHOD(QueryInsertObject) (LPCLSID, LPSTORAGE, LONG)  return S_OK; 
    STDMETHOD(DeleteObject) (LPOLEOBJECT)  return S_OK; 
    STDMETHOD(QueryAcceptData) (LPDATAOBJECT, CLIPFORMAT FAR*, DWORD, BOOL, HGLOBAL)  return S_OK; 
    STDMETHOD(ContextSensitiveHelp) (BOOL)  return S_OK; 
    STDMETHOD(GetClipboardData) (CHARRANGE FAR*, DWORD, LPDATAOBJECT FAR*)  return S_OK; 
    STDMETHOD(GetDragDropEffect) (BOOL, DWORD, LPDWORD)  return S_OK; 
    STDMETHOD(GetContextMenu) (WORD, LPOLEOBJECT, CHARRANGE FAR*, HMENU FAR*)  return S_OK; 
;

下一步,创建cole_callback 的新实例,并使用EM_SETOLECALLBACK 消息发送它。接下来使用EM_STREAMIN读取rtf文件

#include <"cole_callback.h">
...
LoadLibrary(L"Riched20.dll");
...
cole_callback* ole_callback = new cole_callback;
...
richedit = CreateWindowEx(0, RICHEDIT_CLASS, ...

SendMessage(richedit, EM_SETOLECALLBACK, 0, (LPARAM)ole_callback);

auto callback = [](DWORD ptr, LPBYTE buf, LONG count, LONG* red)

    auto fp = (std::ifstream*)ptr;
    fp->read((char*)buf, count);
    *red = (LONG)fp->gcount();
    return DWORD(0);
;
std::ifstream fin(L"c:/test/document.rtf", std::ios::binary);
EDITSTREAM es (DWORD_PTR)&fin, 0, callback ;
SendMessage(richedit, EM_STREAMIN, WPARAM(SF_RTF), (LPARAM)&es);

【讨论】:

我已经尝试过 OLE 方法,在您的链接中描述,它导致将 RTF 作为一个整体加载;它是框架的,超链接不起作用。但是谢谢,现在我将尝试您答案中的代码。 您无法在写字板中插入链接,不清楚您的源 *.rtf 文件是什么

以上是关于RichEdit 不显示图片的主要内容,如果未能解决你的问题,请参考以下文章

RichEdit 控件在切换选项卡时不显示水平滚动条

复制粘贴到word里的图片为啥不显示?

Word中图片不显示怎么办

在word中图片不显示怎么办?

怎么在HTML显示图片

在moodle中图片不显示是怎么回事?