diff --git a/doc/katarakt.txt b/doc/katarakt.txt index 90fd63fe9160f074eb20c67fcfa47830edef9abe..c3d1f1dc3d881d08f2f01edb731ce169244eef24 100644 --- a/doc/katarakt.txt +++ b/doc/katarakt.txt @@ -150,8 +150,8 @@ VARIABLES 'string' *background_color_fullscreen* :: 0xFF000000: Fullscreen background color in ARGB Format. 'string' *unrendered_page_color* :: - 0x80808080: Color that gets drawn instead of a page that hasn't been - rendered yet. + 0x40FFFFFF: Color that gets drawn instead of a page that hasn't been + rendered yet. If colors are inverted, this gets inverted as well. 'int' *click_link_button* :: 1: The mouse button used for clicking links. Buttons 1-5 are supported. 'int' *drag_view_button* :: @@ -212,6 +212,12 @@ GotoLine { 'int' *prefetch_count* :: 4: Number of pages exceeding the currently visible ones to render, back- and forwards respectively. +'float' *inverted_color_contrast* :: + 0.5: the contrast when using inverted colors to avoid too much + brightness. +'float' *inverted_color_brightening* :: + 0.15: amount of brightening when using inverted colors to shift black to + gray. 'int' *mouse_wheel_factor* :: 120: QT delta for turning the mouse wheel 1 click. Shouldn't need to be touched. diff --git a/share/katarakt.ini b/share/katarakt.ini index 2c33eeb01a551ce6f8a71ea24b721e255207bd68..087e1fe55c73b40f1834048f1cdfecf123c97072 100644 --- a/share/katarakt.ini +++ b/share/katarakt.ini @@ -22,6 +22,8 @@ stylesheet= page_overlay_text=Page %1/%2 icon_theme= prefetch_count=4 +inverted_color_contrast=0.5 +inverted_color_brightening=0.15 mouse_wheel_factor=120 thumbnail_filter=true thumbnail_size=32 diff --git a/src/config.cpp b/src/config.cpp index 98d01b9ba8bd1c2e36877f701287fcc43a9ab5f9..eb348b8bd1eca6c538c5e8608ae3f8503e834397 100644 --- a/src/config.cpp +++ b/src/config.cpp @@ -45,6 +45,8 @@ void CFG::init_defaults() { vd.push_back("Settings/icon_theme"); defaults[vd.back()] = ""; // internal vd.push_back("Settings/prefetch_count"); defaults[vd.back()] = 4; + vd.push_back("Settings/inverted_color_contrast"); defaults[vd.back()] = 0.5; + vd.push_back("Settings/inverted_color_brightening"); defaults[vd.back()] = 0.15; vd.push_back("Settings/mouse_wheel_factor"); defaults[vd.back()] = 120; // (qt-)delta for turning the mouse wheel 1 click vd.push_back("Settings/thumbnail_filter"); defaults[vd.back()] = true; // filter when creating thumbnail image vd.push_back("Settings/thumbnail_size"); defaults[vd.back()] = 32; diff --git a/src/kpage.cpp b/src/kpage.cpp index e1e39dfddb2b505eb63d37f1276e6e61e7afddcc..e3667a931372397e1ef65cfa01308b6cdb2bb364 100644 --- a/src/kpage.cpp +++ b/src/kpage.cpp @@ -44,11 +44,23 @@ const QImage *KPage::get_image(int index) const { } int KPage::get_width(int index) const { - return status[index]; + // status might contain the information for img_other, but no inverted version is available yet + if (img[index].isNull()) { + return 0; + } else { + return status[index]; + } } char KPage::get_rotation(int index) const { - return rotation[index]; + // return rotation of next available image, try the right index first + for (int i = 3; i > 0; i--) { + if (!img[(index + i) % 3].isNull()) { + return rotation[(index + i) % 3]; + } + } + // no image available? use thumbnail (always 0) + return 0; } const QList<SelectionLine *> *KPage::get_text() const { @@ -59,4 +71,11 @@ const QList<SelectionLine *> *KPage::get_text() const { // return label; //} +void KPage::toggle_invert_colors() { + for (int i = 0; i < 3; i++) { + img[i].swap(img_other[i]); + } + thumbnail.swap(thumbnail_other); + inverted_colors = !inverted_colors; +} diff --git a/src/kpage.h b/src/kpage.h index 63e07b45dd3c8e47036b961f485241360a46ff38..8bce4ba1bf2ba3578ce8fc2007c547d437b7eeba 100644 --- a/src/kpage.h +++ b/src/kpage.h @@ -22,10 +22,18 @@ public: // QString get_label() const; private: + void toggle_invert_colors(); + float width; float height; QImage img[3]; QImage thumbnail; + // for inverted colors with reduced contrast + // img_other contain the currently not needed color versions + // img store the current versions to be displayed + QImage img_other[3]; + QImage thumbnail_other; + // QString label; QList<Poppler::Link *> *links; QMutex mutex; diff --git a/src/resourcemanager.cpp b/src/resourcemanager.cpp index bf4009a89463e9daa10b20dd7c9d7c4ce2d13b35..44fcf18d71746eae3750160acbee8f4303eeac29 100644 --- a/src/resourcemanager.cpp +++ b/src/resourcemanager.cpp @@ -9,7 +9,6 @@ #endif #include "resourcemanager.h" #include "canvas.h" -#include "config.h" #include "util.h" #include "kpage.h" #include "worker.h" @@ -32,11 +31,6 @@ ResourceManager::ResourceManager(const QString &file, Viewer *v) : #endif inverted_colors(false), cur_jump_pos(jumplist.end()) { - // load config options - CFG *config = CFG::get_instance(); - smooth_downscaling = config->get_value("Settings/thumbnail_filter").toBool(); - thumbnail_size = config->get_value("Settings/thumbnail_size").toInt(); - initialize(file, QByteArray()); } @@ -181,20 +175,20 @@ const KPage *ResourceManager::get_page(int page, int width, int index) { return NULL; } - // page not available or wrong size/rotation + // page not available or wrong size/rotation/color k_page[page].mutex.lock(); + bool must_invert_colors = k_page[page].inverted_colors != inverted_colors; + if (must_invert_colors) { + k_page[page].toggle_invert_colors(); + } + if (k_page[page].img[index].isNull() || k_page[page].status[index] != width || - k_page[page].rotation[index] != rotation) { + k_page[page].rotation[index] != rotation || + must_invert_colors) { enqueue(page, width, index); } - if (inverted_colors != k_page[page].inverted_colors) { - k_page[page].inverted_colors = inverted_colors; - for (int i = 0; i < 3; i++) { - k_page[page].img[i].invertPixels(); - } - k_page[page].thumbnail.invertPixels(); - } + return &k_page[page]; } @@ -240,33 +234,9 @@ void ResourceManager::collect_garbage(int keep_min, int keep_max) { cerr << " removing page " << page << endl; #endif k_page[page].mutex.lock(); - // create thumbnail - if (k_page[page].thumbnail.isNull()) { - Qt::TransformationMode mode = Qt::FastTransformation; - if (smooth_downscaling) { - mode = Qt::SmoothTransformation; - } - // find the index of the rendered image - for (int i = 0; i < 3; i++) { - if (!k_page[page].img[i].isNull()) { -// k_page[page].inverted_colors = inverted_colors; - // scale - k_page[page].thumbnail = k_page[page].img[i].scaled( - QSize(thumbnail_size, thumbnail_size), - Qt::IgnoreAspectRatio, mode); - // rotate - if (k_page[page].rotation[i] != 0) { - QTransform trans; - trans.rotate(-k_page[page].rotation[i] * 90); - k_page[page].thumbnail = k_page[page].thumbnail.transformed( - trans); - } - break; - } - } - } for (int i = 0; i < 3; i++) { k_page[page].img[i] = QImage(); + k_page[page].img_other[i] = QImage(); k_page[page].status[i] = 0; k_page[page].rotation[i] = 0; } diff --git a/src/resourcemanager.h b/src/resourcemanager.h index 0379f28ee51cbb41a37faec70daf053b2ab25347..985ad7c505cdbd01524b524ffea28227712551e8 100644 --- a/src/resourcemanager.h +++ b/src/resourcemanager.h @@ -107,9 +107,6 @@ private: QSocketNotifier *i_notifier; #endif - // config options - bool smooth_downscaling; - int thumbnail_size; bool inverted_colors; std::list<int> jumplist; diff --git a/src/util.cpp b/src/util.cpp index f8e3d10227e00dd49440a26e27cff6728a29a6b2..d1dd49f3a9af1a627ec735e45cd19ab126aef011 100644 --- a/src/util.cpp +++ b/src/util.cpp @@ -1,9 +1,15 @@ #include <QAction> #include <QObject> +#include <QImage> +//#include <QTime> +//#include <iostream> #include "util.h" #include "config.h" +using namespace std; + + const QRectF rotate_rect(const QRectF &rect, float w, float h, int rotation) { if (rotation == 0) { return rect; @@ -53,3 +59,28 @@ void add_action(QWidget *base, const char *action, const char *slot, QWidget *re } } +void invert_image(QImage *img) { + static QRgb invert_mask = qRgba(255, 255, 255, 0); + static float inverted_contrast = + CFG::get_instance()->get_value("Settings/inverted_color_contrast").toFloat(); + static int offset = 255 * + CFG::get_instance()->get_value("Settings/inverted_color_brightening").toFloat(); +// QTime time; +// time.start(); + +// img->invertPixels(); + + QRgb *pixels = reinterpret_cast<QRgb *>(img->bits()); + QRgb *pixels_end = pixels + img->width() * img->height(); + + while (pixels < pixels_end) { + *pixels ^= invert_mask; + *pixels = qRgb( + (qRed(*pixels)) * inverted_contrast + offset, + (qGreen(*pixels)) * inverted_contrast + offset, + (qBlue(*pixels)) * inverted_contrast + offset); + ++pixels; + } +// cout << time.elapsed() << "ms elapsed" << endl; +} + diff --git a/src/util.h b/src/util.h index 4eebfcc4c9e37902997fe1f4fe95e225ae09e45b..b762549a0eadf73a1111793df01313221995d588 100644 --- a/src/util.h +++ b/src/util.h @@ -4,6 +4,10 @@ #include <QRect> #include <QRectF> + +class QImage; + + #define POPPLER_VERSION ((POPPLER_VERSION_MAJOR << 16) | (POPPLER_VERSION_MINOR << 8) | (POPPLER_VERSION_MICRO)) #define POPPLER_VERSION_CHECK(major,minor,micro) ((major << 16) | (minor << 8) | (micro)) @@ -21,5 +25,7 @@ QRect transform_rect_expand(const QRectF &rect, float scale, int off_x, int off_ void add_action(QWidget *base, const char *action, const char *slot, QWidget *receiver); +void invert_image(QImage *img); + #endif diff --git a/src/worker.cpp b/src/worker.cpp index 897ea2f8100ea021bc2d9aa697e4d8a0084f3335..6abb7c2f9e0003dba8ae0726004c176e809ab99e 100644 --- a/src/worker.cpp +++ b/src/worker.cpp @@ -3,6 +3,8 @@ #include "kpage.h" #include "canvas.h" #include "selection.h" +#include "util.h" +#include "config.h" #include <list> #include <iostream> #include <poppler/qt4/poppler-qt4.h> @@ -13,6 +15,10 @@ using namespace std; Worker::Worker(ResourceManager *res) : die(false), res(res) { + // load config options + CFG *config = CFG::get_instance(); + smooth_downscaling = config->get_value("Settings/thumbnail_filter").toBool(); + thumbnail_size = config->get_value("Settings/thumbnail_size").toInt(); } void Worker::run() { @@ -57,58 +63,90 @@ void Worker::run() { res->requestMutex.unlock(); // check for duplicate requests - res->k_page[page].mutex.lock(); - if (res->k_page[page].status[index] == width && - res->k_page[page].rotation[index] == res->rotation) { - res->k_page[page].mutex.unlock(); - continue; + KPage &kp = res->k_page[page]; + + kp.mutex.lock(); + bool render_new = true; + if (kp.status[index] == width && kp.rotation[index] == res->rotation) { + if (kp.img[index].isNull()) { // only invert colors + render_new = false; + } else { // nothing to do + kp.mutex.unlock(); + continue; + } } int rotation = res->rotation; - res->k_page[page].mutex.unlock(); + kp.mutex.unlock(); // open page #ifdef DEBUG cerr << " rendering page " << page << " for index " << index << endl; #endif - Poppler::Page *p = res->doc->page(page); - if (p == NULL) { - cerr << "failed to load page " << page << endl; - continue; - } + Poppler::Page *p = NULL; + if (render_new) { + p = res->doc->page(page); + if (p == NULL) { + cerr << "failed to load page " << page << endl; + continue; + } - // render page - float dpi = 72.0 * width / res->get_page_width(page); - QImage img = p->renderToImage(dpi, dpi, -1, -1, -1, -1, - static_cast<Poppler::Page::Rotation>(rotation)); + // render page + float dpi = 72.0 * width / res->get_page_width(page); + QImage img = p->renderToImage(dpi, dpi, -1, -1, -1, -1, + static_cast<Poppler::Page::Rotation>(rotation)); - if (img.isNull()) { - cerr << "failed to render page " << page << endl; - continue; - } + if (img.isNull()) { + cerr << "failed to render page " << page << endl; + continue; + } - // invert to current color setting - if (res->inverted_colors) { - img.invertPixels(); + // insert new image + kp.mutex.lock(); + if (kp.inverted_colors) { + kp.img[index] = QImage(); + kp.img_other[index] = img; + } else { + kp.img[index] = img; + kp.img_other[index] = QImage(); + } + kp.status[index] = width; + kp.rotation[index] = rotation; + } else { + // image already exists + kp.mutex.lock(); } - // put page - res->k_page[page].mutex.lock(); - if (!res->k_page[page].img[index].isNull()) { - res->k_page[page].img[index] = QImage(); // assign null image + if (kp.inverted_colors) { + // generate inverted image + kp.img[index] = kp.img_other[index]; + invert_image(&kp.img[index]); } - // adjust all available images to current color setting - if (res->k_page[page].inverted_colors != res->inverted_colors) { - res->k_page[page].inverted_colors = res->inverted_colors; - for (int i = 0; i < 3; i++) { - res->k_page[page].img[i].invertPixels(); + // create thumbnail + if (kp.thumbnail.isNull()) { + Qt::TransformationMode mode = Qt::FastTransformation; + if (smooth_downscaling) { + mode = Qt::SmoothTransformation; + } + // scale + if (kp.inverted_colors) { + kp.thumbnail = kp.img_other[index].scaled(QSize(thumbnail_size, thumbnail_size), Qt::IgnoreAspectRatio, mode); + } else { + kp.thumbnail = kp.img[index].scaled(QSize(thumbnail_size, thumbnail_size), Qt::IgnoreAspectRatio, mode); + } + // rotate + if (kp.rotation[index] != 0) { + QTransform trans; + trans.rotate(-kp.rotation[index] * 90); + kp.thumbnail = kp.thumbnail.transformed(trans); + } + kp.thumbnail_other = kp.thumbnail; + invert_image(&kp.thumbnail_other); + if (kp.inverted_colors) { + kp.thumbnail.swap(kp.thumbnail_other); } - res->k_page[page].thumbnail.invertPixels(); } - res->k_page[page].img[index] = img; - res->k_page[page].status[index] = width; - res->k_page[page].rotation[index] = rotation; - res->k_page[page].mutex.unlock(); + kp.mutex.unlock(); res->garbageMutex.lock(); res->garbage.insert(page); // TODO add index information? @@ -118,7 +156,7 @@ void Worker::run() { // collect goto links res->link_mutex.lock(); - if (res->k_page[page].links == NULL) { + if (kp.links == NULL) { res->link_mutex.unlock(); QList<Poppler::Link *> *links = new QList<Poppler::Link *>; @@ -126,9 +164,9 @@ void Worker::run() { links->swap(l); res->link_mutex.lock(); - res->k_page[page].links = links; + kp.links = links; } - if (res->k_page[page].text == NULL) { + if (kp.text == NULL) { res->link_mutex.unlock(); QList<Poppler::TextBox *> text = p->textList(); @@ -190,7 +228,7 @@ void Worker::run() { } res->link_mutex.lock(); - res->k_page[page].text = lines; + kp.text = lines; } res->link_mutex.unlock(); @@ -198,4 +236,3 @@ void Worker::run() { } } - diff --git a/src/worker.h b/src/worker.h index 36d8cac6c7b13bdf46272e325190c2a13e0b46aa..ef51db05ac583126e6fdea334514f0b1a9dab1ad 100644 --- a/src/worker.h +++ b/src/worker.h @@ -22,6 +22,10 @@ signals: private: ResourceManager *res; + + // config options + bool smooth_downscaling; + int thumbnail_size; }; #endif