1 #include "worker.h"
2 #include "resourcemanager.h"
3 #include "kpage.h"
4 #include "canvas.h"
5 #include "selection.h"
6 #include "util.h"
7 #include "config.h"
8 #include <list>
9 #include <iostream>
10 #if QT_VERSION >= 0x050000
11 # include <poppler-qt5.h>
12 #else
13 # include <poppler-qt4.h>
14 #endif
15
16 using namespace std;
17
18
Worker(ResourceManager * res)19 Worker::Worker(ResourceManager *res) :
20 die(false),
21 res(res) {
22 // load config options
23 CFG *config = CFG::get_instance();
24 smooth_downscaling = config->get_value("Settings/thumbnail_filter").toBool();
25 thumbnail_size = config->get_value("Settings/thumbnail_size").toInt();
26 }
27
run()28 void Worker::run() {
29 while (1) {
30 res->requestSemaphore.acquire(1);
31 if (die) {
32 break;
33 }
34
35 // get next page to render
36 res->requestMutex.lock();
37 int page, width, index;
38 map<int,Request>::iterator less = res->requests.lower_bound(res->center_page);
39 map<int,Request>::iterator greater = less--;
40 map<int,Request>::iterator closest;
41
42 if (greater != res->requests.end()) {
43 if (greater != res->requests.begin()) {
44 // favour nearby page, go down first
45 if (greater->first + less->first <= res->center_page * 2) {
46 closest = greater;
47 } else {
48 closest = less;
49 }
50 } else {
51 closest = greater;
52 }
53 } else {
54 closest = less;
55 }
56
57 page = closest->first;
58 index = closest->second.get_lowest_index();
59 width = closest->second.width[index];
60 if (closest->second.remove_index_ok(index)) {
61 res->requestSemaphore.release(1);
62 } else {
63 res->requests.erase(closest);
64 }
65 res->requestMutex.unlock();
66
67 // check for duplicate requests
68 KPage &kp = res->k_page[page];
69
70 kp.mutex.lock();
71 bool render_new = true;
72 if (kp.status[index] == width && kp.rotation[index] == res->rotation) {
73 if (kp.img[index].isNull()) { // only invert colors
74 render_new = false;
75 } else { // nothing to do
76 kp.mutex.unlock();
77 continue;
78 }
79 }
80 int rotation = res->rotation;
81 kp.mutex.unlock();
82
83 // open page
84 #ifdef DEBUG
85 cerr << " rendering page " << page << " for index " << index << ", center: " << res->center_page << endl;
86 #endif
87 Poppler::Page *p = NULL;
88 if (render_new) {
89 p = res->doc->page(page);
90 if (p == NULL) {
91 cerr << "failed to load page " << page << endl;
92 continue;
93 }
94
95 // render page
96 float dpi = 72.0 * width / res->get_page_width(page);
97 QImage img = p->renderToImage(dpi, dpi, -1, -1, -1, -1,
98 static_cast<Poppler::Page::Rotation>(rotation));
99
100 if (img.isNull()) {
101 cerr << "failed to render page " << page << endl;
102 continue;
103 }
104
105 // insert new image
106 kp.mutex.lock();
107 if (kp.inverted_colors) {
108 kp.img[index] = QImage();
109 kp.img_other[index] = img;
110 } else {
111 kp.img[index] = img;
112 kp.img_other[index] = QImage();
113 }
114 kp.status[index] = width;
115 kp.rotation[index] = rotation;
116 } else {
117 // image already exists
118 kp.mutex.lock();
119 }
120
121 if (kp.inverted_colors) {
122 // generate inverted image
123 kp.img[index] = kp.img_other[index];
124 invert_image(&kp.img[index]);
125 }
126
127 // create thumbnail
128 if (kp.thumbnail.isNull()) {
129 Qt::TransformationMode mode = Qt::FastTransformation;
130 if (smooth_downscaling) {
131 mode = Qt::SmoothTransformation;
132 }
133 // scale
134 if (kp.inverted_colors) {
135 kp.thumbnail = kp.img_other[index].scaled(QSize(thumbnail_size, thumbnail_size), Qt::IgnoreAspectRatio, mode);
136 } else {
137 kp.thumbnail = kp.img[index].scaled(QSize(thumbnail_size, thumbnail_size), Qt::IgnoreAspectRatio, mode);
138 }
139 // rotate
140 if (kp.rotation[index] != 0) {
141 QTransform trans;
142 trans.rotate(-kp.rotation[index] * 90);
143 kp.thumbnail = kp.thumbnail.transformed(trans);
144 }
145 kp.thumbnail_other = kp.thumbnail;
146 invert_image(&kp.thumbnail_other);
147 if (kp.inverted_colors) {
148 kp.thumbnail.swap(kp.thumbnail_other);
149 }
150 }
151 kp.mutex.unlock();
152
153 res->garbageMutex.lock();
154 res->garbage[index].insert(page);
155 res->garbageMutex.unlock();
156
157 emit page_rendered(page);
158
159 // collect goto links
160 res->link_mutex.lock();
161 if (kp.links == NULL) {
162 res->link_mutex.unlock();
163
164 QList<Poppler::Link *> *links = new QList<Poppler::Link *>;
165 QList<Poppler::Link *> l = p->links();
166 links->swap(l);
167
168 res->link_mutex.lock();
169 kp.links = links;
170 }
171 if (kp.text == NULL) {
172 res->link_mutex.unlock();
173
174 QList<Poppler::TextBox *> text = p->textList();
175 // assign boxes to lines
176 // make single parts from chained boxes
177 set<Poppler::TextBox *> used;
178 QList<SelectionPart *> selection_parts;
179 Q_FOREACH(Poppler::TextBox *box, text) {
180 if (used.find(box) != used.end()) {
181 continue;
182 }
183 used.insert(box);
184
185 SelectionPart *p = new SelectionPart(box);
186 selection_parts.push_back(p);
187 Poppler::TextBox *next = box->nextWord();
188 while (next != NULL) {
189 used.insert(next);
190 p->add_word(next);
191 next = next->nextWord();
192 }
193 }
194
195 // sort by y coordinate
196 stable_sort(selection_parts.begin(), selection_parts.end(), selection_less_y);
197
198 QRectF line_box;
199 QList<SelectionLine *> *lines = new QList<SelectionLine *>();
200 Q_FOREACH(SelectionPart *part, selection_parts) {
201 QRectF box = part->get_bbox();
202 // box fits into line_box's line
203 if (!lines->empty() && box.y() <= line_box.center().y() && box.bottom() > line_box.center().y()) {
204 float ratio_w = box.width() / line_box.width();
205 float ratio_h = box.height() / line_box.height();
206 if (ratio_w < 1.0f) {
207 ratio_w = 1.0f / ratio_w;
208 }
209 if (ratio_h < 1.0f) {
210 ratio_h = 1.0f / ratio_h;
211 }
212 if (ratio_w > 1.3f && ratio_h > 1.3f) {
213 lines->back()->sort();
214 lines->push_back(new SelectionLine(part));
215 line_box = part->get_bbox();
216 } else {
217 lines->back()->add_part(part);
218 }
219 // it doesn't fit, create new line
220 } else {
221 if (!lines->empty()) {
222 lines->back()->sort();
223 }
224 lines->push_back(new SelectionLine(part));
225 line_box = part->get_bbox();
226 }
227 }
228 if (!lines->empty()) {
229 lines->back()->sort();
230 }
231
232 res->link_mutex.lock();
233 kp.text = lines;
234 }
235 res->link_mutex.unlock();
236
237 delete p;
238 }
239 }
240
241