29 #include "ksane_viewer.moc"
32 #include <QGraphicsPixmapItem>
33 #include <QGraphicsScene>
34 #include <QGraphicsRectItem>
35 #include <QWheelEvent>
50 struct KSaneViewer::Private
52 QGraphicsScene *scene;
53 SelectionItem *selection;
56 QList<SelectionItem *> selectionList;
63 QAction *zoomInAction;
64 QAction *zoomOutAction;
65 QAction *zoomSelAction;
66 QAction *zoom2FitAction;
67 QAction *clrSelAction;
69 QGraphicsRectItem *hideLeft;
70 QGraphicsRectItem *hideRight;
71 QGraphicsRectItem *hideTop;
72 QGraphicsRectItem *hideBottom;
73 QGraphicsRectItem *hideArea;
80 setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
81 setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
82 setMouseTracking(
true);
85 d->scene =
new QGraphicsScene;
86 d->scene->setSceneRect(0, 0, img->width(), img->height());
90 d->selection->setZValue(10);
91 d->selection->setSaved(
false);
92 d->selection->setMaxRight(img->width());
93 d->selection->setMaxBottom(img->height());
94 d->selection->setRect(d->scene->sceneRect());
95 d->selection->setVisible(
false);
97 d->hideTop =
new QGraphicsRectItem;
98 d->hideBottom =
new QGraphicsRectItem;
99 d->hideRight =
new QGraphicsRectItem;
100 d->hideLeft =
new QGraphicsRectItem;
101 d->hideArea =
new QGraphicsRectItem;
103 d->hideTop->setOpacity(0.4);
104 d->hideBottom->setOpacity(0.4);
105 d->hideRight->setOpacity(0.4);
106 d->hideLeft->setOpacity(0.4);
107 d->hideArea->setOpacity(0.6);
109 d->hideTop->setPen(Qt::NoPen);
110 d->hideBottom->setPen(Qt::NoPen);
111 d->hideRight->setPen(Qt::NoPen);
112 d->hideLeft->setPen(Qt::NoPen);
113 d->hideArea->setPen(Qt::NoPen);
115 d->hideTop->setBrush(QBrush(Qt::black));
116 d->hideBottom->setBrush(QBrush(Qt::black));
117 d->hideRight->setBrush(QBrush(Qt::black));
118 d->hideLeft->setBrush(QBrush(Qt::black));
120 d->scene->addItem(d->selection);
121 d->scene->addItem(d->hideLeft);
122 d->scene->addItem(d->hideRight);
123 d->scene->addItem(d->hideTop);
124 d->scene->addItem(d->hideBottom);
125 d->scene->addItem(d->hideArea);
128 d->selectionList.clear();
131 d->zoomInAction =
new QAction(KIcon(
"zoom-in"), i18n(
"Zoom In"),
this);
132 connect(d->zoomInAction, SIGNAL(triggered()),
this, SLOT(
zoomIn()));
134 d->zoomOutAction =
new QAction(KIcon(
"zoom-out"), i18n(
"Zoom Out"),
this);
135 connect(d->zoomOutAction, SIGNAL(triggered()),
this, SLOT(
zoomOut()));
137 d->zoomSelAction =
new QAction(KIcon(
"zoom-fit-best"), i18n(
"Zoom to Selection"),
this);
138 connect(d->zoomSelAction, SIGNAL(triggered()),
this, SLOT(
zoomSel()));
140 d->zoom2FitAction =
new QAction(KIcon(
"document-preview"), i18n(
"Zoom to Fit"),
this);
141 connect(d->zoom2FitAction, SIGNAL(triggered()),
this, SLOT(
zoom2Fit()));
143 d->clrSelAction =
new QAction(KIcon(
"edit-clear"), i18n(
"Clear Selections"),
this);
144 connect(d->clrSelAction, SIGNAL(triggered()),
this, SLOT(
clearSelections()));
146 addAction(d->zoomInAction);
147 addAction(d->zoomOutAction);
148 addAction(d->zoomSelAction);
149 addAction(d->zoom2FitAction);
150 addAction(d->clrSelAction);
151 setContextMenuPolicy(Qt::ActionsContextMenu);
157 painter->fillRect(rect, QColor(0x70, 0x70, 0x70));
158 painter->drawImage(rect, *d->img, rect);
173 if (img == 0)
return;
179 setMatrix(QMatrix());
181 d->scene->setSceneRect(0, 0, img->width(), img->height());
182 d->selection->setMaxRight(img->width());
183 d->selection->setMaxBottom(img->height());
190 setCacheMode(QGraphicsView::CacheNone);
192 setCacheMode(QGraphicsView::CacheBackground);
199 d->selection->saveZoom(transform().m11());
200 for (
int i=0; i<d->selectionList.size(); ++i) {
201 d->selectionList[i]->saveZoom(transform().m11());
208 scale(1.0 / 1.5, 1.0 / 1.5);
209 d->selection->saveZoom(transform().m11());
210 for (
int i=0; i<d->selectionList.size(); ++i) {
211 d->selectionList[i]->saveZoom(transform().m11());
218 if (d->selection->isVisible()) {
219 fitInView(d->selection->boundingRect() , Qt::KeepAspectRatio);
220 d->selection->saveZoom(transform().m11());
221 for (
int i=0; i<d->selectionList.size(); ++i) {
222 d->selectionList[i]->saveZoom(transform().m11());
233 fitInView(d->img->rect(), Qt::KeepAspectRatio);
234 d->selection->saveZoom(transform().m11());
235 for (
int i=0; i<d->selectionList.size(); ++i) {
236 d->selectionList[i]->saveZoom(transform().m11());
243 if (!d->selection->isVisible())
return;
244 QRectF rect = d->selection->rect();
245 rect.setLeft(ratio * d->img->width());
246 d->selection->setRect(rect);
247 updateSelVisibility();
253 if (!d->selection->isVisible())
return;
254 QRectF rect = d->selection->rect();
255 rect.setTop(ratio * d->img->height());
256 d->selection->setRect(rect);
257 updateSelVisibility();
263 if (!d->selection->isVisible())
return;
264 QRectF rect = d->selection->rect();
265 rect.setRight(ratio * d->img->width());
266 d->selection->setRect(rect);
267 updateSelVisibility();
273 if (!d->selection->isVisible())
return;
274 QRectF rect = d->selection->rect();
275 rect.setBottom(ratio * d->img->height());
276 d->selection->setRect(rect);
277 updateSelVisibility();
284 rect.setCoords(tl_x * d->img->width(),
285 tl_y * d->img->height(),
286 br_x * d->img->width(),
287 br_y * d->img->height());
289 d->selection->setRect(rect);
290 updateSelVisibility();
299 rect.setCoords(0,0, tl_x * d->img->width(), d->img->height());
300 d->hideLeft->setRect(rect);
303 rect.setCoords(br_x * d->img->width(),
307 d->hideRight->setRect(rect);
310 rect.setCoords(tl_x * d->img->width(),
312 br_x * d->img->width(),
313 tl_y * d->img->height());
314 d->hideTop->setRect(rect);
317 rect.setCoords(tl_x * d->img->width(),
318 br_y * d->img->height(),
319 br_x * d->img->width(),
321 d->hideBottom->setRect(rect);
324 rect.setCoords(tl_x * d->img->width(), tl_y* d->img->height(),
325 br_x * d->img->width(), br_y* d->img->height());
327 d->hideArea->setRect(rect);
330 d->hideRight->show();
332 d->hideBottom->show();
340 if (percentage >= 100) {
345 d->hideArea->setBrush(hideColor);
347 qreal diff = d->hideBottom->rect().top() - d->hideTop->rect().bottom();
348 diff -= (diff * percentage) / 100;
350 QRectF rect = d->hideArea->rect();
351 rect.setTop(d->hideBottom->rect().top() - diff);
353 d->hideArea->setRect(rect);
359 void KSaneViewer::updateHighlight()
361 if (d->selection->isVisible()) {
364 rect.setCoords(0,0, d->selection->rect().left(), d->img->height());
365 d->hideLeft->setRect(rect);
368 rect.setCoords(d->selection->rect().right(),
372 d->hideRight->setRect(rect);
375 rect.setCoords(d->selection->rect().left(),
377 d->selection->rect().right(),
378 d->selection->rect().top());
379 d->hideTop->setRect(rect);
382 rect.setCoords(d->selection->rect().left(),
383 d->selection->rect().bottom(),
384 d->selection->rect().right(),
386 d->hideBottom->setRect(rect);
389 d->hideRight->show();
391 d->hideBottom->show();
396 d->hideRight->hide();
398 d->hideBottom->hide();
408 d->hideRight->hide();
410 d->hideBottom->hide();
415 void KSaneViewer::updateSelVisibility()
417 if ((d->selection->rect().width() >0.001) &&
418 (d->selection->rect().height() > 0.001) &&
419 ((d->img->width() - d->selection->rect().width() > 0.1) ||
420 (d->img->height() - d->selection->rect().height() > 0.1)))
422 d->selection->setVisible(
true);
425 d->selection->setVisible(
false);
432 if (d->selection->isVisible()) {
433 return (d->selectionList.size() + 1);
436 return d->selectionList.size();
443 if ((index < 0) || (index > d->selectionList.size())) {
444 activeSelection(tl_x, tl_y, br_x, br_y);
447 if (index == d->selectionList.size()) {
448 return activeSelection(tl_x, tl_y, br_x, br_y);
451 tl_x = d->selectionList[index]->rect().left() / d->img->width();
452 tl_y = d->selectionList[index]->rect().top() / d->img->height();
453 br_x = d->selectionList[index]->rect().right() / d->img->width();
454 br_y = d->selectionList[index]->rect().bottom() / d->img->height();
459 bool KSaneViewer::activeSelection(
float &tl_x,
float &tl_y,
float &br_x,
float &br_y)
461 if (!d->selection->isVisible()) {
469 tl_x = d->selection->rect().left() / d->img->width();
470 tl_y = d->selection->rect().top() / d->img->height();
471 br_x = d->selection->rect().right() / d->img->width();
472 br_y = d->selection->rect().bottom() / d->img->height();
474 if ((tl_x == br_x) || (tl_y == br_y)) {
487 d->selection->setRect(QRectF(0,0,0,0));
488 d->selection->intersects(QPointF(100,100));
489 d->selection->setVisible(
false);
497 while (!d->selectionList.isEmpty()) {
498 tmp = d->selectionList.takeFirst();
499 d->scene->removeItem(tmp);
514 if(e->modifiers() == Qt::ControlModifier) {
521 QGraphicsView::wheelEvent(e);
528 if (e->button() == Qt::LeftButton)
530 d->m_left_last_x = e->x();
531 d->m_left_last_y = e->y();
532 QPointF scenePoint = mapToScene(e->pos());
533 d->lastSPoint = scenePoint;
534 if (e->modifiers() != Qt::ControlModifier) {
535 if (!d->selection->isVisible()) {
536 d->selection->setVisible(
true);
537 d->selection->setRect(QRectF(scenePoint, QSizeF(0,0)));
538 d->selection->intersects(scenePoint);
542 d->selection->setRect(QRectF(scenePoint, QSizeF(0,0)));
548 QGraphicsView::mousePressEvent(e);
554 bool removed =
false;
555 if (e->button() == Qt::LeftButton) {
556 if ((d->selection->rect().width() < 0.001) ||
557 (d->selection->rect().height() < 0.001))
563 QPointF scenePoint = mapToScene(e->pos());
564 for (
int i=0; i<d->selectionList.size(); i++) {
566 d->scene->removeItem(d->selectionList[i]);
568 d->selectionList.removeAt(i);
569 d->selection->setVisible(
true);
570 d->selection->setRect(tmp->
rect());
571 d->selection->intersects(scenePoint);
580 d->selectionList.push_back(tmp);
581 d->selectionList.back()->setSaved(
true);
582 d->selectionList.back()->saveZoom(transform().m11());
583 d->scene->addItem(d->selectionList.back());
584 d->selectionList.back()->setZValue(9);
585 d->selectionList.back()->intersects(scenePoint);
593 if ((e->modifiers() != Qt::ControlModifier) &&
594 (d->selection->isVisible()) &&
595 (d->img->width() > 0.001) &&
596 (d->img->height() > 0.001))
598 float tlx = d->selection->rect().left() / d->img->width();
599 float tly = d->selection->rect().top() / d->img->height();
600 float brx = d->selection->rect().right() / d->img->width();
601 float bry = d->selection->rect().bottom() / d->img->height();
606 QGraphicsView::mouseReleaseEvent(e);
612 QPointF scenePoint = mapToScene(e->pos());
614 if (e->buttons()&Qt::LeftButton)
616 if (e->modifiers() == Qt::ControlModifier)
618 int dx = e->x() - d->m_left_last_x;
619 int dy = e->y() - d->m_left_last_y;
620 verticalScrollBar()->setValue(verticalScrollBar()->value()-dy);
621 horizontalScrollBar()->setValue(horizontalScrollBar()->value()-dx);
622 d->m_left_last_x = e->x();
623 d->m_left_last_y = e->y();
626 ensureVisible(QRectF(scenePoint, QSizeF(0,0)), 1, 1);
627 QRectF rect = d->selection->rect();
634 if (scenePoint.y() < rect.bottom()) rect.setTop(scenePoint.y());
637 rect.setBottom(scenePoint.y());
641 if (scenePoint.x() > rect.left()) rect.setRight(scenePoint.x());
643 rect.setLeft(scenePoint.x());
646 if (scenePoint.y() < rect.bottom()) rect.setTop(scenePoint.y());
648 rect.setBottom(scenePoint.y());
653 if (scenePoint.x() > rect.left()) rect.setRight(scenePoint.x());
655 rect.setLeft(scenePoint.x());
660 if (scenePoint.x() > rect.left()) rect.setRight(scenePoint.x());
662 rect.setLeft(scenePoint.x());
665 if (scenePoint.y() > rect.top()) rect.setBottom(scenePoint.y());
667 rect.setTop(scenePoint.y());
672 if (scenePoint.y() > rect.top()) rect.setBottom(scenePoint.y());
675 rect.setTop(scenePoint.y());
679 if (scenePoint.x() < rect.right()) rect.setLeft(scenePoint.x());
681 rect.setRight(scenePoint.x());
684 if (scenePoint.y() > rect.top()) rect.setBottom(scenePoint.y());
686 rect.setTop(scenePoint.y());
691 if (scenePoint.x() < rect.right()) rect.setLeft(scenePoint.x());
693 rect.setRight(scenePoint.x());
698 if (scenePoint.x() < rect.right()) rect.setLeft(scenePoint.x());
700 rect.setRight(scenePoint.x());
703 if (scenePoint.y() < rect.bottom()) rect.setTop(scenePoint.y());
705 rect.setBottom(scenePoint.y());
710 rect.translate(d->selection->fixTranslation(scenePoint-d->lastSPoint));
716 d->selection->setRect(rect);
719 else if (d->selection->isVisible()) {
720 d->change = d->selection->intersects(scenePoint);
725 viewport()->setCursor(Qt::CrossCursor);
728 viewport()->setCursor(Qt::SizeVerCursor);
731 viewport()->setCursor(Qt::SizeBDiagCursor);
734 viewport()->setCursor(Qt::SizeHorCursor);
737 viewport()->setCursor(Qt::SizeFDiagCursor);
740 viewport()->setCursor(Qt::SizeVerCursor);
743 viewport()->setCursor(Qt::SizeBDiagCursor);
746 viewport()->setCursor(Qt::SizeHorCursor);
749 viewport()->setCursor(Qt::SizeFDiagCursor);
752 viewport()->setCursor(Qt::SizeAllCursor);
755 viewport()->setCursor(Qt::ArrowCursor);
760 viewport()->setCursor(Qt::CrossCursor);
764 for (
int i=0; i<d->selectionList.size(); i++) {
766 viewport()->setCursor(Qt::ArrowCursor);
770 d->lastSPoint = scenePoint;
772 QGraphicsView::mouseMoveEvent(e);
800 float multiplier = sqrt(area/(d->img->height() * d->img->width()));
802 int width = (int)(d->img->width() * multiplier);
803 int height = (int)(d->img->height() * multiplier);
805 QImage img = d->img->scaled(width, height, Qt::KeepAspectRatio);
806 height = img.height();
809 QVector<qint64> colSums(width +
SEL_MARGIN + 1);
821 for (
int h=1; h<height; h++) {
825 pix = qGray(img.pixel(0, h));
826 diff = qAbs(pix - qGray(img.pixel(1, h)));
827 diff += qAbs(pix - qGray(img.pixel(0, h-1)));
828 diff += qAbs(pix - qGray(img.pixel(0, h+1)));
835 pix = qGray(img.pixel(width - 1, h));
836 diff = qAbs(pix - qGray(img.pixel(width - 2, h)));
837 diff += qAbs(pix - qGray(img.pixel(width - 1, h-1)));
838 diff += qAbs(pix - qGray(img.pixel(width - 1, h+1)));
840 colSums[width - 1] += diff;
844 for (
int w=1; w < (width - 1); w++) {
845 pix = qGray(img.pixel(w, h));
848 diff += qAbs(pix - qGray(img.pixel(w - 1, h)));
849 diff += qAbs(pix - qGray(img.pixel(w + 1, h)));
850 diff += qAbs(pix - qGray(img.pixel(w, h - 1)));
851 diff += qAbs(pix - qGray(img.pixel(w, h + 1)));
866 if (hSelStart >= 0) {
867 if (hSelMargin > 0) hSelMargin--;
869 if ((hSelStart > -1) && ((hSelMargin == 0) || (h==height-1))) {
871 hSelEnd = h - hSelMargin;
878 for (
int w=0; w <= width; w++) {
886 if (wSelStart >= 0) {
887 if (wSelMargin > 0) wSelMargin--;
889 if ((wSelStart >= 0) && ((wSelMargin == 0) || (w == width))) {
898 if ((wSelEnd-wSelStart) < width) {
901 int x1 = wSelStart / multiplier;
902 int y1 = hSelStart / multiplier;
903 int x2 = wSelEnd / multiplier;
904 int y2 = hSelEnd / multiplier;
905 float selArea = (float)(wSelEnd - wSelStart) * (float)(hSelEnd-hSelStart);
908 d->selectionList.push_back(tmp);
909 d->selectionList.back()->setSaved(
true);
910 d->selectionList.back()->saveZoom(transform().m11());
911 d->scene->addItem(d->selectionList.back());
912 d->selectionList.back()->setZValue(9);
938 refineSelections(qRound(1/multiplier));
940 float minArea = d->img->height() * d->img->width() *
MIN_AREA_SIZE;
943 while (i < d->selectionList.size()) {
944 if ((d->selectionList[i]->rect().width() * d->selectionList[i]->rect().height()) < minArea) {
945 d->scene->removeItem(d->selectionList[i]);
946 d->selectionList.removeAt(i);
957 return QSize(250, 300);
960 void KSaneViewer::refineSelections(
int pixelMargin)
968 for (
int i=0; i<d->selectionList.size(); i++) {
969 QRectF selRect = d->selectionList.at(i)->rect();
972 hSelStart = (int)selRect.top();
973 hSelEnd = (int)selRect.bottom();
974 wSelStart = (int)selRect.left();
975 wSelEnd = (int)selRect.right();
979 hSelStart = refineRow(hSelStart - pixelMargin, hSelEnd, wSelStart, wSelEnd);
982 hSelEnd = refineRow(hSelEnd + pixelMargin, hSelStart, wSelStart, wSelEnd);
985 wSelStart = refineColumn(wSelStart - pixelMargin, wSelEnd, hSelStart, hSelEnd);
988 wSelEnd = refineColumn(wSelEnd + pixelMargin, wSelStart, hSelStart, hSelEnd);
991 d->selectionList.at(i)->setRect(QRectF(QPointF(wSelStart, hSelStart), QPointF(wSelEnd, hSelEnd)));
995 int KSaneViewer::refineRow(
int fromRow,
int toRow,
int colStart,
int colEnd)
1001 int addSub = (fromRow < toRow) ? 1 : -1;
1006 if (colStart < 1) colStart = 1;
1007 if (colEnd >= d->img->width()-1) colEnd = d->img->width() - 2;
1009 if (fromRow < 1) fromRow = 1;
1010 if (fromRow >= d->img->height()-1) fromRow = d->img->height() - 2;
1012 if (toRow < 1) toRow = 1;
1013 if (toRow >= d->img->height()-1) toRow = d->img->height() - 2;
1016 while (row != toRow) {
1018 for (
int w=colStart; w<colEnd; w++) {
1020 pix = qGray(d->img->pixel(w, row));
1022 diff += qAbs(pix - qGray(d->img->pixel(w-1, row)));
1023 diff += qAbs(pix - qGray(d->img->pixel(w+1, row)));
1024 diff += qAbs(pix - qGray(d->img->pixel(w, row-1)));
1025 diff += qAbs(pix - qGray(d->img->pixel(w, row+1)));
1038 if (row == 1) row = 0;
1039 if (row == (d->img->width() -2)) row = d->img->width();
1047 int KSaneViewer::refineColumn(
int fromCol,
int toCol,
int rowStart,
int rowEnd)
1054 int addSub = (fromCol < toCol) ? 1 : -1;
1059 if (rowStart < 1) rowStart = 1;
1060 if (rowEnd >= d->img->height()-1) rowEnd = d->img->height() - 2;
1062 if (fromCol < 1) fromCol = 1;
1063 if (fromCol >= d->img->width()-1) fromCol = d->img->width() - 2;
1065 if (toCol < 1) toCol = 1;
1066 if (toCol >= d->img->width()-1) toCol = d->img->width() - 2;
1069 while (col != toCol) {
1072 for (
int row=rowStart; row<rowEnd; row++) {
1075 pix = qGray(d->img->pixel(col, row));
1077 diff += qAbs(pix - qGray(d->img->pixel(col-1, row)));
1078 diff += qAbs(pix - qGray(d->img->pixel(col+1, row)));
1079 diff += qAbs(pix - qGray(d->img->pixel(col, row-1)));
1080 diff += qAbs(pix - qGray(d->img->pixel(col, row+1)));
1093 if (col == 1) col = 0;
1094 if (col == (d->img->width() -2)) col = d->img->width();
static const int DIFF_TRIGGER
void mousePressEvent(QMouseEvent *e)
void setQImage(QImage *img)
static const int SUM_TRIGGER
void setHighlightArea(float tl_x, float tl_y, float br_x, float br_y)
This function is used to darken everything except what is inside the given area.
void setSelection(float tl_x, float tl_y, float br_x, float br_y)
This function is used to set a selection without the user setting it.
void mouseReleaseEvent(QMouseEvent *e)
void drawBackground(QPainter *painter, const QRectF &rect)
void setHighlightShown(int percentage, QColor hideColor=Qt::white)
This function sets the percentage of the highlighted area that is visible.
void findSelections(float area=10000.0)
Find selections in the picture.
static const int AVERAGE_MULT
static const int AVERAGE_COUNT
KSaneViewer(QImage *img, QWidget *parent=0)
virtual QSize sizeHint() const
static const int AVERAGE_TRIGGER
void mouseMoveEvent(QMouseEvent *e)
void clearSavedSelections()
static const int MAX_NUM_SELECTIONS
static const float MIN_AREA_SIZE
static const int SEL_MARGIN
bool selectionAt(int index, float &tl_x, float &tl_y, float &br_x, float &br_y)
void clearActiveSelection()
void newSelection(float tl_x, float tl_y, float br_x, float br_y)
void clearHighlight()
This function removes the highlight area.
void wheelEvent(QWheelEvent *e)