diff options
author | ZackaryWelch <welch.zackary@gmail.com> | 2018-04-27 17:26:02 -0400 |
---|---|---|
committer | ZackaryWelch <welch.zackary@gmail.com> | 2018-04-27 17:26:02 -0400 |
commit | 253bacc6ee0d825564bef6aa507296e79b2611ff (patch) | |
tree | 0d87304383654f25f83259cdb0ae776706250c23 /src-qt5/desktop-utils/lumina-pdf/Renderer-mupdf.cpp | |
parent | Merge branch 'master' of http://github.com/trueos/lumina (diff) | |
download | lumina-253bacc6ee0d825564bef6aa507296e79b2611ff.tar.gz lumina-253bacc6ee0d825564bef6aa507296e79b2611ff.tar.bz2 lumina-253bacc6ee0d825564bef6aa507296e79b2611ff.zip |
Added more annotation and widget support. Currently incomplete. Updated to MuPDF 1.13.
Diffstat (limited to 'src-qt5/desktop-utils/lumina-pdf/Renderer-mupdf.cpp')
-rw-r--r-- | src-qt5/desktop-utils/lumina-pdf/Renderer-mupdf.cpp | 350 |
1 files changed, 283 insertions, 67 deletions
diff --git a/src-qt5/desktop-utils/lumina-pdf/Renderer-mupdf.cpp b/src-qt5/desktop-utils/lumina-pdf/Renderer-mupdf.cpp index 31a07e01..a52fd5b4 100644 --- a/src-qt5/desktop-utils/lumina-pdf/Renderer-mupdf.cpp +++ b/src-qt5/desktop-utils/lumina-pdf/Renderer-mupdf.cpp @@ -1,34 +1,17 @@ #include "Renderer.h" #include "TextData.h" -#include <QDateTime> #include <mupdf/fitz.h> #include <mupdf/pdf.h> +#include <QDateTime> #include <QMutex> #include <QFuture> #include <QtConcurrent> -class Annot{ - public: - Annot(fz_context *_ctx, pdf_annot *_fzAnnot, char *_text, char *_author, QRectF _loc = QRectF()) : fzAnnot(_fzAnnot), ctx(_ctx), loc(_loc) { - author = (_author) ? QString::fromLocal8Bit(_author) : QString(); - text = (_text) ? QString::fromLocal8Bit(_text) : QString(); - } - - ~Annot() { - fz_drop_annot(ctx, (fz_annot*)fzAnnot); - } - - QString getAuthor() { return author; } - QString getText() { return text; } - QRectF getLoc() { return loc; } +class Annot; - private: - pdf_annot *fzAnnot; - fz_context *ctx; - QString author; - QString text; - QRectF loc; -}; +inline QRectF convertRect(fz_rect bbox, double sf=1.0) { + return QRectF(sf*bbox.x0, sf*bbox.y0, sf*(bbox.x1-bbox.x0), sf*(bbox.y1 - bbox.y0)); +} class Link { public: @@ -52,15 +35,14 @@ class Link { class Data { public: - Data(int _pagenum, fz_context *_ctx, fz_display_list *_list, fz_rect _bbox, fz_matrix _ctm, double _sf, fz_link *_link, QList<Annot*> &_annot) : pagenumber(_pagenum), ctx(_ctx), list(_list), bbox(_bbox), ctm(_ctm), sf(_sf), annotList(_annot) { + Data(int _pagenum, fz_context *_ctx, fz_display_list *_list, fz_rect _bbox, fz_matrix _ctm, double _sf, fz_link *_link, QList<Annot*> &_annot, QList<Widget*> &_widgets) : pagenumber(_pagenum), ctx(_ctx), list(_list), bbox(_bbox), ctm(_ctm), sf(_sf), annotList(_annot), widgetList(_widgets) { while(_link) { - QRectF rect(sf*_link->rect.x0, sf*_link->rect.y0, sf*(_link->rect.x1 - _link->rect.x0), sf*(_link->rect.y1 - _link->rect.y0)); + QRectF rect = convertRect(_link->rect, sf); Link *link = new Link(_ctx, _link, _link->uri, _pagenum, rect); linkList.append(link); _link = _link->next; } - } ~Data() { @@ -70,14 +52,19 @@ class Data { linkList.clear(); qDeleteAll(annotList); annotList.clear(); + qDeleteAll(widgetList); + widgetList.clear(); } int getPage() { return pagenumber; } QList<Link*> getLinkList() { return linkList; } - QList<Annot*> getAnnotList() { return annotList; } + Annot* getAnnotList(int i) { return annotList[i]; } + Widget* getWidgetList(int i) { return widgetList[i]; } + int getAnnotSize() { return annotList.size(); } + int getWidgetSize() { return widgetList.size(); } fz_context* getContext() { return ctx; } fz_display_list* getDisplayList() { return list; } - QRectF getScaledRect() { return QRectF(sf*bbox.x0, sf*bbox.y0, sf*(bbox.x1-bbox.x0), sf*(bbox.y1 - bbox.y0)); } + QRectF getScaledRect() { return convertRect(bbox, sf); } fz_rect getBoundingBox() { return bbox; } fz_matrix getMatrix() { return ctm; } QImage getImage() { return img; } @@ -95,6 +82,7 @@ class Data { QList<Link*> linkList; double sf; QList<Annot*> annotList; + QList<Widget*> widgetList; fz_pixmap *pix; QImage img; @@ -107,6 +95,32 @@ QHash<int, Data*> dataHash; QMutex mutex[FZ_LOCK_MAX]; fz_locks_context locks; +class Annot : public Annotation{ + public: + Annot(fz_context *_ctx, pdf_annot *_fzAnnot, int _type, int _i, float _opacity, QRectF _loc = QRectF()) : Annotation(_type, _opacity, _loc), ctx(_ctx), fzAnnot(_fzAnnot), pageNum(_i) { } + virtual ~Annot() { fz_drop_annot(ctx, (fz_annot*)fzAnnot); } + + virtual QImage renderImage() { + fz_rect bbox; + fz_irect rbox; + pdf_bound_annot(ctx, fzAnnot, &bbox); + + fz_pixmap *pixmap = fz_new_pixmap_with_bbox(ctx, fz_device_rgb(ctx), fz_round_rect(&rbox, &bbox), NULL, 0); + fz_clear_pixmap_with_value(ctx, pixmap, 0xff); + fz_device *dev = fz_new_draw_device(ctx, &fz_identity, pixmap); + fz_run_display_list(ctx, dataHash[pageNum]->getDisplayList(), dev, &fz_identity, &bbox, NULL); + + QImage image(pixmap->samples, pixmap->w, pixmap->h, pixmap->stride, QImage::Format_RGB888); + return image; + } + + private: + fz_context *ctx; + pdf_annot *fzAnnot; + + int pageNum; +}; + inline QString getTextInfo(QString str) { char infoBuff[1000]; int size = DOC->lookup_metadata(CTX, DOC, ("info:"+str).toLocal8Bit().data(), infoBuff, 1000); @@ -137,6 +151,7 @@ Renderer::Renderer(){ } Renderer::~Renderer(){ + //pdf_clean_page_contents qDebug() << "Dropping Context"; clearHash(); fz_drop_document(CTX, DOC); @@ -147,7 +162,7 @@ Renderer::~Renderer(){ bool Renderer::loadMultiThread(){ return false; } -void Renderer::handleLink(QString link) { +void Renderer::handleLink(QWidget *obj, QString link) { float xp = 0.0, yp = 0.0; int pagenum = 0; @@ -155,9 +170,13 @@ void Renderer::handleLink(QString link) { char *uri = linkData.data(); if(!link.isEmpty()) { - pagenum = fz_resolve_link(CTX, DOC, uri, &xp, &yp); - if(pagenum != -1) - emit goToPosition(pagenum+1, xp, yp); + if(fz_is_external_link(CTX, uri)) { + if(QMessageBox::Yes == QMessageBox::question(obj, tr("Open External Link?"), QString(tr("Do you want to open %1 in the default browser")).arg(link), QMessageBox::Yes | QMessageBox::No, QMessageBox::No) ){ QProcess::startDetached("firefox \""+link+"\""); } + }else{ + pagenum = fz_resolve_link(CTX, DOC, uri, &xp, &yp); + if(pagenum != -1) + emit goToPosition(pagenum+1, xp, yp); + } } } @@ -193,6 +212,8 @@ bool Renderer::loadDocument(QString path, QString password){ qDebug() << "Document handlers registered"; } + //fz_page_presentation + docpath = path; DOC = fz_open_document(CTX, path.toLocal8Bit().data()); qDebug() << "File opened" << DOC; @@ -280,49 +301,250 @@ void Renderer::renderPage(int pagenum, QSize DPI, int degrees){ fz_rect bbox; fz_display_list *list; - //double pageDPI = 96.0; - //double sf = DPI.width() / pageDPI; - double sf = 1; - //fz_scale(&matrix, sf, sf); - fz_rotate(&matrix, degrees); + double pageDPI = 96.0; + double sf = DPI.width() / pageDPI; + fz_scale(&matrix, sf, sf); + fz_pre_rotate(&matrix, degrees); - fz_page *PAGE = fz_load_page(CTX, DOC, pagenum); - fz_bound_page(CTX, PAGE, &bbox); + pdf_page *PAGE = pdf_load_page(CTX, (pdf_document*)DOC, pagenum); + pdf_bound_page(CTX, PAGE, &bbox); emit OrigSize(QSizeF(bbox.x1 - bbox.x0, bbox.y1 - bbox.y0)); fz_transform_rect(&bbox, &matrix); list = fz_new_display_list(CTX, &bbox); fz_device *dev = fz_new_list_device(CTX, list); - fz_run_page(CTX, PAGE, dev, &fz_identity, NULL); + pdf_run_page_contents(CTX, PAGE, dev, &fz_identity, NULL); - fz_link *link = fz_load_links(CTX, PAGE); - pdf_annot *_annot = pdf_first_annot(CTX, (pdf_page*)PAGE); + fz_link *link = pdf_load_links(CTX, PAGE); + pdf_annot *_annot = pdf_first_annot(CTX, PAGE); QList<Annot*> annotList; + QList<Widget*> widgetList; //qDebug() << "Starting annotations for:" << pagenum; while(_annot) { - pdf_run_annot(CTX, _annot, dev, &fz_identity, NULL); + //if(pdf_annot_is_dirty(CTX, _annot)) + //qDebug() << "DIRTY ANNOT"; + + int type = pdf_annot_type(CTX, _annot); + /**TYPES + 0 = TEXT + 1 = LINK + 2 = FREE_TEXT + 3 = LINE + 4 = SQUARE + ... + 24 = 3D + -1 = UNKNOWN + **/ + //qDebug() << "Page Number:" << pagenum+1 << type << pdf_string_from_annot_type(CTX, (enum pdf_annot_type)type); fz_rect anotBox; pdf_bound_annot(CTX, _annot, &anotBox); - QRectF rect(sf*anotBox.x0, sf*anotBox.y0, sf*(anotBox.x1-anotBox.x0), sf*(anotBox.y1 - anotBox.y0)); + QRectF rect = convertRect(anotBox, sf); + float opacity = pdf_annot_opacity(CTX, _annot); + /**TYPES + 0 = LEFT + 1 = CENTER + 2 = RIGHT + **/ + int quadding = pdf_annot_quadding(CTX, _annot); + + Annot *annot = new Annot(CTX, _annot, type, pagenum, opacity, rect); + + int flags = pdf_annot_flags(CTX, _annot); + /**FLAGS + 1 << 0 = INVISIBLE + 1 << 1 = HIDDEN + 1 << 2 = PRINT + 1 << 3 = NO_ZOOM + 1 << 4 = NO_ROTATE + 1 << 5 = NO_VIEW + 1 << 6 = READ_ONLY + 1 << 7 = LOCKED + 1 << 8 = TOGGLE_NO_VIEW + 1 << 9 = LOCKED_CONTENTS + **/ + + annot->setPrint((flags & PDF_ANNOT_IS_PRINT) == PDF_ANNOT_IS_PRINT); + char *contents = NULL, *author = NULL; - fz_try(CTX) - contents = pdf_copy_annot_contents(CTX, _annot); - fz_catch(CTX) { } - fz_try(CTX) - author = pdf_copy_annot_author(CTX, _annot); - fz_catch(CTX) { } + if(type != 19 and type != 20) { + fz_try(CTX){ + contents = pdf_copy_annot_contents(CTX, _annot); + if(contents) + annot->setContents(QString::fromLocal8Bit(contents)); + }fz_catch(CTX) { } + fz_try(CTX){ + author = pdf_copy_annot_author(CTX, _annot); + if(author) + annot->setAuthor(QString::fromLocal8Bit(author)); + }fz_catch(CTX) { } + } + //pdf_annot_modification_date(CTX, _annot); + + if(pdf_annot_has_ink_list(CTX, _annot)) { + int inkCount = pdf_annot_ink_list_count(CTX, _annot); + QVector<QVector<QPointF>> inkList; + for(int i = 0; i < inkCount; i++) { + int strokeCount = pdf_annot_ink_list_stroke_count(CTX, _annot, i); + QVector<QPointF> inkPoints; + for(int k = 0; k < strokeCount; k++) { + fz_point strokeVertex = pdf_annot_ink_list_stroke_vertex(CTX, _annot, i, k); + QPointF vertexPoint(strokeVertex.x, strokeVertex.y); + inkPoints.append(sf*vertexPoint); + } + inkList.append(inkPoints); + annot->setInkList(inkList); + } + fz_rect annotRect; + pdf_annot_rect(CTX, _annot, &annotRect); + //qDebug() << "ANNOT RECT:" << convertRect(annotRect, sf); + //qDebug() << "INK LIST:" << inkList; + } + + float color[4] = {0, 0, 0, 1}; + int n; + fz_try(CTX) { + pdf_annot_color(CTX, _annot, &n, color); + QColor inkColor = QColor(color[0]*255, color[1]*255, color[2]*255, color[3]*255); + annot->setColor(inkColor); + //qDebug() << "COLOR:" << inkColor; + }fz_catch(CTX) { + //qDebug() << "NO COLOR"; + annot->setColor(QColor()); + } + + if(pdf_annot_has_interior_color(CTX, _annot)) { + fz_try(CTX) { + color[0] = 0; color[1] = 0; color[2] = 0; color[3] = 1; + pdf_annot_interior_color(CTX, _annot, &n, color); + QColor internalColor = QColor(color[0]*255, color[1]*255, color[2]*255, color[3]*255); + //qDebug() << "INTERNAL COLOR:" << internalColor; + annot->setInternalColor(internalColor); + }fz_catch(CTX) { + //qDebug() << "NO INTERNAL COLOR"; + annot->setInternalColor(QColor()); + } + } + + //qDebug() << "BORDER:" << pdf_annot_border(CTX, _annot); + + if(pdf_annot_has_quad_points(CTX, _annot)) { + //qDebug() << "HAS QUAD POINTS" << "Page Number:" << pagenum << type; + int pointCount = pdf_annot_quad_point_count(CTX, _annot); + QList<QPolygonF> quadList; + for(int i = 0; i < pointCount; i++) { + float qp[8]; + pdf_annot_quad_point(CTX, _annot, i, qp); + QPolygonF quad = QPolygonF(QVector<QPointF>() << QPointF(qp[0], qp[1]) << QPointF(qp[2], qp[3]) << QPointF(qp[4], qp[5]) << QPointF(qp[6], qp[7])); + quadList.append(quad); + } + annot->setQuadList(quadList); + } - Annot *annot = new Annot(CTX, _annot, contents, author, rect); + if(pdf_annot_has_line_ending_styles(CTX, _annot)) { + //qDebug() << "HAS LINE ENDING STYLES" << "Page Number:" << pagenum << type; + pdf_line_ending start, end; + /**LINE ENDING + 0 = NONE + 1 = SQUARE + 2 = CIRCLE + ... + 9 = SLASH + **/ + pdf_annot_line_ending_styles(CTX, _annot, &start, &end); + //qDebug() << "START:" << start << "END:" << end; + } + + if(pdf_annot_has_vertices(CTX, _annot)) { + //qDebug() << "HAS VERTICIES" << "Page Number:" << pagenum << type; + int vertexCount = pdf_annot_vertex_count(CTX, _annot); + QList<QPointF> vertexList; + for(int i = 0; i < vertexCount; i++) { + fz_point v = pdf_annot_vertex(CTX, _annot, i); + vertexList.append(sf*QPointF(v.x, v.y)); + } + //qDebug() << vertexList; + } + + if(pdf_annot_has_line(CTX, _annot)) { + fz_point a, b; + pdf_annot_line(CTX, _annot, &a, &b); + QPointF pa(a.x, a.y); + QPointF pb(b.x, b.y); + //qDebug() << pa << pb; + } + + if(pdf_annot_has_icon_name(CTX, _annot)) { + QString iconName = QString::fromLocal8Bit(pdf_annot_icon_name(CTX, _annot)); + //qDebug() << iconName; + } + + if(!pdf_annot_has_ink_list(CTX, _annot)) { + pdf_run_annot(CTX, _annot, dev, &fz_identity, NULL); + } + annotList.append(annot); - _annot = _annot->next; + _annot = pdf_next_annot(CTX, _annot); + } + + pdf_widget *widget = pdf_first_widget(CTX, (pdf_document*)DOC, PAGE); + while(widget) { + int type = pdf_widget_type(CTX, widget); + /** + -1 = NOT_WIDGET + 0 = PUSHBUTTON + 1 = CHECKBOX + 2 = RADIOBUTTON + 3 = TEXT + 4 = LISTBOX + 5 = COMBOBOX + 6 = SIGNATURE + **/ + + fz_rect wrect; + pdf_bound_widget(CTX, widget, &wrect); + QRectF WRECT = convertRect(wrect, sf); + char *currText = pdf_text_widget_text(CTX, (pdf_document*)DOC, widget); + int maxLen = pdf_text_widget_max_len(CTX, (pdf_document*)DOC, widget); + int contentType = pdf_text_widget_content_type(CTX, (pdf_document*)DOC, widget); + /** + 0 = UNRESTRAINED + 1 = NUMBER + 2 = SPECIAL + 3 = DATE + 4 = TIME + **/ + + Widget *WIDGET = new Widget(type, WRECT, QString::fromLocal8Bit(currText), maxLen, contentType); + if(type == 4 or type == 5) { + QStringList optionList, exportList; + bool multi = pdf_choice_widget_is_multiselect(CTX, (pdf_document*)DOC, widget); + + if(int listS = pdf_choice_widget_options(CTX, (pdf_document*)DOC, widget, 0, NULL)) { + char *opts[listS]; + pdf_choice_widget_options(CTX, (pdf_document*)DOC, widget, 0, opts); + for(int i = 0; i < listS; i++) { optionList.append(QString::fromLocal8Bit(opts[i])); } + WIDGET->setOptions(optionList); + } + + if(int exportS = pdf_choice_widget_options(CTX, (pdf_document*)DOC, widget, 1, NULL)) { + char *opts[exportS]; + pdf_choice_widget_options(CTX, (pdf_document*)DOC, widget, 1, opts); + for(int i = 0; i < exportS; i++) { exportList.append(QString::fromLocal8Bit(opts[i])); } + WIDGET->setExports(exportList); + } + } + + widgetList.push_back(WIDGET); + + widget = pdf_next_widget(CTX, widget); } fz_close_device(CTX, dev); fz_drop_device(CTX, dev); - fz_drop_page(CTX, PAGE); + //fz_drop_page(CTX, PAGE); - data = new Data(pagenum, CTX, list, bbox, matrix, sf, link, annotList); + data = new Data(pagenum, CTX, list, bbox, matrix, sf, link, annotList, widgetList); data->setRenderThread(QtConcurrent::run(&renderer, data, this)); } @@ -368,26 +590,20 @@ int Renderer::linkSize(int pagenum) { return dataHash[pagenum]->getLinkList().size(); } -QList<QString> Renderer::annotList(int pagenum, int entry) { - return QList<QString>() << dataHash[pagenum]->getAnnotList()[entry]->getAuthor() << dataHash[pagenum]->getAnnotList()[entry]->getText(); +Annotation *Renderer::annotList(int pagenum, int entry) { + return static_cast<Annotation*>(dataHash[pagenum]->getAnnotList(entry)); } -QRectF Renderer::annotLoc(int pagenum, int entry) { - return dataHash[pagenum]->getAnnotList()[entry]->getLoc(); +int Renderer::annotSize(int pagenum) { + return dataHash[pagenum]->getAnnotSize(); } -int Renderer::annotSize(int pagenum) { - return dataHash[pagenum]->getAnnotList().size(); +Widget *Renderer::widgetList(int pagenum, int entry) { + return dataHash[pagenum]->getWidgetList(entry); } -bool Renderer::isExternalLink(int pagenum, QString text) { - QList<Link*> linkList = dataHash[pagenum]->getLinkList(); - foreach(Link *link, linkList) { - if(link->getData()->text() == text) - return fz_is_external_link(CTX, link->getData()->text().toLocal8Bit().data()); - } - return false; +int Renderer::widgetSize(int pagenum) { + return dataHash[pagenum]->getWidgetSize(); } bool Renderer::supportsExtraFeatures() { return true; } - |