imageanalyzer.cpp Example File | Qt WebKit Examples 5.9

Qt 5.9 | Qt WebKit Examples | The Webkit Bridge Tutorial - Hybrid Client Application | imageanalyzer.cpp Example File

Qt 5.9.2 Reference Documentation

# imageanalyzer.cpp Example File

webkitwidgets/imageanalyzer/imageanalyzer.cpp

      /****************************************************************************
      **
      ** Copyright (C) 2015 The Qt Company Ltd.
      ** Contact: http://www.qt.io/licensing/
      **
      ** This file is part of the examples of the Qt Toolkit.
      **
      ** $QT_BEGIN_LICENSE:BSD$
      ** You may use this file under the terms of the BSD license as follows:
      **
      ** "Redistribution and use in source and binary forms, with or without
      ** modification, are permitted provided that the following conditions are
      ** met:
      **   * Redistributions of source code must retain the above copyright
      **     notice, this list of conditions and the following disclaimer.
      **   * Redistributions in binary form must reproduce the above copyright
      **     notice, this list of conditions and the following disclaimer in
      **     the documentation and/or other materials provided with the
      **     distribution.
      **   * Neither the name of The Qt Company Ltd nor the names of its
      **     contributors may be used to endorse or promote products derived
      **     from this software without specific prior written permission.
      **
      **
      ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
      ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
      ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
      ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
      ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
      ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
      ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
      ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
      ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
      ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
      ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
      **
      ** $QT_END_LICENSE$
      **
      ****************************************************************************/

      #include <QNetworkReply>
      #include <QNetworkRequest>
      #include <QNetworkAccessManager>
      #include <QNetworkDiskCache>
      #include <QtConcurrentMap>
      #include "imageanalyzer.h"

      /*!
       * This class operates as follows:
       * Parent calls the slot startAnalysis which shoves a list of QStrings into URLQueue and then calls fetchURLs.
       * FetchURLs sends out HTTP GETs for each image it can't get out of the cache.
       * As the responses come in, handleReply tries to create an image out of each and pushes those images into imageQueue.
       * On the last (detected by no outstandingFetches and URLQueue.isEmpty()) call to queueImage (from handleReply)
       * a thread is forked to process all the images. When it finishes, it emits a finished signal that is received
       * by our JavaScript code.
       */

      ImageAnalyzer::ImageAnalyzer(QNetworkDiskCache* netcache, QObject* parent)
          : QObject(parent), m_cache(netcache), m_outstandingFetches(0)
      {
          /*  ImageAnalyzer only wants to receive http responses
              for requests that it makes, so that's why it has its own
              QNetworkAccessManager. */
          m_network = new QNetworkAccessManager(this);
          m_watcher = new QFutureWatcher<QRgb>(this);
          /*  We want to share a cache with the web browser,
              in case it has some images we want: */
          m_network->setCache(m_cache);

          QObject::connect(m_network, SIGNAL(finished(QNetworkReply*)),
                           this, SLOT(handleReply(QNetworkReply*)));
          QObject::connect(m_watcher, SIGNAL(finished()),
                           this, SLOT(doneProcessing()));
          QObject::connect(m_watcher, SIGNAL(progressValueChanged(int)),
                           this, SLOT(progressStatus(int)));
      }
      ImageAnalyzer::~ImageAnalyzer()
      {
          delete(m_watcher);
      }

      QRgb ImageAnalyzer::lastResults()
      {
          int rTot = 0;
          int bTot = 0;
          int gTot = 0;
          int count = m_watcher->future().results().size();
          foreach(const QRgb & triplet, m_watcher->future().results())
          {
              rTot += qRed(triplet);
              bTot += qBlue(triplet);
              gTot += qGreen(triplet);
          }
          return qRgb(rTot/count, bTot/count, gTot/count);
      }

      float ImageAnalyzer::lastRed() { return qRed(lastResults())/2.55; }
      float ImageAnalyzer::lastGreen() { return qGreen(lastResults())/2.55; }
      float ImageAnalyzer::lastBlue() { return qBlue(lastResults())/2.55; }

      void ImageAnalyzer::progressStatus(int newstat)
      {
          emit updateProgress(newstat, m_watcher->progressMaximum());
      }

      bool ImageAnalyzer::isBusy()
      {
          return m_watcher->isRunning();
      }

      void ImageAnalyzer::startAnalysis(const QStringList & urls)
      {
          m_URLQueue = urls;
          fetchURLs();
      }

      /*!
       * Analyzes the entire queue - just starts all our http GETs.
       */
      void ImageAnalyzer::fetchURLs()
      {
          while (!m_URLQueue.isEmpty())
          {
              QString url = m_URLQueue.takeFirst();
              QUrl URL = QUrl(url);
              QIODevice * pData = m_cache->data(URL);
              // Is image already loaded in cache?
              if (pData == 0) {
                  // HTTP Get image over network.
                  m_outstandingFetches++;
                  QNetworkRequest request = QNetworkRequest(URL);
                  request.setRawHeader("User-Agent", "The Qt Company Ltd. - Custom Qt app");
                  m_network->get(request);
              } else {
                  // Get image from cache
                  QImage image;
                  image.load(pData, 0);
                  if (!image.isNull())
                      queueImage(image);
                  delete(pData);
              }
          }
      }
      /*
       * Slot to handle the incoming responses from our http GETs
       */
      void ImageAnalyzer::handleReply(QNetworkReply * pReply)
      {
          m_outstandingFetches--;
          if (pReply->error()) {
              qDebug() << "Error code" << pReply->error();
              qDebug() << "Http code" << pReply->attribute(QNetworkRequest::HttpStatusCodeAttribute);
              return;
          }
          QImage image;
          image.load(pReply, 0);
          pReply->deleteLater();
          if (image.isNull()) {
              qDebug() << "bad image";
              qDebug() << pReply->rawHeaderList();
              foreach(QByteArray element, pReply->rawHeaderList()) {
                  qDebug() << element << " = " << pReply->rawHeader(element);
              }
              return;
          }
          queueImage(image);
      }

      void ImageAnalyzer::doneProcessing()
      {
          m_imageQueue = QList<QImage>();
          emit finishedAnalysis();
      }
      void ImageAnalyzer::queueImage(QImage img)
      {
          if (!img.isNull())
              m_imageQueue << img;

          if (m_outstandingFetches == 0 && m_URLQueue.isEmpty()) {
              m_watcher->setFuture(QtConcurrent::mapped(m_imageQueue, averageRGB));
          }
      }

      QRgb averageRGB(const QImage &img)
      {
          int pixelCount = img.width() * img.height();
          int rAvg, gAvg, bAvg;

          // We waste some time here:
          for (int timeWaster=0; timeWaster < 100; timeWaster++) {
              quint64 rTot = 0;
              quint64 gTot = 0;
              quint64 bTot = 0;
              for (int i=0; i < img.width(); i++) {
                  for (int j=0; j < img.height(); j++) {
                      QRgb pixel = img.pixel(i,j);
                      rTot += qRed(pixel);
                      gTot += qGreen(pixel);
                      bTot += qBlue(pixel);
                  }
              }
              rAvg = (rTot)/(pixelCount);
              gAvg = (gTot)/(pixelCount);
              bAvg = (bTot)/(pixelCount);
          }
          return qRgb(rAvg, gAvg, bAvg);
      }