分类

类型:
不限 游戏开发 计算机程序开发 Android开发 网站开发 笔记总结 其他
评分:
不限 10 9 8 7 6 5 4 3 2 1
原创:
不限
年份:
不限 2018 2019 2020

文章列表

  • 为程序创建任务栏右下角托盘图标

    背景我们用过很多应用程序,无论是功能复杂的大程序还是功能单一的小程序,大都会在计算机右下角显示一个图盘图标,然后我们可以直接把窗口关掉,通过点击托盘图标来控制程序的执行操作或显示窗口。使得程序使用起来比较便捷,不用显示程序主窗口就能完成一些操作,增强了程序的用户体验。
    本文要讲解的正是为程序添加这样的一个右下角托盘,并实现显示程序主窗口、退出程序等功能。本文分别在MFC程序和Windows应用程序中进行演示,其实,原理步骤都是相同的,只是为了方便大家理解,所以MFC程序和Windows程序都各写一个来演示。
    现在,我就把程序实现的过程整理成文档,分享给大家。
    函数介绍Shell_NotifyIcon 函数
    主要用于向任务栏的状态栏发送一个消息。
    函数声明
    BOOL Shell_NotifyIcon( DWORD dwMessage, PNOTIFYICONDATA lpdata);
    参数

    dwMessage为输入参数,传递发送的消息,表明要执行的操作。可选的值如下:NIM_ADD向托盘区域添加一个图标。此时第二个参数lpdata指向的NOTIFYICONDATA结构体中的hWnd和uID成员用来标示这个图标,以便以后再次使用Shell_NotifyIcon对此图标操作。NIM_DELETE删除托盘区域的一个图标。此时第二个参数lpdata指向的NOTIFYICONDATA结构体中的hWnd和uID成员用来标示需要被删除的这个图标。NIM_MODIFY修改托盘区域的一个图标。此时第二个参数lpdata指向的NOTIFYICONDATA结构体中的hWnd和uID成员用来标示需要被修改的这个图标。NIM_SETFOCUSVersion 5.0. 设置焦点。比如当用户操作托盘图标弹出菜单,而有按下ESC键将菜单消除后,程序应该使用此消息来将焦点设置到托盘图标上。NIM_SETVERSIONVersion 5.0. 设置任务栏按照第二个参数lpdata指向的NOTIFYICONDATA结构体中的uVersion成员指定的版本号来工作。此消息可以允许用户设置是否使用基于Windows2000的version 5.0的风格。uVersion的缺省值为0,默认指明了使用原始Windows 95图标消息风格。具体这两者的区别请参考msdn中的Shell_NotifyIcon函数说明的Remarks。lpdata为输入参数,是指向NOTIFYICONDATA结构体的指针,结构体内容用来配合第一个参数wMessage进行图标操作。
    返回值

    如果图标操作成功返回TRUE,否则返回FALSE。

    NOTIFYICONDATA 结构体
    结构体声明
    typedef struct _NOTIFYICONDATA { DWORD cbSize; HWND hWnd; UINT uID; UINT uFlags; UINT uCallbackMessage; HICON hIcon; TCHAR szTip[64]; DWORD dwState; DWORD dwStateMask; TCHAR szInfo[256]; union { UINT uTimeout; UINT uVersion; }; TCHAR szInfoTitle[64]; DWORD dwInfoFlags; GUID guidItem;} NOTIFYICONDATA, *PNOTIFYICONDATA;
    成员

    cbSize:结构体的大小,以字节为单位。hWnd:窗口的句柄。窗口用来接收与托盘图标相关的消息。Shell_NotifyIcon函数调用时,hWnd和uID成员用来标示具体要操作的图标。uID:应用程序定义的任务栏图标的标识符。Shell_NotifyIcon函数调用时,hWnd和uID成员用来标示具体要操作的图标。通过将多次调用,你可以使用不同的uID将多个图标关联到一个窗口。hWnd。uFlags:此成员表明具体哪些其他成员为合法数据(即哪些成员起作用)。此成员可以为以下值的组合:NIF_ICON:hIcon成员起作用。NIF_MESSAGE:uCallbackMessage成员起作用。NIF_TIP:szTip成员起作用。NIF_STATE:dwState和dwStateMask成员起作用。NIF_INFO:使用气球提示代替普通的工具提示框。szInfo, uTimeout, szInfoTitle和dwInfoFlags成员起作用。NIF_GUID:保留。uCallbackMessage:应用程序定义的消息标示。当托盘图标区域发生鼠标事件或者使用键盘选择或激活图标时,系统将使用此标示向由hWnd成员标示的窗口发送消息。消息响应函数的wParam参数标示了消息事件发生的任务栏图标,lParam参数根据事件的不同,包含了鼠标或键盘的具体消息,例如当鼠标指针移过托盘图标时,lParam将为WM_MOUSEMOVE。hIcon:增加、修改或删除的图标的句柄。注意,windows不同版本对于图标有不同要求。Windows XP可支持32位。szTip:指向一个以\0结束的字符串的指针。字符串的内容为标准工具提示的信息。包含最后的\0字符,szTip最多含有64个字符。对于Version 5.0 和以后版本,szTip最多含有128个字符(包含最后的\0字符)。dwState:Version 5.0,图标的状态,有两个可选值,如下:NIS_HIDDEN:图标隐藏NIS_SHAREDICON:图标共享dwStateMask:Version 5.0. 指明dwState成员的那些位可以被设置或者访问。比如设置此成员为NIS_HIDDEN,将导致只有hidden状态可以被获取。szInfo:Version 5.0. 指向一个以\0结束的字符串的指针。字符串的内容为气球提示内容。最多含有255个字符。如果要移除已经存在的气球提示信息,设置uFlags成员为NIF_INFO,同时将szInfo设为空。uTimeout:和uVersion成员为联合体。uTimeout表示气球提示超时的时间,单位为毫秒,此时间后气球提示将消失。系统默认气球提示的超时时间最小值为10秒,最大值为30秒。如果设置的uTimeout的值小于10将设置最小值,如果大于30将设置最大值。将超时时间分为最大最小两种,是因为解决不同图标的气球提示同时弹出的问题,详细内容请参考MSDN中NOTIFYICONDATA结构体说明的remarks。uVersion:Version 5.0. 和uTimeout成员为联合体。用来设置使用Windows 95 还是 Windows 2000风格的图标消息接口。szInfoTitle:Version 5.0. 指向一个以\0结束的字符串的指针。字符串的内容为气球提示的标题。此标题出现在气球提示框的上部,最多含有63个字符。dwInfoFlags:Version 5.0. 设置此成员用来给气球提示框增加一个图标。增加的图标出现在气球提示标题的左侧,注意如果szInfoTitle成员设为空字符串,则图标也不会显示。guidItem:Version 6.0. 保留。

    实现过程无论是对MFC程序还是Windows应用程序,实现的步骤和原理都是一样的。
    1. 设置 NOTIFYICONDATA首先,我们需要对托盘图标结构体 NOTIFYICONDATA 进行设置,设置的内容,就是我们想要托盘图标显示的内容。我们主要是对 NOTIFYICONDATA 的cbSize、hWnd、uID、uFlags、uCallbackMessage、hIcon以及szTip成员进行设置。
    其中,cbSize表示 NOTIFYICONDATA 结构体的大小;hWnd表示和托盘图标相关联的程序窗体的句柄,这个值需要被指定,因为窗口用来接收与托盘图标相关的消息;uID表示应用程序定义的任务栏图标的标识符,可以使用不同的uID将多个图标关联到一个窗口;uFlags表示哪些结构体成员起作用,NIF_ICON则hIcon成员起作用,NIF_MESSAGE则uCallbackMessage成员起作用,NIF_TIP则szTip成员起作用,所以下面我们还需要对hIcon、uCallbackMessage以及szTip成员赋值;hIcon表示托盘显示的图标句柄;uCallbackMessage表示托盘的消息类型;szTip表示托盘的提示信息。
    NOTIFYICONDATA notifyIconData = {0};::RtlZeroMemory(&notifyIconData, sizeof(notifyIconData));notifyIconData.cbSize = sizeof(NOTIFYICONDATA);notifyIconData.hWnd = hWnd;notifyIconData.uID = IDI_ICON1;notifyIconData.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP;notifyIconData.uCallbackMessage = WM_MYTASK;notifyIconData.hIcon = ::LoadIcon(::GetModuleHandle(NULL), (LPCSTR)IDI_ICON1);::lstrcpy(notifyIconData.szTip, "This Is A Notify Tip.");
    2. 增加托盘显示然后,我们开始调用 Shell_NotifyIcon 函数按照上面 NOTIFYICONDATA 设置新增托盘。其中,NIM_ADD表示向托盘区域添加一个图标。notifyIconData就是上面设置的 NOTIFYICONDATA 结构体变量。
    // 增加托盘::Shell_NotifyIcon(NIM_ADD, &notifyIconData);
    3. 托盘消息处理函数经过上面两步操作,我们就可以成功为程序在窗口右下角增加一个托盘图标显示。但是,我们还需要让托盘图标对一些操作做出响应,而不是只是显示而已。例如,我们鼠标右击托盘图标的时候,显示菜单栏。
    根据上面对 NOTIFYICONDATA 结构体成员 uCallbackMessage 介绍中知道 ,当托盘图标区域发生鼠标事件或者使用键盘选择或激活图标时,系统将使用此标示向由hWnd成员标示的窗口发送消息。消息响应函数的wParam参数标示了消息事件发生的任务栏图标,lParam参数根据事件的不同,包含了鼠标或键盘的具体消息,例如当鼠标指针移过托盘图标时,lParam将为WM_MOUSEMOVE。所以,我们要响应鼠标右键的操作,需要判断 lParam 是否为 WM_RBUTTONUP ,若是,弹出菜单,否则忽略操作。
    switch (lParam){// 鼠标右键弹起时case WM_RBUTTONUP: { // 弹出菜单 PopupMyMenu(); break;}default: break;}
    就这样,菜单弹出来后,我们直接响应菜单选项的消息响应函数,在对应的选项里执行相应的操作就好。
    为程序添加托盘显示的原理就是上面 3 个步骤,剩下来的就是编码实现了。
    编码实现Windows应用程序实现首先我们把对NOTIFYICONDATA结构体的设置以及添加托盘图标的操作代码都放在程序初始化WM_INITDIALOG操作里。
    然后,我们就开始在窗口消息过程函数中添加托盘消息类型WM_MYTASK,并对实现托盘消息处理响应函数。这样,在右击托盘的时候,就可以显示菜单栏了。
    窗口消息过程函数BOOL CALLBACK ProgMainDlg(HWND hWnd, UINT uiMsg, WPARAM wParam, LPARAM lParam){ if (WM_INITDIALOG == uiMsg) { // 设置托盘显示 SetNotifyIcon(hWnd); } else if (WM_CLOSE == uiMsg) { // 隐藏窗口 ::ShowWindow(hWnd, SW_HIDE); } else if (WM_MYTASK == uiMsg) { // 处理操作托盘的消息 OnTaskMsg(hWnd, wParam, lParam); } else if (WM_COMMAND == uiMsg) { if (ID_EXIT == wParam) { // 托盘菜单 退出 ::EndDialog(hWnd, NULL); } else if (ID_SHOW == wParam) { // 托盘菜单 显示主窗口 ::ShowWindow(hWnd, SW_SHOW); } } return FALSE;}
    设置托盘显示// 设置托盘显示void SetNotifyIcon(HWND hWnd){ NOTIFYICONDATA notifyIconData = {0}; ::RtlZeroMemory(&notifyIconData, sizeof(notifyIconData)); notifyIconData.cbSize = sizeof(NOTIFYICONDATA); notifyIconData.hWnd = hWnd; notifyIconData.uID = IDI_ICON1; notifyIconData.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP; notifyIconData.uCallbackMessage = WM_MYTASK; notifyIconData.hIcon = ::LoadIcon(::GetModuleHandle(NULL), (LPCSTR)IDI_ICON1); ::lstrcpy(notifyIconData.szTip, "This Is A Notify Tip."); // 增加托盘 ::Shell_NotifyIcon(NIM_ADD, &notifyIconData);}
    托盘消息处理函数// 处理操作托盘的消息LRESULT OnTaskMsg(HWND hWnd, WPARAM wParam, LPARAM lParam){ switch (lParam) { // 鼠标右键弹起时,弹出菜单 case WM_RBUTTONUP: { // 弹出菜单 PopupMyMenu(hWnd); break; } default: break; } return 0;}
    弹出菜单栏// 弹出菜单栏void PopupMyMenu(HWND hWnd){ POINT p; ::GetCursorPos(&p); HMENU hMenu = ::LoadMenu(::GetModuleHandle(NULL), (LPCSTR)IDR_MENU1); HMENU hSubMenu = ::GetSubMenu(hMenu, 0); ::TrackPopupMenu(hSubMenu, TPM_LEFTALIGN | TPM_RIGHTBUTTON, p.x, p.y, 0, hWnd, NULL); ::DestroyMenu(hSubMenu);}
    MFC程序实现和上面的Windows应用程序一样,首先我们把对NOTIFYICONDATA结构体的设置以及添加托盘图标的操作代码都放在程序初始化,对于MFC来说,初始化消息响应函数是主对话框类的OnInitDialog函数。我们把托盘设置这部分代码,放在函数OnInitDialog中即可。
    然后,我们开始对为自定义消息类型 WM_MYTASK 创建自定义消息响应函数 OnTaskMsg。创建自定义消息响应函数操作如下:

    声明消息类型 WM_MYTASK。
    #define WM_MYTASK (WM_USER + 100)
    声明消息响应函数,函数名称可以任意,但是返回值类型和参数类型是固定的。
    // 托盘消息处理函数 LRESULT OnTaskMsg(WPARAM wParam, LPARAM lParam);
    在主对话框的窗口消息响应列表中,为上述自定义的消息类型和消息响应函数进行关联。
    BEGIN_MESSAGE_MAP(CNotifyIcon_MFC_TestDlg, CDialogEx) … …(省略) ON_MESSAGE(WM_MYTASK, OnTaskMsg) END_MESSAGE_MAP()

    这样,我们就可以直接定义响应函数OnTaskMsg就可以了。
    接下来的操作和代码,基本上和Windows应用程序中的代码是一样的,所以,就给出代码了。若有什么问题,可以直接参考本文对应的程序代码即可。
    程序测试我们直接运行程序,便可以看到窗口右下角有托盘图标显示,然后我们鼠标右击图标,便成功弹出菜单栏,点击菜单栏选项,成功实现相应的操作。

    总结这个程序原理上不是很复杂,但是实现上面,由于Windows应用程序和MFC程序框架上不同,所以,要注意它们的区别,特别是MFC的自定义消息响应函数。
    参考参考自《Windows黑客编程技术详解》一书
    2 回答 2018-12-20 12:32:31
  • 编程实现MFC程序窗口一运行立马隐藏

    背景MFC程序在启动显示窗口之前,就已经做了很多关于界面初始化的操作。如果对WIN32 API函数较为熟悉的同学就会认为,让窗口隐藏,直接调用 ShowWindow 函数,将窗口设置为隐藏就可以了。是的,ShowWindow 函数可以隐藏窗口没错。但是,这个函数要成功实现的窗口隐藏有一个前提条件,就是窗口界面初始化已经完成,而且窗口界面你已经显示完全了。这时,再调用 ShowWindow 函数去隐藏窗口,这是可以的。
    但是,本文要实现的是,窗口程序一运行就已经开始隐藏的功能,而不是显示后隐藏。也就是说,在窗口界面初始化阶段,窗口界面还没有显示的时候,就已经开始隐藏界面了。这样的隐藏,使得程序运行无声无息。
    现在,我们把这个程序的实现过程整理成文档,分享给大家。
    函数介绍MoveWindow 函数
    改变指定窗口的位置和大小。对子窗口来说,位置和大小取决于父窗口客户区的左上角;对于Owned窗口,位置和大小取决于屏幕左上角。
    函数声明
    BOOL MoveWindow( HWND hWnd, int X, int Y, int nWidth, int nHeight, BOOL bRepaint );
    参数

    hWnd [in]窗口的句柄。X [in]窗口左侧的新位置。Y [in]窗口顶部的新位置。nWidth [in]窗口的新宽度。nHeight [in]窗口的新高度。bRepaint [in]指示窗口是否要重画。 如果此参数为TRUE,窗口将收到一条消息。 如果参数为FALSE,则不会发生任何重画。 这适用于客户端区域,非客户区域(包括标题栏和滚动条),父窗口的任何部分由于移动子窗口而被覆盖。
    返回值

    如果函数成功,则返回值不为零。如果函数失败,返回值为零。 要获取扩展错误信息,请调用GetLastError。

    GetWindowLong 函数
    获取有关指定窗口的信息。 函数也获得在额外窗口内存中指定偏移位地址的32位度整型值。
    函数声明
    LONG GetWindowLong( HWND hWnd, int nlndex );
    参数

    hWnd目标窗口的句柄。它可以是窗口句柄及间接给出的窗口所属的窗口类。
    nlndex需要获得的相关信息的类型。要获得任意其他值,指定下列值之一:




    VALUE
    MEANING




    GWL_EXSTYLE
    获得扩展窗口风格。


    GWL_HINSTANCE
    获得应用实例的句柄


    GWL_HWNDPARENT
    如果父窗口存在,获得父窗口句柄


    GWL_ID
    获得窗口标识


    GWL_STYLE
    获得窗口风格


    GWL_USERDATA
    获得与窗口有关的32位值。每一个窗口均有一个由创建该窗口的应用程序使用的32位值


    GWL_WNDPROC
    获得窗口过程的地址,或代表窗口过程的地址的句柄。必须使用CallWindowProc函数调用窗口过程



    hWnd参数为对话框句柄时,还可用下列值:



    VALUE
    MEANING




    DWL_DLGPROC
    获得对话框过程的地址,或一个代表对话框过程的地址的句柄。必须使用函数CallWindowProc来调用对话框过程


    DWL_MSGRESULT
    获得在对话框过程中一个消息处理的返回值


    DWL_USER
    获得应用程序私有的额外信息,例如一个句柄或指针



    返回值

    如果函数成功,返回值是所需的32位值;如果函数失败,返回值是0。若想获得更多错误信息请调用 GetLastError函数。

    SetWindowLong 函数
    用来改变指定窗口的属性.函数也将指定的一个32位值设置在窗口的额外存储空间的指定偏移位置。
    函数声明
    LONG SetWindowLong( HWND hWnd, // handle to window int nlndex, // offset of value to set LONG dwNewLong // new value);
    参数

    hWnd窗口句柄及间接给出的窗口所属的类。nlndex设置相关信息的类型。要获得任意其他值,指定下列值之一(和上面 GetWindowLong 函数的 nIndex 值相同)。dwNewLong指定的替换值。
    返回值

    如果函数成功,返回值是指定的32位整数的原来的值。如果函数失败,返回值为0。若想获得更多错误信息,请调用GetLastError函数。

    实现原理窗口移动到显示屏幕之外要设置程序窗口显示的位置和大小,我们可以直接调用 MoveWindow 函数,设置移动后窗口显示的位置坐标、窗口大小。这时,我们只需要将窗口大小都设为 0 ,位置坐标都设为-1000(屏幕位置坐标以屏幕左上角为起点),这样窗口就在屏幕之外显示了。
    隐藏任务栏程序图标其中,我们先来了解 GWL_EXSTYLE 窗口拓展属性中的两个值的含义,这是要理解隐藏任务栏比较关键的一步:
    一是 WS_EX_APPWINDOW,表示当窗口可见时,将一个顶层窗口放置到任务条上;
    二是 WS_EX_TOOLWINDOW,表示创建工具窗口,即窗口是一个游动的工具条。工具窗口的标题条比一般窗口的标题条短,并且窗口标题以小字体显示。工具窗口不在任务栏里显示,当用户按下alt+Tab键时工具窗口不在对话框里显示。如果工具窗口有一个系统菜单,它的图标也不会显示在标题栏里,但是,可以通过点击鼠标右键或Alt+Space来显示菜单。
    由上面 WS_EX_APPWINDOW 和 WS_EX_TOOLWINDOW 可知,我们要想实现任务栏程序的隐藏。那么,就要把 WS_EX_APPWINDOW 值去掉,然后再增加值 WS_EX_TOOLWINDOW。所以:

    首先调用 GetWindowLong 函数获取窗口 GWL_EXSTYLE 属性的值 dwOldStyle;
    然后,去掉 WS_EX_APPWINDOW 值,即
    dwOldStyle & (~WS_EX_APPWINDOW)
    接着,增加 WS_EX_APPWINDOW 值,即
    dwNewStyle = dwNewStyle | WS_EX_TOOLWINDOW;
    最后,调用 SetWindowLong 将新的 GWL_EXSTYLE 属性的值重新设置,这样就完成了。

    编码实现// 隐藏窗口void HideWindow(HWND hWnd){ // 把窗口移动到屏幕显示之外, 窗口大小都设为 0 ::MoveWindow(hWnd, -1000, -1000, 0, 0, FALSE); // 先获取原来窗口的拓展风格 DWORD dwOldStyle = ::GetWindowLong(hWnd, GWL_EXSTYLE); // 设置新属性, 隐藏任务栏程序图标 DWORD dwNewStyle = dwOldStyle & (~WS_EX_APPWINDOW); dwNewStyle = dwNewStyle | WS_EX_TOOLWINDOW; ::SetWindowLong(hWnd, GWL_EXSTYLE, dwNewStyle);}
    总结我们隐藏窗口的思路就两点:一是把窗口的显示位置坐标移到屏幕之外,这样窗口显示的时候,在屏幕之内是看不到的;二是把任务栏的程序图标隐藏,因为第一步操作会因为任务栏下的图标露出马脚,所以,必须隐藏任务栏中程序的图标。这样,就可以实现一运行程序,窗口就隐藏了。
    大家要注意,虽然窗口隐藏了,我们打开任务管理器还是会看到我们程序的进程的。所以,关于进程隐藏,就是另一个不同知识点了。
    参考参考自《Windows黑客编程技术详解》一书
    2 回答 2018-12-20 12:32:48
  • 基于MuPDF库实现PDF文件转换成PNG格式图片

    背景之所以会接触MuPDF是因为,有位群友在Q群里提问,如何将PDF保存为.PNG图片格式。我一看到这个问题,就蒙了,因为我没有接触过类似的项目或程序。但是,作为一群之主的我,还是要给初学者一个答复的,所以便去网上搜索了相关信息,才了解到有MuPDF开源库的存在。
    MuPDF是一种轻量级的PDF,XPS和电子书阅读器。由各种平台的软件库,命令行工具和查看器组成。支持许多文档格式,如PDF,XPS,OpenXPS,CBZ,EPUB和FictionBook 2。
    后来,自己就根据网上搜索到的一些资料,实现了基于MuPDF库将PDF指定页转换成PNG格式图片的小程序。现在,我就把程序的实现思路和过程写成文档,分享给大家。
    实现思路对于MuPDF库的源码下载以及编译过程,可以参考本站的《使用VS2013编译MuPDF库》这篇文章。
    其实,在MuPDF库中就提供了这一个功能:将PDF指定页转换成PNG格式图片,所以,我们直接编译MuPDF提供的代码就可以了。
    示例程序代码位于MuPDF库源码的“docs”目录下的“example.c”文件,我们只需使用VS2013创建一个空项目,然后把“example.c”文件导入项目中,接着将“include”目录中的头文件以及编译出来的libmupdf.lib、libmupdf-js-none.lib、libthirdparty.lib导入文件中即可。
    其中,“example.c”中主要的函数就是 render 函数,我们主要是把参数传进render函数,就可以把pdf转换成png图片了。
    对于“example.c”的代码可以不用修改,直接编译运行即可。但是,为了方便演示,我们还是对“example.c”中的 main 函数进行修改。
    编码实现以下是“example.c”文件中 render 函数的源码:
    void render(char *filename, int pagenumber, int zoom, int rotation){ // Create a context to hold the exception stack and various caches. fz_context *ctx = fz_new_context(NULL, NULL, FZ_STORE_UNLIMITED); // Open the PDF, XPS or CBZ document. fz_document *doc = fz_open_document(ctx, filename); // Retrieve the number of pages (not used in this example). int pagecount = fz_count_pages(doc); // Load the page we want. Page numbering starts from zero. fz_page *page = fz_load_page(doc, pagenumber - 1); // Calculate a transform to use when rendering. This transform // contains the scale and rotation. Convert zoom percentage to a // scaling factor. Without scaling the resolution is 72 dpi. fz_matrix transform; fz_rotate(&transform, rotation); fz_pre_scale(&transform, zoom / 100.0f, zoom / 100.0f); // Take the page bounds and transform them by the same matrix that // we will use to render the page. fz_rect bounds; fz_bound_page(doc, page, &bounds); fz_transform_rect(&bounds, &transform); // Create a blank pixmap to hold the result of rendering. The // pixmap bounds used here are the same as the transformed page // bounds, so it will contain the entire page. The page coordinate // space has the origin at the top left corner and the x axis // extends to the right and the y axis extends down. fz_irect bbox; fz_round_rect(&bbox, &bounds); fz_pixmap *pix = fz_new_pixmap_with_bbox(ctx, fz_device_rgb(ctx), &bbox); fz_clear_pixmap_with_value(ctx, pix, 0xff); // A page consists of a series of objects (text, line art, images, // gradients). These objects are passed to a device when the // interpreter runs the page. There are several devices, used for // different purposes: // // draw device -- renders objects to a target pixmap. // // text device -- extracts the text in reading order with styling // information. This text can be used to provide text search. // // list device -- records the graphic objects in a list that can // be played back through another device. This is useful if you // need to run the same page through multiple devices, without // the overhead of parsing the page each time. // Create a draw device with the pixmap as its target. // Run the page with the transform. fz_device *dev = fz_new_draw_device(ctx, pix); fz_run_page(doc, page, dev, &transform, NULL); fz_free_device(dev); // Save the pixmap to a file. fz_write_png(ctx, pix, "out.png", 0); // Clean up. fz_drop_pixmap(ctx, pix); fz_free_page(doc, page); fz_close_document(doc); fz_free_context(ctx);}
    程序测试我们修改 main 函数直接调用上述函数接口, main 函数为:
    int main(int argc, char **argv){ // 文件路径 char filename[MAX_PATH] = "C:\\Users\\DemonGan\\Desktop\\test.pdf"; // 转换的页码数 int pagenumber = 1; // 缩放比例 int zoom = 100; // 旋转角度 int rotation = 0; // 处理 render(filename, pagenumber, zoom, rotation); system("pause"); return 0;}
    直接运行程序,目录下有 out.png 图片生成,打开图片查看内容,发现是 test.pdf 的第一页内容,所以转换成功。
    总结这个程序的实现,自己可以不用写代码就可以完成。因为MuPDF已经把接口都封装好了,而且也有示例程序可以直接调用。如果想要把界面做得更有好些,可以把程序写成界面程序,然后直接调用现在的这个 render 函数接口,进行转换即可。
    3 回答 2018-12-20 12:37:25
显示 75 到 78 ,共 3 条
eject