aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorZackaryWelch <welch.zackary@gmail.com>2018-03-11 21:18:53 -0400
committerZackaryWelch <welch.zackary@gmail.com>2018-03-11 21:18:53 -0400
commit4b126da97fe1a6180507b13c36591743b44d0d27 (patch)
tree3e496f67eab3ddcb5ffd2e8b11a06dbd0665c74c
parentMerge remote-tracking branch 'origin/master' (diff)
downloadlumina-4b126da97fe1a6180507b13c36591743b44d0d27.tar.gz
lumina-4b126da97fe1a6180507b13c36591743b44d0d27.tar.bz2
lumina-4b126da97fe1a6180507b13c36591743b44d0d27.zip
Added multithreading support for the MuPDF backend and fixed rendering errors
-rw-r--r--src-qt5/desktop-utils/lumina-pdf/PrintWidget.cpp16
-rw-r--r--src-qt5/desktop-utils/lumina-pdf/Renderer-mupdf.cpp133
-rw-r--r--src-qt5/desktop-utils/lumina-pdf/Renderer-poppler.cpp4
-rw-r--r--src-qt5/desktop-utils/lumina-pdf/Renderer.h4
-rw-r--r--src-qt5/desktop-utils/lumina-pdf/mainUI.cpp12
-rw-r--r--src-qt5/desktop-utils/lumina-pdf/mainUI.h1
6 files changed, 93 insertions, 77 deletions
diff --git a/src-qt5/desktop-utils/lumina-pdf/PrintWidget.cpp b/src-qt5/desktop-utils/lumina-pdf/PrintWidget.cpp
index bece454e..5c7fa1dd 100644
--- a/src-qt5/desktop-utils/lumina-pdf/PrintWidget.cpp
+++ b/src-qt5/desktop-utils/lumina-pdf/PrintWidget.cpp
@@ -185,23 +185,23 @@ void PrintWidget::layoutPages() {
void PrintWidget::populateScene()
{
for (int i = 0; i < pages.size(); i++){
- scene->removeItem(pages.at(i));
+ scene->removeItem(pages.at(i));
}
qDeleteAll(pages);
pages.clear();
//qDebug() << "populateScene";
if(pictures==0){ return; } //nothing to show yet
int numPages = pictures->count();
- //Replace from loadingHash resolution
- QSize paperSize = pictures->value(0).size();
- //qDebug() << "Image paperSize" << paperSize;
-
- //Changes the paper orientation if rotated by 90 or 270 degrees
- if(degrees == 90 or degrees == 270)
- paperSize.transpose();
for (int i = 0; i < numPages; i++) {
QImage pagePicture = pictures->value(i);
+
+ QSize paperSize = pictures->value(i).size();
+
+ //Changes the paper orientation if rotated by 90 or 270 degrees
+ if(degrees == 90 or degrees == 270)
+ paperSize.transpose();
+
if(degrees != 0) {
pagePicture = pagePicture.transformed(rotMatrix, Qt::SmoothTransformation);
//qDebug() << "Rotating by: " << degrees << " degrees";
diff --git a/src-qt5/desktop-utils/lumina-pdf/Renderer-mupdf.cpp b/src-qt5/desktop-utils/lumina-pdf/Renderer-mupdf.cpp
index 279888c6..799f6584 100644
--- a/src-qt5/desktop-utils/lumina-pdf/Renderer-mupdf.cpp
+++ b/src-qt5/desktop-utils/lumina-pdf/Renderer-mupdf.cpp
@@ -1,23 +1,43 @@
#include "Renderer.h"
-#include <mupdf/fitz.h>
-#include <mupdf/pdf.h>
-
#include <QDateTime>
+#include <mupdf/fitz.h>
+//#include <pthread.h>
fz_document *DOC;
-pdf_document *PDOC;
fz_context *CTX;
-inline QString getTextInfo(pdf_obj *info, QString str) {
- pdf_obj *obj = pdf_dict_gets(CTX, info, str.toLatin1().data());
- if(obj){ return pdf_to_utf8(CTX, obj); }
+inline QString getTextInfo(QString str) {
+ char infoBuff[1000];
+ int size = DOC->lookup_metadata(CTX, DOC, ("info:"+str).toLocal8Bit().data(), infoBuff, 1000);
+ if(size != -1){ return QString::fromLatin1(infoBuff); }
return "";
}
+/*void lock_mutex(void *user, int lock) {
+ pthread_mutex_t *mutex = (pthread_mutex_t *) user;
+ pthread_mutex_lock(&mutex[lock]);
+}
+
+void unlock_mutex(void *user, int lock) {
+ pthread_mutex_t *mutex = (pthread_mutex_t *) user;
+ pthread_mutex_unlock(&mutex[lock]);
+}*/
+
Renderer::Renderer(){
+ /*pthread_mutex_t mutex[FZ_LOCK_MAX];
+ fz_locks_context locks;
+ locks.user = mutex;
+ locks.lock = lock_mutex;
+ locks.unlock = unlock_mutex;
+
+ for (int i = 0; i < FZ_LOCK_MAX; i++)
+ pthread_mutex_init(&mutex[i], NULL);*/
+
+ mutex = new QMutex();
DOC = 0;
+ //CTX = fz_new_context(NULL, &locks, FZ_STORE_UNLIMITED);
CTX = fz_new_context(NULL, NULL, FZ_STORE_UNLIMITED);
- PDOC = 0;
+ qDebug() << "Context created";
needpass = false;
}
@@ -25,43 +45,45 @@ Renderer::~Renderer(){
}
-bool Renderer::loadMultiThread(){ return false; }
+//bool Renderer::loadMultiThread(){ return true; }
QJsonObject Renderer::properties(){
QJsonObject jobj;
- pdf_obj *info = pdf_dict_gets(CTX, pdf_trailer(CTX, PDOC), "Info");
- jobj.insert("title", getTextInfo(info, "Title") );
- jobj.insert("subject", getTextInfo(info, "Subject") );
- jobj.insert("author", getTextInfo(info, "Author") );
- jobj.insert("creator", getTextInfo(info, "Creator") );
- jobj.insert("producer", getTextInfo(info, "Producer") );
- jobj.insert("keywords", getTextInfo(info, "Keywords") );
- jobj.insert("dt_created", QDateTime::fromString( getTextInfo(info, "CreationDate").left(16), "'D:'yyyyMMddHHmmss").toString() );
- jobj.insert("dt_modified", QDateTime::fromString( getTextInfo(info, "ModDate").left(16), "'D:'yyyyMMddHHmmss").toString() );
+ jobj.insert("title", getTextInfo("Title") );
+ jobj.insert("subject", getTextInfo("Subject") );
+ jobj.insert("author", getTextInfo("Author") );
+ jobj.insert("creator", getTextInfo("Creator") );
+ jobj.insert("producer", getTextInfo("Producer") );
+ jobj.insert("keywords", getTextInfo("Keywords") );
+ jobj.insert("dt_created", QDateTime::fromString( getTextInfo("CreationDate").left(16), "'D:'yyyyMMddHHmmss").toString() );
+ jobj.insert("dt_modified", QDateTime::fromString( getTextInfo("ModDate").left(16), "'D:'yyyyMMddHHmmss").toString() );
return jobj;
}
bool Renderer::loadDocument(QString path, QString password){
- if(DOC==0){ fz_register_document_handlers(CTX); } //first time through
- else if(path!=docpath){
+ //first time through
+ if(DOC==0){
+ fz_register_document_handlers(CTX);
+ qDebug() << "Document handlers registered";
+ }else if(path!=docpath){
//fz_close_document(DOC);
//Clear out the old document first
delete DOC;
DOC=0;
- if(PDOC!=0){ delete PDOC; PDOC=0; }
needpass = false;
+ docpath = path;
}
+
if(DOC==0){
DOC = fz_open_document(CTX, path.toLocal8Bit().data());
+ docpath = path;
+ qDebug() << "File opened";
if(DOC==0){
qDebug() << "Could not open file:" << path;
return false;
}
needpass = (fz_needs_password(CTX, DOC) != 0);
}
- if(PDOC==0){
- PDOC = pdf_open_document(CTX, path.toLocal8Bit().data());
- }
if(needpass && password.isEmpty()){ return false; }
else if(needpass){
@@ -69,48 +91,47 @@ bool Renderer::loadDocument(QString path, QString password){
if(needpass){ return false; } //incorrect password
}
+ qDebug() << "Password Check cleared";
+
//Could read/access the PDF - go ahead and load the info now
pnum = -1;
doctitle.clear();
//qDebug() << "Opening File:" << path;
- pdf_obj *info = pdf_dict_gets(CTX, pdf_trailer(CTX, (pdf_document*)DOC), "Info");
- if(info) {
- if(pdf_obj *obj = pdf_dict_gets(CTX, info, (char *)"Title")){ doctitle = pdf_to_utf8(CTX, obj); }
- }
- if(doctitle.isEmpty()){ doctitle = path.section("/",-1); }
+ QString title = getTextInfo("Subject");
+ if(!title.isNull())
+ doctitle = title;
+ else
+ doctitle = path.section("/",-1);
pnum = fz_count_pages(CTX, DOC);
//Setup the Document
fz_page *PAGE = fz_load_page(CTX, DOC, 0);
- if(PAGE!=0){
- /*switch(PAGE->orientation()){
- case Poppler::Page::Landscape:
- WIDGET->setOrientation(QPageLayout::Landscape); break;
- default:
- WIDGET->setOrientation(QPageLayout::Portrait);
- }*/
- delete PAGE;
- return true; //could see the first page
- }
- return false;
+ qDebug() << "Page Loaded";
+ //Possibly check Page orientation";
+
+ return (PAGE);
}
+//Consider rendering through a display list
QImage Renderer::renderPage(int pagenum, QSize DPI){
- //MuPDF uses a scaling factor, not DPI
- fz_page *PAGE = fz_load_page(CTX, DOC, pagenum);
- QImage img;
- if(PAGE!=0){
- fz_matrix matrix;
- //double scaleFactorW = dpi.width()/72.0;
- //double scaleFactorH = dpi.height()/72.0;
- //fz_scale(&matrix, scaleFactorW, scaleFactorH);
- fz_scale(&matrix, 4.0, 4.0); //need to adjust this later according to DPI
- fz_pre_rotate(&matrix, 0.0);
- fz_pixmap *pixmap = fz_new_pixmap_from_page_number(CTX, DOC, pagenum, &matrix, fz_device_rgb(CTX), 0);
- //unsigned char *samples = fz_pixmap_samples(CTX, pixmap);
- img = QImage(pixmap->samples, pixmap->w, pixmap->h, QImage::Format_RGB888); //make the raw image a bit larger than the end result
- delete PAGE;
- }
- qDebug() << "Render Page:" << pagenum << img.size();
+ QImage img;
+ fz_matrix matrix;
+ fz_pixmap *pixmap = nullptr;
+
+ fz_scale(&matrix, DPI.width()/96.0, DPI.height()/96.0);
+
+ //fz_context *ctx = fz_clone_context(CTX);
+ mutex->lock();
+
+ fz_try(CTX) {
+ pixmap = fz_new_pixmap_from_page_number(CTX, DOC, pagenum, &matrix, fz_device_rgb(CTX), 0);
+ }fz_catch(CTX){
+ qDebug() << "Error when rendering page using MuPDF";
+ }
+
+ mutex->unlock();
+
+ img = QImage(pixmap->samples, pixmap->w, pixmap->h, pixmap->stride, QImage::Format_RGB888);
+ qDebug() << "Render Page:" << pagenum;
return img;
}
diff --git a/src-qt5/desktop-utils/lumina-pdf/Renderer-poppler.cpp b/src-qt5/desktop-utils/lumina-pdf/Renderer-poppler.cpp
index b2d7dd32..693faa64 100644
--- a/src-qt5/desktop-utils/lumina-pdf/Renderer-poppler.cpp
+++ b/src-qt5/desktop-utils/lumina-pdf/Renderer-poppler.cpp
@@ -13,7 +13,7 @@ Renderer::~Renderer(){
}
-bool Renderer::loadMultiThread(){ return true; }
+//bool Renderer::loadMultiThread(){ return true; }
QJsonObject Renderer::properties(){
return QJsonObject(); //TO-DO
@@ -27,11 +27,13 @@ bool Renderer::loadDocument(QString path, QString password){
DOC=0;
needpass = false;
pnum=0;
+ docpath = path;
}
//Load the Document (if needed);
if(DOC==0){
//qDebug() << "Loading Document";
DOC = Poppler::Document::load(path);
+ docpath = path;
}
if(DOC==0){
diff --git a/src-qt5/desktop-utils/lumina-pdf/Renderer.h b/src-qt5/desktop-utils/lumina-pdf/Renderer.h
index 09e9c425..c9e13c7f 100644
--- a/src-qt5/desktop-utils/lumina-pdf/Renderer.h
+++ b/src-qt5/desktop-utils/lumina-pdf/Renderer.h
@@ -11,6 +11,7 @@
#include <QImage>
#include <QDebug>
#include <QJsonObject>
+#include <QMutex>
#include "textData.h"
class Renderer{
@@ -19,10 +20,11 @@ private:
bool needpass;
QString docpath; //save the path for the currently-loaded document
QString doctitle;
+ QMutex *mutex;
public:
Renderer();
~Renderer();
- bool loadMultiThread();
+ //bool loadMultiThread();
//Information functions (usually needs to be loaded first)
int numPages(){ return pnum; }
diff --git a/src-qt5/desktop-utils/lumina-pdf/mainUI.cpp b/src-qt5/desktop-utils/lumina-pdf/mainUI.cpp
index 4daf8ec9..03050138 100644
--- a/src-qt5/desktop-utils/lumina-pdf/mainUI.cpp
+++ b/src-qt5/desktop-utils/lumina-pdf/mainUI.cpp
@@ -15,7 +15,6 @@
#include <QDebug>
#include <QApplication>
#include <QScreen>
-#include <QTimer>
#include <iostream>
#include <QtConcurrent>
@@ -382,10 +381,6 @@ void MainUI::startLoadingPages(){
// Using Qt to scale the image (adjust page value) smooths out the image quite a bit without a lot of performance loss (but cannot scale up without pixelization)
// The best approach seams to be to increase the DPI a bit, but match that with the same scaling on the page size (smoothing)
- //double scalefactor = 2.5;
- //fz_rect page_rect;
- //fz_bound_page(CTX, fz_load_page(CTX, DOC, 0), &page_rect);
- //pageSize = QSizeF((page_rect.x1 - page_rect.x0)/72.0, (page_rect.y1 - page_rect.y0)/72.0);
QSize DPI(300,300); //print-quality (some printers even go to 600 DPI nowdays)
/*qDebug() << "Screen Resolutions:";
@@ -393,14 +388,9 @@ void MainUI::startLoadingPages(){
for(int i=0; i<screens.length(); i++){
qDebug() << screens[i]->name() << screens[i]->logicalDotsPerInchX() << screens[i]->logicalDotsPerInchY();
}*/
- bool async = BACKEND->loadMultiThread();
for(int i=0; i<BACKEND->numPages(); i++){
//qDebug() << " - Kickoff page load:" << i;
- if(async){
- QtConcurrent::run(this, &MainUI::loadPage, i, this, DPI);
- }else{
- loadPage(i, this, DPI);
- }
+ QtConcurrent::run(this, &MainUI::loadPage, i, this, DPI);
}
//qDebug() << "Finish page loading kickoff";
}
diff --git a/src-qt5/desktop-utils/lumina-pdf/mainUI.h b/src-qt5/desktop-utils/lumina-pdf/mainUI.h
index 911456aa..74badbfd 100644
--- a/src-qt5/desktop-utils/lumina-pdf/mainUI.h
+++ b/src-qt5/desktop-utils/lumina-pdf/mainUI.h
@@ -18,6 +18,7 @@
#include <QWheelEvent>
#include <QApplication>
#include <QMenu>
+#include <QTimer>
#include "Renderer.h"
#include "PresentationLabel.h"
bgstack15