注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

Nihui's Blog

nihui的私人空间和日志

 
 
 

日志

 
 

okular 的设计和后端  

2010-02-25 14:26:00|  分类: KDE related |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |
        okular 为了支持各种格式的文档,采用了模块化的设计思路。
        okular 可分为四个部分:
外壳(Shell)
部件(Part)
文档对象(Okular::Document)
后端(Okular::Generator)
        外壳只是作为独立启动 okular 是嵌入部件的部分;部件主要负责呈现,比如各种书签,内容列表,菜单等;文档对象是个抽象概念,包含了文档的各个页面内容,尺寸方向等。
        文档对象必须从后端获取这些内容信息,后端得把文档文件本身解析并转换为 okular 内部用于展示的通用模式,再交给文档对象。
        那么内部使用的通用模式是如何的呢?看看各种文档有什么共同点吧。大家都有“页”这个概念,哪怕是图片也可以看成只有一页的文档。每个页面都有大小尺寸方向。最终,页面都可以转换成图片给用户看,就像把内容打印在一张纸上。后端最基本的任务就是得知这个文档一共有几页,然后需要转换为图片。对于放大缩小这类需求,一些基于矢量图形的文档,例如 PDF 和 PostScript,后端只需要将矢量图形渲染成需要的尺寸就可以了,而一些静态的内容,例如图像文件,后端就必须进行缩放操作再交给文档对象。
        文档对象从后端获取页面图片之后便可以进行一些附加操作了,比如应用切换的特效和旋转等等。
        有些格式支持从文档内容中获取文本,比如 PDF。okular 要获取这些文字,是通过用户使用鼠标选取一块区域然后再获得该区域中的文本。这种位置到文字的方式会因为缩放的关系而无法直接确定。okular 定义了一种 0 到 1 的绝对比例坐标,按照比例坐标乘以缩放系数得到对应的实际位置。比如有个文字在页面中央的位置,那么坐标即为 (0.5, 0.5)。
        此外,后端还会负责获取文档的元数据信息。如文档作者、创建日期、版本、内容排版、书签、批注。

        okular 的强大之处就在于后端插件的可扩展性。接下来将为你展示如何自己写一个 okular 后端。
示例中的 Magic 文档格式是假象中的东西,实际上是没有的。
最基本的后端:装入文档,获取页数,返回指定尺寸的页面图片

以下部分纯照抄,来自 okular team。
/*******************************************************************************************************************************/
class MagicDocument
{
public:
MagicDocument();
~MagicDocument();

bool loadDocument( const QString &fileName );

int numberOfPages() const;

QSize pageSize( int pageNumber ) const;

QImage pictureOfPage( int pageNumber ) const;

private:
...
};
后端的 API 是这样子的:
##########################################################################
#include "magicdocument.h"

#include <okular/core/generator.h>

class MagicGenerator : public Okular::Generator
{
public:
MagicGenerator( QObject *parent, const QVariantList &args );
~MagicGenerator();

bool loadDocument( const QString &fileName, QVector<Okular::Page*> &pages );

bool canGeneratePixmap() const;
void generatePixmap( Okular::PixmapRequest *request );

protected:
bool doCloseDocument();

private:
MagicDocument mMagicDocument;
};
##########################################################################
#include <okular/core/page.h>

#include "magicgenerator.h"

static KAboutData createAboutData()
{
KAboutData aboutData(...);
// fill the about data
return aboutData;
}

OKULAR_EXPORT_PLUGIN(MagicGenerator, createAboutData())

MagicGenerator::MagicGenerator( QObject *parent, const QVariantList &args )
: Okular::Generator( parent, args )
{
}

MagicGenerator::~MagicGenerator()
{
}

// loadDocument 装入文档文件并获取文档页数。文档内的每个页面都会向 pages 添加一个 Okular::Page 对象,

bool MagicGenerator::loadDocument( const QString &fileName, QVector<Okular::Page*> &pages )
{
if ( !mMagicDocument.loadDocument( fileName ) ) {
emit error( i18n( "Unable to load document" ), -1 );
return false;
}

pages.resize( mMagicDocument.numberOfPages() );

for ( int i = 0; i < mMagicDocument.numberOfPages(); ++i ) {
const QSize size = mMagicDocument.pageSize( i );

Okular::Page * page = new Okular::Page( i, size.width(), size.height(), Okular::Rotation0 );
pages[ i ] = page;
}

return true;
}

bool MagicGenerator::doCloseDocument()
{
return true;
}

bool MagicGenerator::canGeneratePixmap() const
{
return true;
}

void MagicGenerator::generatePixmap( Okular::PixmapRequest *request )
{
QImage image = mMagicDocument.pictureOfPage( request->pageNumber() );

image = image.scaled( request->width(), request->height(), Qt::IgnoreAspectRatio, Qt::SmoothTransformation );

request->page()->setPixmap( request->id(), new QPixmap( QPixmap::fromImage( image ) ) );

signalPixmapRequestDone( request );
}
##########################################################################






  评论这张
 
阅读(988)| 评论(0)
推荐 转载

历史上的今天

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017