libjxl

FORK: libjxl patches used on blog
git clone https://git.neptards.moe/blog/libjxl.git
Log | Files | Refs | Submodules | README | LICENSE

split_image_renderer.cc (7780B)


      1 // Copyright (c) the JPEG XL Project Authors. All rights reserved.
      2 //
      3 // Use of this source code is governed by a BSD-style
      4 // license that can be found in the LICENSE file.
      5 
      6 #include "tools/comparison_viewer/split_image_renderer.h"
      7 
      8 #include <QEvent>
      9 #include <QGuiApplication>
     10 #include <QPainter>
     11 #include <QPalette>
     12 #include <QPen>
     13 #include <QPoint>
     14 #include <QRect>
     15 #include <algorithm>
     16 #include <cmath>
     17 #include <utility>
     18 
     19 namespace jpegxl {
     20 namespace tools {
     21 
     22 SplitImageRenderer::SplitImageRenderer(QWidget* const parent)
     23     : QWidget(parent) {
     24   setAttribute(Qt::WA_OpaquePaintEvent);
     25   setMouseTracking(true);
     26   setFocusPolicy(Qt::WheelFocus);
     27   grabKeyboard();
     28 
     29   connect(&fadingPoint_, &QVariantAnimation::valueChanged,
     30           [this] { update(); });
     31 }
     32 
     33 void SplitImageRenderer::setLeftImage(QImage image) {
     34   leftImage_ = QPixmap::fromImage(std::move(image));
     35   leftImage_.setDevicePixelRatio(devicePixelRatio());
     36   updateMinimumSize();
     37   update();
     38 }
     39 void SplitImageRenderer::setRightImage(QImage image) {
     40   rightImage_ = QPixmap::fromImage(std::move(image));
     41   rightImage_.setDevicePixelRatio(devicePixelRatio());
     42   updateMinimumSize();
     43   update();
     44 }
     45 void SplitImageRenderer::setMiddleImage(QImage image) {
     46   middleImage_ = QPixmap::fromImage(std::move(image));
     47   middleImage_.setDevicePixelRatio(devicePixelRatio());
     48   updateMinimumSize();
     49   update();
     50 }
     51 
     52 void SplitImageRenderer::setRenderingSettings(
     53     const SplitImageRenderingSettings& settings) {
     54   renderingSettings_ = settings;
     55 }
     56 
     57 void SplitImageRenderer::setMiddleWidthPercent(const int percent) {
     58   middleWidthPercent_ = percent;
     59   update();
     60 }
     61 
     62 void SplitImageRenderer::setZoomLevel(double scale) {
     63   scale_ = scale;
     64   updateMinimumSize();
     65   update();
     66 }
     67 
     68 void SplitImageRenderer::keyPressEvent(QKeyEvent* const event) {
     69   switch (event->key()) {
     70     case Qt::Key_Left:
     71       setRenderingMode(RenderingMode::LEFT);
     72       break;
     73 
     74     case Qt::Key_Right:
     75       setRenderingMode(RenderingMode::RIGHT);
     76       break;
     77 
     78     case Qt::Key_Up:
     79     case Qt::Key_Down:
     80       setRenderingMode(RenderingMode::MIDDLE);
     81       break;
     82 
     83     case Qt::Key_Escape:
     84       QCoreApplication::quit();
     85       break;
     86 
     87     case Qt::Key_ZoomIn:
     88       emit zoomLevelIncreaseRequested();
     89       break;
     90     case Qt::Key_ZoomOut:
     91       emit zoomLevelDecreaseRequested();
     92       break;
     93 
     94     default:
     95       QWidget::keyPressEvent(event);
     96       break;
     97   }
     98   update();
     99 }
    100 
    101 void SplitImageRenderer::mouseMoveEvent(QMouseEvent* const event) {
    102   setRenderingMode(RenderingMode::SPLIT);
    103   middleX_ = event->pos().x();
    104   update();
    105 }
    106 
    107 void SplitImageRenderer::wheelEvent(QWheelEvent* event) {
    108   if (QGuiApplication::keyboardModifiers().testFlag(Qt::ControlModifier)) {
    109     if (event->angleDelta().y() > 0) {
    110       emit zoomLevelIncreaseRequested();
    111       return;
    112     } else if (event->angleDelta().y() < 0) {
    113       emit zoomLevelDecreaseRequested();
    114       return;
    115     }
    116   }
    117 
    118   event->ignore();
    119 }
    120 
    121 void SplitImageRenderer::paintEvent(QPaintEvent* const event) {
    122   QRectF drawingArea(0., 0., minimumWidth(), minimumHeight());
    123 
    124   QPainter painter(this);
    125   painter.fillRect(rect(), QColor(119, 119, 119));
    126   painter.translate(QRectF(rect()).center() - drawingArea.center());
    127   painter.scale(scale_, scale_);
    128   if (scale_ < 1.) {
    129     painter.setRenderHint(QPainter::SmoothPixmapTransform);
    130   }
    131 
    132   const auto drawSingleImage = [&](const RenderingMode mode) {
    133     const QPixmap* image = nullptr;
    134     switch (mode) {
    135       case RenderingMode::LEFT:
    136         image = &leftImage_;
    137         break;
    138       case RenderingMode::RIGHT:
    139         image = &rightImage_;
    140         break;
    141       case RenderingMode::MIDDLE:
    142         image = &middleImage_;
    143         break;
    144 
    145       default:
    146         return;
    147     }
    148     painter.drawPixmap(QPointF(0., 0.), *image);
    149   };
    150 
    151   if (mode_ != RenderingMode::SPLIT) {
    152     if (fadingPoint_.state() != QAbstractAnimation::Running) {
    153       drawSingleImage(mode_);
    154       return;
    155     }
    156 
    157     const float fadingPoint = fadingPoint_.currentValue().toFloat();
    158     if (renderingSettings_.gray) {
    159       if (fadingPoint < renderingSettings_.fadingMSecs) {
    160         painter.setOpacity((renderingSettings_.fadingMSecs - fadingPoint) /
    161                            renderingSettings_.fadingMSecs);
    162         drawSingleImage(previousMode_);
    163       } else if (fadingPoint > renderingSettings_.fadingMSecs +
    164                                    renderingSettings_.grayMSecs) {
    165         painter.setOpacity((fadingPoint - renderingSettings_.fadingMSecs -
    166                             renderingSettings_.grayMSecs) /
    167                            renderingSettings_.fadingMSecs);
    168         drawSingleImage(mode_);
    169       }
    170     } else {
    171       drawSingleImage(previousMode_);
    172       painter.setOpacity(fadingPoint / renderingSettings_.fadingMSecs);
    173       drawSingleImage(mode_);
    174     }
    175 
    176     return;
    177   }
    178 
    179   const qreal middleWidth =
    180       std::min<qreal>((minimumWidth() / scale_) * middleWidthPercent_ / 100.,
    181                       middleImage_.width());
    182 
    183   const double transformedMiddleX =
    184       painter.transform().inverted().map(QPointF(middleX_, 0.)).x();
    185   QRectF middleRect = middleImage_.rect();
    186   middleRect.setWidth(middleWidth);
    187   middleRect.moveCenter(QPointF(transformedMiddleX * devicePixelRatio(),
    188                                 middleRect.center().y()));
    189   middleRect.setLeft(std::round(middleRect.left()));
    190   middleRect.setRight(std::round(middleRect.right()));
    191 
    192   QRectF leftRect = leftImage_.rect();
    193   leftRect.setRight(middleRect.left());
    194 
    195   QRectF rightRect = rightImage_.rect();
    196   rightRect.setLeft(middleRect.right());
    197 
    198   painter.drawPixmap(QPointF(), leftImage_, leftRect);
    199   painter.drawPixmap(middleRect.topLeft() / devicePixelRatio(), middleImage_,
    200                      middleRect);
    201   painter.drawPixmap(rightRect.topLeft() / devicePixelRatio(), rightImage_,
    202                      rightRect);
    203 
    204   QPen middlePen;
    205   middlePen.setStyle(Qt::DotLine);
    206   painter.setPen(middlePen);
    207   painter.drawLine(leftRect.topRight() / devicePixelRatio(),
    208                    leftRect.bottomRight() / devicePixelRatio());
    209   painter.drawLine(rightRect.topLeft() / devicePixelRatio(),
    210                    rightRect.bottomLeft() / devicePixelRatio());
    211 }
    212 
    213 void SplitImageRenderer::updateMinimumSize() {
    214   const QSizeF leftSize = leftImage_.deviceIndependentSize();
    215   const QSizeF rightSize = rightImage_.deviceIndependentSize();
    216   const QSizeF middleSize = middleImage_.deviceIndependentSize();
    217   const qreal imagesWidth = std::max(
    218       std::max(leftSize.width(), rightSize.width()), middleSize.width());
    219   const qreal imagesHeight = std::max(
    220       std::max(leftSize.height(), rightSize.height()), middleSize.height());
    221   setMinimumSize((scale_ * QSizeF(imagesWidth, imagesHeight)).toSize());
    222 }
    223 
    224 void SplitImageRenderer::setRenderingMode(const RenderingMode newMode) {
    225   if (newMode == mode_) return;
    226   previousMode_ = mode_;
    227   mode_ = newMode;
    228   if (previousMode_ == RenderingMode::SPLIT || mode_ == RenderingMode::SPLIT) {
    229     fadingPoint_.stop();
    230   } else {
    231     const int msecs =
    232         renderingSettings_.gray
    233             ? 2 * renderingSettings_.fadingMSecs + renderingSettings_.grayMSecs
    234             : renderingSettings_.fadingMSecs;
    235     const float startValue = fadingPoint_.state() == QAbstractAnimation::Running
    236                                  ? fadingPoint_.endValue().toFloat() -
    237                                        fadingPoint_.currentValue().toFloat()
    238                                  : 0.f;
    239     fadingPoint_.stop();
    240     fadingPoint_.setStartValue(startValue);
    241     fadingPoint_.setEndValue(static_cast<float>(msecs));
    242     fadingPoint_.setDuration(fadingPoint_.endValue().toFloat() -
    243                              fadingPoint_.startValue().toFloat());
    244     fadingPoint_.start();
    245   }
    246   emit renderingModeChanged(mode_);
    247 }
    248 
    249 }  // namespace tools
    250 }  // namespace jpegxl