// really generate the cache void ImageView::generateCache() { // disable the one-shot timer cacheTimer_->deleteLater(); cacheTimer_ = nullptr; if(!imageItem_ || image_.isNull()) return; // generate a cache for "the visible part" of the scaled image // rectangle of the whole image in viewport coordinate QRect viewportImageRect = sceneToViewport(imageItem_->rect()); // rect of the image area that's visible in the viewport (in viewport coordinate) cachedRect_ = viewportImageRect.intersected(viewport()->rect()); // convert to the coordinate of the original image cachedSceneRect_ = viewportToScene(cachedRect_); // create a sub image of the visible without real data copy // Reference: http://stackoverflow.com/questions/12681554/dividing-qimage-to-smaller-pieces QRect subRect = image_.rect().intersected(cachedSceneRect_); const uchar* bits = image_.constBits(); unsigned int offset = subRect.x() * image_.depth() / 8 + subRect.y() * image_.bytesPerLine(); QImage subImage = QImage(bits + offset, subRect.width(), subRect.height(), image_.bytesPerLine(), image_.format()); // If the original image has a color table, also use it for the subImage QVector<QRgb> colorTable = image_.colorTable(); if (!colorTable.empty()) subImage.setColorTable(colorTable); // QImage scaled = subImage.scaled(subRect.width() * scaleFactor_, subRect.height() * scaleFactor_, Qt::KeepAspectRatio, Qt::SmoothTransformation); QImage scaled = subImage.scaled(cachedRect_.width(), cachedRect_.height(), Qt::KeepAspectRatio, Qt::SmoothTransformation); // convert the cached scaled image to pixmap cachedPixmap_ = QPixmap::fromImage(scaled); viewport()->update(); }
void ImageView::paintEvent(QPaintEvent* event) { // if the image is scaled and we have a high quality cached image if(imageItem_ && scaleFactor_ != 1.0 && !cachedPixmap_.isNull()) { // rectangle of the whole image in viewport coordinate QRect viewportImageRect = sceneToViewport(imageItem_->rect()); // the visible part of the image. QRect desiredCachedRect = viewportToScene(viewportImageRect.intersected(viewport()->rect())); // check if the cached area is what we need and if the cache is out of date if(cachedSceneRect_ == desiredCachedRect) { // rect of the image area that needs repaint, in viewport coordinate QRect repaintImageRect = viewportImageRect.intersected(event->rect()); // see if the part asking for repaint is contained by our cache. if(cachedRect_.contains(repaintImageRect)) { QPainter painter(viewport()); painter.fillRect(event->rect(), backgroundBrush()); painter.drawPixmap(repaintImageRect, cachedPixmap_); return; } } } if(!image_.isNull()) { // we don't have a cache yet or it's out of date already, generate one queueGenerateCache(); } QGraphicsView::paintEvent(event); }
void ImageView::generateCache() { delete m_cacheTimer; m_cacheTimer = 0; if (!m_item) return; m_cachedRect = sceneToViewport(m_item->rect()).intersected(viewport()->rect()); m_cachedSceneRect = viewportToScene(m_cachedRect); const QRect subRect = m_image.rect().intersected(m_cachedSceneRect); # if QT_VERSION >= 0x040700 const uchar* bits = m_image.constBits(); # else const uchar* bits = m_image.bits(); # endif const unsigned int offset = subRect.x() * m_image.depth() / 8 + subRect.y() * m_image.bytesPerLine(); const QImage subImage = QImage(bits + offset, subRect.width(), subRect.height(), m_image.bytesPerLine(), m_image.format()); ScaleRunnable *runnable = new ScaleRunnable(subImage.copy(), m_cachedRect.size()); connect(runnable, SIGNAL(finished(QImage)), SLOT(onFinished(QImage))); QThreadPool::globalInstance()->start(runnable); }
Rect2 Graphic::Renderer::sceneToViewport(Rect2 const& rect) const { if (_scene == NULL) throw new Graphic::Exception("Tried to transform coords but no scene was specified"); Vec2 viewport = getViewportSize(); Vec2 scene = _scene->getViewport(); Vec2 newPos = sceneToViewport(rect.pos); Vec2 newSize = rect.size / scene * viewport; newPos.y -= newSize.y; Rect2 newRect(newPos, Vec2(newSize)); return newRect; }
void ImageView::paintEvent(QPaintEvent* event) { if (m_item && m_scaleFactor != 1.0 && !m_cachedPixmap.isNull()) { const QRect viewportImageRect = sceneToViewport(m_item->rect()); const QRect desiredCachedRect = viewportToScene(viewportImageRect.intersected(viewport()->rect())); if (m_cachedSceneRect == desiredCachedRect) { const QRect repaintImageRect = viewportImageRect.intersected(event->rect()); if (m_cachedRect.contains(repaintImageRect)) { QPainter painter(viewport()); painter.fillRect(event->rect(), backgroundBrush()); painter.drawPixmap(repaintImageRect, m_cachedPixmap); return; } } } if (!m_image.isNull()) queueGenerateCache(); QGraphicsView::paintEvent(event); }