| 1 | /**************************************************************************** |
| 2 | ** |
| 3 | ** Copyright (C) 2016 The Qt Company Ltd. |
| 4 | ** Contact: https://www.qt.io/licensing/ |
| 5 | ** |
| 6 | ** This file is part of the examples of the Qt Toolkit. |
| 7 | ** |
| 8 | ** $QT_BEGIN_LICENSE:BSD$ |
| 9 | ** Commercial License Usage |
| 10 | ** Licensees holding valid commercial Qt licenses may use this file in |
| 11 | ** accordance with the commercial license agreement provided with the |
| 12 | ** Software or, alternatively, in accordance with the terms contained in |
| 13 | ** a written agreement between you and The Qt Company. For licensing terms |
| 14 | ** and conditions see https://www.qt.io/terms-conditions. For further |
| 15 | ** information use the contact form at https://www.qt.io/contact-us. |
| 16 | ** |
| 17 | ** BSD License Usage |
| 18 | ** Alternatively, you may use this file under the terms of the BSD license |
| 19 | ** as follows: |
| 20 | ** |
| 21 | ** "Redistribution and use in source and binary forms, with or without |
| 22 | ** modification, are permitted provided that the following conditions are |
| 23 | ** met: |
| 24 | ** * Redistributions of source code must retain the above copyright |
| 25 | ** notice, this list of conditions and the following disclaimer. |
| 26 | ** * Redistributions in binary form must reproduce the above copyright |
| 27 | ** notice, this list of conditions and the following disclaimer in |
| 28 | ** the documentation and/or other materials provided with the |
| 29 | ** distribution. |
| 30 | ** * Neither the name of The Qt Company Ltd nor the names of its |
| 31 | ** contributors may be used to endorse or promote products derived |
| 32 | ** from this software without specific prior written permission. |
| 33 | ** |
| 34 | ** |
| 35 | ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| 36 | ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| 37 | ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
| 38 | ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
| 39 | ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| 40 | ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| 41 | ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| 42 | ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| 43 | ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| 44 | ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| 45 | ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." |
| 46 | ** |
| 47 | ** $QT_END_LICENSE$ |
| 48 | ** |
| 49 | ****************************************************************************/ |
| 50 | #include "imagescaling.h" |
| 51 | |
| 52 | #include <qmath.h> |
| 53 | |
| 54 | #include <functional> |
| 55 | |
| 56 | Images::Images(QWidget *parent) |
| 57 | : QWidget(parent) |
| 58 | { |
| 59 | setWindowTitle(tr("Image loading and scaling example" )); |
| 60 | resize(800, 600); |
| 61 | |
| 62 | imageScaling = new QFutureWatcher<QImage>(this); |
| 63 | connect(imageScaling, &QFutureWatcher<QImage>::resultReadyAt, this, &Images::showImage); |
| 64 | connect(imageScaling, &QFutureWatcher<QImage>::finished, this, &Images::finished); |
| 65 | |
| 66 | openButton = new QPushButton(tr("Open Images" )); |
| 67 | connect(openButton, &QPushButton::clicked, this, &Images::open); |
| 68 | |
| 69 | cancelButton = new QPushButton(tr("Cancel" )); |
| 70 | cancelButton->setEnabled(false); |
| 71 | connect(cancelButton, &QPushButton::clicked, imageScaling, &QFutureWatcher<QImage>::cancel); |
| 72 | |
| 73 | pauseButton = new QPushButton(tr("Pause/Resume" )); |
| 74 | pauseButton->setEnabled(false); |
| 75 | connect(pauseButton, &QPushButton::clicked, imageScaling, &QFutureWatcher<QImage>::toggleSuspended); |
| 76 | |
| 77 | QHBoxLayout *buttonLayout = new QHBoxLayout(); |
| 78 | buttonLayout->addWidget(openButton); |
| 79 | buttonLayout->addWidget(cancelButton); |
| 80 | buttonLayout->addWidget(pauseButton); |
| 81 | buttonLayout->addStretch(); |
| 82 | |
| 83 | imagesLayout = new QGridLayout(); |
| 84 | |
| 85 | mainLayout = new QVBoxLayout(); |
| 86 | mainLayout->addLayout(buttonLayout); |
| 87 | mainLayout->addLayout(imagesLayout); |
| 88 | mainLayout->addStretch(); |
| 89 | setLayout(mainLayout); |
| 90 | } |
| 91 | |
| 92 | Images::~Images() |
| 93 | { |
| 94 | imageScaling->cancel(); |
| 95 | imageScaling->waitForFinished(); |
| 96 | } |
| 97 | |
| 98 | void Images::open() |
| 99 | { |
| 100 | // Cancel and wait if we are already loading images. |
| 101 | if (imageScaling->isRunning()) { |
| 102 | imageScaling->cancel(); |
| 103 | imageScaling->waitForFinished(); |
| 104 | } |
| 105 | |
| 106 | // Show a file open dialog at QStandardPaths::PicturesLocation. |
| 107 | QStringList files = QFileDialog::getOpenFileNames(this, tr("Select Images" ), |
| 108 | QStandardPaths::writableLocation(QStandardPaths::PicturesLocation), |
| 109 | "*.jpg *.png" ); |
| 110 | |
| 111 | if (files.isEmpty()) |
| 112 | return; |
| 113 | |
| 114 | const int imageSize = 100; |
| 115 | |
| 116 | // Do a simple layout. |
| 117 | qDeleteAll(labels); |
| 118 | labels.clear(); |
| 119 | |
| 120 | int dim = qSqrt(qreal(files.count())) + 1; |
| 121 | for (int i = 0; i < dim; ++i) { |
| 122 | for (int j = 0; j < dim; ++j) { |
| 123 | QLabel *imageLabel = new QLabel; |
| 124 | imageLabel->setFixedSize(imageSize,imageSize); |
| 125 | imagesLayout->addWidget(imageLabel,i,j); |
| 126 | labels.append(imageLabel); |
| 127 | } |
| 128 | } |
| 129 | |
| 130 | std::function<QImage(const QString&)> scale = [&](const QString &imageFileName) { |
| 131 | QImage image(imageFileName); |
| 132 | return image.scaled(QSize(imageSize, imageSize), Qt::IgnoreAspectRatio, Qt::SmoothTransformation); |
| 133 | }; |
| 134 | |
| 135 | // Use mapped to run the thread safe scale function on the files. |
| 136 | imageScaling->setFuture(QtConcurrent::mapped(files, scale)); |
| 137 | |
| 138 | openButton->setEnabled(false); |
| 139 | cancelButton->setEnabled(true); |
| 140 | pauseButton->setEnabled(true); |
| 141 | } |
| 142 | |
| 143 | void Images::showImage(int num) |
| 144 | { |
| 145 | labels[num]->setPixmap(QPixmap::fromImage(imageScaling->resultAt(num))); |
| 146 | } |
| 147 | |
| 148 | void Images::finished() |
| 149 | { |
| 150 | openButton->setEnabled(true); |
| 151 | cancelButton->setEnabled(false); |
| 152 | pauseButton->setEnabled(false); |
| 153 | } |
| 154 | |