aboutsummaryrefslogtreecommitdiff
path: root/src-qt5/desktop-utils/lumina-pdf/Renderer-mupdf.cpp
blob: 279888c69d6304830f8dac8dd43b367606262c1b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
#include "Renderer.h"
#include <mupdf/fitz.h>
#include <mupdf/pdf.h>

#include <QDateTime>

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); }
  return "";
}

Renderer::Renderer(){
  DOC = 0;
  CTX = fz_new_context(NULL, NULL, FZ_STORE_UNLIMITED);
  PDOC = 0;
  needpass = false;
}

Renderer::~Renderer(){

}

bool Renderer::loadMultiThread(){ return false; }

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() );
  return jobj;
}

bool Renderer::loadDocument(QString path, QString password){
  if(DOC==0){ fz_register_document_handlers(CTX); } //first time through
  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;
  }
  if(DOC==0){
    DOC = fz_open_document(CTX, path.toLocal8Bit().data());
    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){
    needpass = !fz_authenticate_password(CTX, DOC, password.toLocal8Bit());
    if(needpass){ return false; } //incorrect password
  }

  //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); }
  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;
}

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();
  return img;
}

QList<TextData*> Renderer::searchDocument(QString text, bool matchCase){
  fz_rect rectBuffer[1000];
  QList<TextData*> results;
  for(int i = 0; i < pnum; i++) {
    int count = fz_search_page_number(CTX, DOC, i, text.toLatin1().data(), rectBuffer, 1000);
    //qDebug() << "Page " << i+1 << ": Count, " << count;
    for(int j = 0; j < count; j++) {
      QRect rect(rectBuffer[j].x0, rectBuffer[j].y0, rectBuffer[j].x1-rectBuffer[j].x0, rectBuffer[j].y1 - rectBuffer[j].y0);
      TextData *t = new TextData(rect, i+1, text);
      //MuPDF search does not match case, so retrieve the exact text at the location found and determine whether or not it matches the case of the search text if the user selected to match case
      if(matchCase){
        fz_stext_page *sPage = fz_new_stext_page_from_page_number(CTX, DOC, i, NULL);
        QString currentStr = QString(fz_copy_selection(CTX, sPage, *fz_rect_min(&rectBuffer[j]), *fz_rect_max(&rectBuffer[j]), false));
        if(currentStr.contains(text, Qt::CaseSensitive)){ results.append(t); }
      }else{
          results.append(t);
      }
    }
  }
  return results;
}
bgstack15