Qt多功能PDF阅读器

多功能PDF阅读器

多功能PDF阅读器用于PDF文档的打开和编辑,主要由文档收藏、页面交互、笔记系统三个部分组成。其中,文档收藏功能可搭配云盘工具(如坚果云)使用,实现与云端同步操作。笔记系统可兼容其它工具(如Foxit、Xodo等),由其它工具生成的笔记也可以使用本阅读器进行编辑。最后,概览功能用于在页面两侧显示注释文字,该功能非常适用于双栏文档(如论文)的阅读和回顾。

文档收藏系统

文档收藏系统主要用于提供不同位置目录的快捷入口,配合云盘工具(如坚果云)后,可以实现快速打开以及修改自动同步到云的功能。

笔记系统

本阅读器支持文本、几何(圆形、方形)、箭头及注释笔记的创建和编辑。选中笔记后,左键拖动可改变笔记位置,右键点击可弹出对话框,以修改笔记的各类参数。

概览模式

概览模式是我们针对双栏文档阅读设计的功能,概览模式下,原本隐藏的注释可以通过弹框显示在文档两侧。首次阅读文档时,用户可将每一部分内容的翻译、总结或批注用注释形式进行保存,概览模式下,这些笔记将显示在对应位置两侧,非常便于对双栏论文进行回顾。

 // 返回PDF页面项的边界矩形
QRectF PaperItem::boundingRect() const
{
    QImage **addr = (QImage **)(images + index*size);
    return QRectF(0, 0, (*addr)->width(), (*addr)->height());
}

 // 绘制PDF页面项
void PaperItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
    QImage **addr = (QImage **)(images + index*size);
    painter->drawImage(0, 0, **addr);
}

bool MainScene::loadFile(const QString &addr)
{
    this->filename = addr;
    document->document = Poppler::Document::load(addr);
    if (!document || document->document->isLocked()) {
        delete document;
        return false;
    }

    if(document->document->numPages()>30)
    {
        return false;
    }

    for(int i=0; i<document->document->numPages(); i++)
    {
        indexes.append(i);
    }

    document->document->setRenderHint(Poppler::Document::TextAntialiasing, 1);
    document->document->setRenderHint(Poppler::Document::Antialiasing, 1);

    /* set hidden */
    for(int pageidx=0; pageidx<document->document->numPages(); pageidx++)
    {
        for(int i=0;i<document->document->page(pageidx)->annotations().length();i++)
        {
            int type = document->document->page(pageidx)->annotations().at(i)->subType();
            if(type==1 || type==2 || type==3 || type==6)
            {
                document->document->page(pageidx)->annotations().at(i)->setFlags(Poppler::Annotation::Hidden);
            }
        }
    }

    QProgressDialog *progressDlg=new QProgressDialog(nullptr);
    progressDlg->setWindowModality(Qt::WindowModal);
    progressDlg->setMinimumDuration(5);
    progressDlg->setWindowTitle(tr("载入进度"));
    progressDlg->setLabelText(tr("正在加载"));
    progressDlg->setRange(0, document->document->numPages());
    QPushButton *button = new QPushButton(tr("取消"));
    button->setEnabled(false);
    progressDlg->setCancelButton(button);

    for(int i=0; i<document->document->numPages(); i++)
    {
        QImage *image = new QImage(document->document->page(i)->renderToImage(xres, yres, -1, -1, -1, -1));
        if(i==0)
        {
            width = image->width();
            height = image->height()*document->document->numPages();
        }
        document->images[i] = image;
        QImage *tmptmp = *(&(document->images[0]));
        pages.append(new PaperItem(i, (long)(&(document->images[0]))));
        pages.at(i)->setPos(0, image->height()*i+SPACING*i);
        addItem(pages.at(i));
        progressDlg->setValue(i+1);
    }

    setSceneRect(0, 0, width, height);
    document->startTimer();

    for(int pageidx=0; pageidx<document->document->numPages(); pageidx++)
    {
        for(int i=0;i<document->document->page(pageidx)->annotations().length();i++)
        {
            switch(document->document->page(pageidx)->annotations().at(i)->subType())
            {
            case 1:  // Text Annotation
            {
                Poppler::TextAnnotation *annotation = (Poppler::TextAnnotation *)(document->document->page(pageidx)->annotations().at(i));
                annotation->setFlags(Poppler::Annotation::Hidden);
                if(annotation->textType()==1)
                {
                    annotations.append(new PaperAnnotation::FlatTextAnnotation(pageidx, annotation, width, height/document->document->numPages(), scale));
                    this->addItem(annotations.at(annotations.length()-1));
                    connect(((PaperAnnotation::FlatTextAnnotation *)(annotations.last())),
                            &PaperAnnotation::FlatTextAnnotation::posChanged,
                            this, &MainScene::send_status_changed);
                    // 添加删除接口
                    connect((PaperAnnotation::FlatTextAnnotation *)(annotations.last()), &PaperAnnotation::FlatTextAnnotation::deleteSelf,
                            this, &MainScene::removeCertainItem);
                    //                    this->removeItem(tmprectitem);
                }
                else {
                    annotations.append(new PaperAnnotation::PopupTextAnnotation(pageidx, annotation, width, height/document->document->numPages(), scale));
                    this->addItem(annotations.at(annotations.length()-1));
                    connect((PaperAnnotation::PopupTextAnnotation *)(annotations.last()), &PaperAnnotation::PopupTextAnnotation::deleteSelf,
                            this, &MainScene::removeCertainItem);
                    //annotations.append(new PaperAnnotation::PreviewAnnotation(pageidx, annotation, width, height/document->document->numPages(), scale));
                    //this->addItem(annotations.last());
                }
                break;
            }
            case 3:  // Geom Annotation
            {
                Poppler::GeomAnnotation *annotation = (Poppler::GeomAnnotation *)(document->document->page(pageidx)->annotations().at(i));
                annotation->setFlags(Poppler::Annotation::Hidden);
                annotations.append(new PaperAnnotation::GeomAnnotation(pageidx, annotation, width, height/document->document->numPages(), scale));
                this->addItem(annotations.at(annotations.length()-1));
                connect(((PaperAnnotation::GeomAnnotation *)(annotations.last())),
                        &PaperAnnotation::GeomAnnotation::posChanged,
                        this, &MainScene::send_status_changed);
                // 添加删除接口
                connect((PaperAnnotation::GeomAnnotation *)(annotations.last()), &PaperAnnotation::GeomAnnotation::deleteSelf,
                        this, &MainScene::removeCertainItem);
                break;
            }
            case 2:  // LineAnnotation
            {
                Poppler::LineAnnotation *annotation = (Poppler::LineAnnotation *)(document->document->page(pageidx)->annotations().at(i));
                annotation->setFlags(Poppler::Annotation::Hidden);
                annotations.append(new PaperAnnotation::LineAnnotation(pageidx, annotation, width, height/document->document->numPages(), scale));
                this->addItem(annotations.at(annotations.length()-1));
                connect(((PaperAnnotation::LineAnnotation *)(annotations.last())),
                        &PaperAnnotation::LineAnnotation::posChanged,
                        this, &MainScene::send_status_changed);
                // 添加删除接口
                connect((PaperAnnotation::LineAnnotation *)(annotations.last()), &PaperAnnotation::LineAnnotation::deleteSelf,
                        this, &MainScene::removeCertainItem);

                QLinkedListIterator<QPointF> rwIterator(annotation->linePoints());
                startPoint = rwIterator.next();
                rwIterator.toBack();
                endPoint = rwIterator.previous();
                break;
            }
            case 6:  // Ink Annotation
            {
                Poppler::InkAnnotation *annotation = (Poppler::InkAnnotation *)(document->document->page(pageidx)->annotations().at(i));
                annotation->setFlags(Poppler::Annotation::Hidden);
                annotations.append(new PaperAnnotation::InkAnnotation(pageidx, annotation, width, height/document->document->numPages(), scale));
                this->addItem(annotations.at(annotations.length()-1));
                break;
            }
            }
        }
    }

    return true;
}

  // 处理鼠标滚轮事件,实现页面缩放
void GraphicsView::wheelEvent(QWheelEvent *ev)
{
    if(ev->modifiers() & Qt::ControlModifier)
    {
        if(ev->delta()>0 & scalefactor>2)
        {
            ev->ignore();
            return;
        }
        else if(ev->delta()<0 & scalefactor<0.5)
        {
            ev->ignore();
            return;
        }
        else
        {
            mainscene->document->indexes.clear();
            if(!refreshtimer->isActive())
            {
                oldCenterPoint = mapToScene(QPoint(width()/2, height()/2));
                currentScenePoint = mapToScene(ev->pos());
                lengthPoint = oldCenterPoint-currentScenePoint;
                mainscene->currentpage = (int)(currentScenePoint.y()/height()/scalefactor);
            }

            if(ev->delta()>0)
            {
                refreshtimer->stop();
                point = mapToScene(QPoint(this->x()*1.2+this->width()/2*1.2, this->y()*1.2+this->height()/2*1.2));
                scale(1.2, 1.2);
                scalefactor*=1.2;
                mainscene->scale = scalefactor;
                centerPoint = currentScenePoint+lengthPoint/scalefactor*oldscalefactor;
                centerOn(centerPoint);
                refreshtimer->start(500);
            }
            else
            {
                refreshtimer->stop();
                point = mapToScene(QPoint(this->x()/1.2+this->width()/2/1.2, this->y()/1.2+this->height()/2/1.2));
                scale(1/1.2, 1/1.2);
                scalefactor*=1/1.2;
                mainscene->scale = scalefactor;
                QPointF lengthPoint = oldCenterPoint-currentScenePoint;
                centerPoint = currentScenePoint+lengthPoint/scalefactor*oldscalefactor;
                centerOn(centerPoint);
                refreshtimer->start(500);
            }
            ev->accept();
        }
    }
    else
    {
        QGraphicsView::wheelEvent(ev);
    }
}

环境要求

Qt: 5.15.2

因为Poppler是32位的,所以只能Qt 5.15.2 MinGW 32位编译

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值