[翻]为自定义MFC文件格式创建缩略图

原文: Create Thumbnail Extractor objects for your MFC documents types

虽然这时候发这个已经有点像个Joke,但还是发吧。。有些付出的东西,留下的东西,不是一篇两篇文章可以理清。

翻译很稚嫩,用词也不得体,甚至有些地方语意还有些模糊,那又如何?那便如何!!

【前注】这一阵子做东西,想给自已的软件加上这样的一个功能。找到此文,翻译如下。

【介绍】

       缩略图显示是Windows资源管理器一个很不错的功能。但关于如何为用户的文件创建扩展缩略图的内容却比较少。我前一阵子在做可视化医学图像的软件时,就想为自己的DICOM(Digital Imaging and Communications in Medicine)软件添加这个功能。在网上搜索过后,我最后在MSDN杂志上找到了一篇相关文章: 更多Windows 2000 UI 技巧: 通过定制超文本模板文件扩展资源管理器视图(天啊,不知道是嘛意思) 这篇文件解决了这个问题,并包含了一个针对图标文件的简易图片提取器。在创建了我的DICOM软件的图片提取器之后(如果有人要,我可以提供),我也创建了一个可为涂鸦板(MFC指导)文档特别是涂鸦第五步,提取图片的框架扩展。我尝试着将这些代码以一个面向对象的方式来编写,以使得他们可以支持重用(我是面向对象思想的领导者  Paul Dilascia 的"Fans",他是MSDN杂志的作者)。 最后,我将这个涂鸦图像提取工程转换成了一个客户端程序,这样你们就可以为你自己的MFC文档容易地生成图像抽取。下面的图像就显示了一个包含了我的医药涂鸦文档的文件夹的截图:)

涂鸦板提取的COM对象

       为涂鸦软件做的基于MFC的缩略图提取扩展已经被生成为一个规则的MFC动态链接库。顺着应用程序向导,我添加了一个ATL对象到工程中。  这个ATL对象是用来实现需要的两个接口:IPersistFile,用来确定当前框架中被选中的文件(译注:加载文档)。IExtractImage2(继承于IExtractImage),用来进入文件并返回能表示其内容的图像。

// ScribbleExtractor.h
class ATL_NO_VTABLE CScribbleExtractor :
    public CComObjectRootEx
  
  
   
   ,
    public CComCoClass
   
   
    
    ,
    public IPersistFile,
    public IExtractImage2
{
public: ...

// ScribbleExtractor.cpp
// IExtractImage::Extract
HRESULT CScribbleExtractor::Extract(HBITMAP* phBmpThumbnail)
{
    AFX_MANAGE_STATE(AfxGetStaticModuleState());

    theApp.LoadDoc(m_szFile);
    m_hPreview = theApp.CreateThumbnail(m_bmSize);
    *phBmpThumbnail = m_hPreview;
    return NOERROR;
}
...
// Code for other interface functions is omitted since it is boiterblate.
   
   
  
  
CExtractImageApp 一般应用类

       正如你看到的,COM对象为主程序对象做了加载文档和生成缩略图这两件事儿。因为从CWinApp继承下来的类可以决定支持的文件类型,并通过文档管理机制创建对应的文档对象,这将会很方便。为了能够将尽可能多的代码实现重用,我实现从CWinApp继承下来的类ExtractImageApp里面的LoadDocCreateThumbnail函数。 第一部分在通用MFC代码中实现的。 辅助函数 CanOpenDocument 返回一个合适的文档模板,这个模板可以一个文件对象来提供给文件。 文件对象是被动态创建的,文档的内容是从硬盘中加载的。加载的代码大部分是从MFC的OnOpenDocument 函数里复制粘贴来的。

// Load document. This function is responsible for opening the document
// and setting m_pOpenDoc to the document loaded.
BOOL CExtractImageApp::LoadDoc(LPCTSTR lpFileName)
{
    ASSERT(lpFileName!=NULL);
    CString sFileName = lpFileName;
    CDocTemplate* pDocTemplate = CanOpenDocument(sFileName); // helper function
                                                             // defined above
    if (pDocTemplate) {
        if(!m_pDoc) {
            m_pDoc = pDocTemplate->CreateNewDocument();
            m_pDoc->m_bAutoDelete = TRUE;
        }
        if (m_pDoc)
        {
            // load content of file, code taken from MFC OnOpenDocument and modified
            CFileException fe;
            CFile* pFile = m_pDoc->GetFile(sFileName,    CFile::modeRead, &fe);
            if (pFile == NULL)
                return FALSE;

            m_pDoc->DeleteContents();
            CArchive loadArchive(pFile, CArchive::load | CArchive::bNoFlushOnDelete);
            loadArchive.m_pDocument = m_pDoc;
            loadArchive.m_bForceFlat = FALSE;
            try
            {
                if (pFile->GetLength() != 0)
                    m_pDoc->Serialize(loadArchive);     // load me
                loadArchive.Close();
                m_pDoc->ReleaseFile(pFile, FALSE);
            }
            catch(CException *e)
            {
                //e->ReportError();
                m_pDoc->ReleaseFile(pFile, TRUE);
                m_pDoc->DeleteContents();   // remove failed contents
                e->Delete();
                return FALSE;
            }
            return TRUE;
            //delete pDoc;
        }
    }
    return FALSE;
}

    CreateThumbnail 函数创建了缩略图的BMP图像,并将文档内容画在这个图像上。这个函数在本质上来说是一个模板函数,因为它调用了GetDocSizeOnDraw 这两个纯虚函数(必须要在子类中实现的)。缩略图是依照缩略图的尺寸同比放缩文档内容尺寸(在维度上保持一致)。在SetViewportExt 函数里的负号是用来定义笛卡尔坐标系(y轴是自底向上的)。

HBITMAP CExtractImageApp::CreateThumbnail(const SIZE bmSize)
{
    HBITMAP hThumb; CBitmap bmpThumb;
    if(!m_pDoc) return NULL;

    CSize bmDocSize = GetDocSize(); // derived class knows it
    // Create memory DC, create a color bitmap, and draw on it
    CDC memdc;
    memdc.CreateCompatibleDC(NULL);
    bmpThumb.CreateBitmap(bmSize.cx,bmSize.cy,3,8,NULL);
    CBitmap* pOldBm = memdc.SelectObject(&bmpThumb);

    memdc.PatBlt(0,0,bmSize.cx,bmSize.cy,WHITENESS);
    memdc.SetMapMode(MM_ISOTROPIC);
    memdc.SetViewportExt(bmSize.cx,-bmSize.cy);
    memdc.SetWindowExt(bmDocSize.cx,bmDocSize.cy);
    OnDraw(&memdc); //let the derived class to handle it
    memdc.SelectObject(pOldBm);
    hThumb = (HBITMAP)bmpThumb.Detach();
    return hThumb;
}
继承类

主要的应用程序类是从 CExtractImageApp继承的,在子类里,通过调用已加载的文档各自的函数,实现了上面提到的两个纯虚函数。在这之前,我必须将CDocumentm_pDoc 指针向下指向CScribbleDoc 指针。 如果你是多文档,有多个文档类,你可以使用CObject::IsKindOf 函数去定位文档类的m_pDoc 指针指向。在InitInstance 函数中,我添加了一个针对涂鸦板文档的文档模板。  CMDIChildWndCView 都是MFC的类,而CScribbleDoc 是原始涂鸦文档的一个简略版。The only functions that 工程里CScribbleDoc 类唯一需要被实现的就是Serialize 函数,此函数在文档加载时被调用。而 GetDocSizeOnDraw 函数在创建缩略图时被调用。一般来说,OnDraw 函数属于 CScribbleView 类,但这里没有必要使用文档视图结构,为了简化实现,我就从  CScribbleView里拷了OnDraw 函数。在第一行里,把GetDocument() 替换成了 this.

//thumbscb.cpp
BOOL CThumbScbApp::InitInstance()
{
    if (!InitATL())
        return FALSE;
    // Create document template
    AddDocTemplate(new CMultiDocTemplate(IDR_SCRIBBTYPE,
        RUNTIME_CLASS(CScribbleDoc),RUNTIME_CLASS(CMDIChildWnd), RUNTIME_CLASS(CView)));

    return CWinApp::InitInstance();
}

void CThumbScbApp::OnDraw(CDC *pDC)
{
    CScribbleDoc *mydoc = (CScribbleDoc *)m_pDoc;
    mydoc->OnDraw(pDC);
}

CSize CThumbScbApp::GetDocSize()
{
    CScribbleDoc *mydoc = (CScribbleDoc *)m_pDoc;
    return mydoc->GetDocSize();
}

// scribdoc.cpp
void CScribbleDoc::OnDraw(CDC* pDC)
{
    CScribbleDoc* pDoc = this; //GetDocument();
    ASSERT_VALID(pDoc);
    ...
怎样Debug

调试框架扩展挺难的。我创建了一个COM对象(ThumbExtract project) ,可以用框架接口得到文件的IExtractImage,然后创建一幅位图。在同一个文件夹下,你也可以找到小的VB6的Exe工程, 名字是TestThumbExtract ,这个工程引用了ThumbExtract 对象。 这个测试程序的一个实例在下面展示出来了。点击鼠标去选择一个文件,一个大的缩略图就会显示在图像框中。你也可以在Project/Settings/Debug 里设置TestThumbExtract.exe 的 'Executable for debug session' 来调试你你自己的框架扩展。

ThumbExtract2

缩略图工程向导

一个新的缩略图提取工程需要修改的代码量比较少,我基于ThumbScb工程做了一个客户端程序(ThumbWiz 工程) 。编译后的Dll名称为ThumbWiz.awx ,你得将这个文件复制到"C:/Program Files/Microsoft Visual Studio/Common/MSDev98/Template" 文件夹。在新的工程对话框会出现一个新的条目,名字为"Thumbnail Project Wizard" 。这个向导有一个向导,会询问你的对象名(比如 Scribble) 和文件扩展名支持种类(如果你想支持多种文件扩展名,你要用逗号将他们隔开)。 App类,文件类和COM类的名字都是基于你提供的对象名字创建的。 针对每一种文件扩展名,在InitInstance中都会成生一个新的文档模板。而控件的ID就会被自动创建。自动生成的代码包含了TODO注释,这就是指名什么地方需要添加一些细节了。在 CThumbWizAppWiz:: CustomizeProject 我定制了工程的一些设置(特别是MIDL设置)同时也创建了一个快速指南来注意对象。文件扩展名注册的键值也创建了,这样系统就可以确定针对每种文件格式需要加载哪个对象。不要粗心将已知的格式(如 .jpg)格式注册了,因为我没有做注册表的备份哦。

总结

现在为你自己的文件格式创建扩展名的缩略图该很简单了(我希望:))。随着写这篇文章,我的缩略图提取程序也写完了!欢迎访问我的主页以获得更多的免费工具和程序。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值