diff --git a/kstars/fitsviewer/fitsview.h b/kstars/fitsviewer/fitsview.h --- a/kstars/fitsviewer/fitsview.h +++ b/kstars/fitsviewer/fitsview.h @@ -270,8 +270,8 @@ void calculateMaxPixel(double min, double max); void initDisplayImage(); - QPointF getPointForGridLabel(); - bool pointIsInImage(QPointF pt, bool scaled); + QPointF getPointForGridLabel(QPainter *painter, const QString& str); + bool pointIsInImage(QPointF pt); void loadInFrame(); @@ -285,10 +285,14 @@ FITSData *imageData { nullptr }; /// Current zoom level double currentZoom { 0 }; + // The maximum percent zoom. The value is recalculated in the constructor + // based on the amount of physical memory. + int zoomMax { 400 }; private: bool processData(); void doStretch(FITSData *data, QImage *outputImage); + double scaleSize(double size); QLabel *noImageLabel { nullptr }; QPixmap noImage; @@ -299,17 +303,13 @@ /// Current width due to zoom uint16_t currentWidth { 0 }; - uint16_t lastWidth { 0 }; /// Current height due to zoom uint16_t currentHeight { 0 }; - uint16_t lastHeight { 0 }; /// Image zoom factor const double zoomFactor; // Original full-size image QImage rawImage; - // Scaled images - QImage scaledImage; // Actual pixmap after all the overlays QPixmap displayPixmap; diff --git a/kstars/fitsviewer/fitsview.cpp b/kstars/fitsviewer/fitsview.cpp --- a/kstars/fitsviewer/fitsview.cpp +++ b/kstars/fitsviewer/fitsview.cpp @@ -35,12 +35,16 @@ #include #include +#include + #define BASE_OFFSET 50 #define ZOOM_DEFAULT 100.0f #define ZOOM_MIN 10 -#define ZOOM_MAX 400 +// ZOOM_MAX is adjusted in the constructor if the amount of physical memory is known. +#define ZOOM_MAX 300 #define ZOOM_LOW_INCR 10 #define ZOOM_HIGH_INCR 50 +#define FONT_SIZE 14 namespace { @@ -147,6 +151,31 @@ // by adjusting the stretchBar's sliders. autoStretch = true; + // Adjust the maximum zoom according to the amount of memory. + // There have been issues with users running out system memory because of zoom memory. + // Note: this is not currently image dependent. It's possible, but not implemented, + // to allow for more zooming on smaller images. + const long numPages = sysconf(_SC_PAGESIZE); + const long pageSize = sysconf(_SC_PHYS_PAGES); + zoomMax = ZOOM_MAX; + // _SC_PHYS_PAGES "may not be standard" http://man7.org/linux/man-pages/man3/sysconf.3.html + // If an OS doesn't support it, sysconf should return -1. + if (numPages > 0 && pageSize > 0) + { + // (numPages * pageSize) will likely overflow a 32bit int, so use floating point calculations. + const int memoryMb = numPages * (static_cast(pageSize) / 1e6); + if (memoryMb < 2000) + zoomMax = 100; + else if (memoryMb < 4000) + zoomMax = 200; + else if (memoryMb < 8000) + zoomMax = 300; + else if (memoryMb < 16000) + zoomMax = 400; + else + zoomMax = 600; + } + grabGesture(Qt::PinchGesture); image_frame.reset(new FITSLabel(this)); @@ -384,7 +413,6 @@ QTimer::singleShot(100, this, SLOT(viewStarProfile())); } - scaledImage = QImage(); updateFrame(); return true; } @@ -552,7 +580,6 @@ initDisplayImage(); image_frame->setScaledContents(true); doStretch(imageData, &rawImage); - scaledImage = QImage(); setWidget(image_frame.get()); // This is needed by fitstab, even if the zoom doesn't change, to change the stretch UI. @@ -575,9 +602,9 @@ currentZoom += ZOOM_HIGH_INCR; emit actionUpdated("view_zoom_out", true); - if (currentZoom >= ZOOM_MAX) + if (currentZoom >= zoomMax) { - currentZoom = ZOOM_MAX; + currentZoom = zoomMax; emit actionUpdated("view_zoom_in", false); } @@ -629,6 +656,13 @@ starFilter.outerRadius = outerRadius; } +// scaleSize() may increase the line widths or font sizes, as we draw lines and render text on the +// full image and when zoomed out, these sizes may be too small. +double FITSView::scaleSize(double size) +{ + return currentZoom > 100.0 ? size : std::round(size * 100.0 / currentZoom); +} + int FITSView::filterStars() { return starFilter.used() ? imageData->filterStars(starFilter.innerRadius, starFilter.outerRadius) : imageData->getStarCenters().count(); @@ -641,35 +675,28 @@ if (toggleStretchAction) toggleStretchAction->setChecked(stretchImage); - if (currentZoom != ZOOM_DEFAULT) - { - // Only scale when necessary - if (scaledImage.isNull() || currentWidth != lastWidth || currentHeight != lastHeight) - { - scaledImage = rawImage.scaled(currentWidth, currentHeight, Qt::KeepAspectRatio, Qt::SmoothTransformation); - lastWidth = currentWidth; - lastHeight = currentHeight; - } - ok = displayPixmap.convertFromImage(scaledImage); - } - else - ok = displayPixmap.convertFromImage(rawImage); + ok = displayPixmap.convertFromImage(rawImage); if (!ok) return; QPainter painter(&displayPixmap); + // Possibly scale the fonts as we're drawing on the full image, not just the visible part of the scroll window. + QFont font = painter.font(); + font.setPixelSize(scaleSize(FONT_SIZE)); + painter.setFont(font); + drawOverlay(&painter); if (starFilter.used()) { - double const diagonal = std::sqrt(currentWidth * currentWidth + currentHeight * currentHeight) / 2; + double const diagonal = std::sqrt(imageData->width() * imageData->width() + imageData->height() * imageData->height()) / 2; int const innerRadius = std::lround(diagonal * starFilter.innerRadius); int const outerRadius = std::lround(diagonal * starFilter.outerRadius); - QPoint const center(currentWidth / 2, currentHeight / 2); + QPoint const center(imageData->width() / 2, imageData->height() / 2); painter.save(); - painter.setPen(QPen(Qt::blue, 1, Qt::DashLine)); + painter.setPen(QPen(Qt::blue, scaleSize(1), Qt::DashLine)); painter.setOpacity(0.7); painter.setBrush(QBrush(Qt::transparent)); painter.drawEllipse(center, outerRadius, outerRadius); @@ -680,7 +707,7 @@ image_frame->setPixmap(displayPixmap); - image_frame->resize(currentWidth, currentHeight); + image_frame->resize((currentZoom / 100.0) * image_frame->pixmap()->size()); } void FITSView::ZoomDefault() @@ -735,22 +762,23 @@ void FITSView::drawMarker(QPainter * painter) { - painter->setPen(QPen(QColor(KStarsData::Instance()->colorScheme()->colorNamed("TargetColor")), 2)); + painter->setPen(QPen(QColor(KStarsData::Instance()->colorScheme()->colorNamed("TargetColor")), + scaleSize(2))); painter->setBrush(Qt::NoBrush); - float pxperdegree = (currentZoom / ZOOM_DEFAULT) * (57.3 / 1.8); + constexpr float pxperdegree = (57.3 / 1.8); - float s1 = 0.5 * pxperdegree; - float s2 = pxperdegree; - float s3 = 2.0 * pxperdegree; + const float s1 = 0.5 * pxperdegree; + const float s2 = pxperdegree; + const float s3 = 2.0 * pxperdegree; - float x0 = markerCrosshair.x() * (currentZoom / ZOOM_DEFAULT); - float y0 = markerCrosshair.y() * (currentZoom / ZOOM_DEFAULT); - float x1 = x0 - 0.5 * s1; - float y1 = y0 - 0.5 * s1; - float x2 = x0 - 0.5 * s2; - float y2 = y0 - 0.5 * s2; - float x3 = x0 - 0.5 * s3; - float y3 = y0 - 0.5 * s3; + const float x0 = markerCrosshair.x(); + const float y0 = markerCrosshair.y(); + const float x1 = x0 - 0.5 * s1; + const float y1 = y0 - 0.5 * s1; + const float x2 = x0 - 0.5 * s2; + const float y2 = y0 - 0.5 * s2; + const float x3 = x0 - 0.5 * s3; + const float y3 = y0 - 0.5 * s3; //Draw radial lines painter->drawLine(QPointF(x1, y0), QPointF(x3, y0)); @@ -764,37 +792,35 @@ void FITSView::drawStarCentroid(QPainter * painter) { - float const ratio = currentZoom / ZOOM_DEFAULT; - if (showStarsHFR) { QFont painterFont; // If we need to print the HFR out, give an arbitrarily sized font to the painter - painterFont.setPointSizeF(painterFont.pointSizeF() * 3 * ratio); + painterFont.setPointSizeF(scaleSize(painterFont.pointSizeF())); painter->setFont(painterFont); } - painter->setPen(QPen(Qt::red, 2)); + painter->setPen(QPen(Qt::red, scaleSize(2))); QFontMetrics const fontMetrics = painter->fontMetrics(); QRect const boundingRect(0, 0, painter->device()->width(), painter->device()->height()); foreach (auto const &starCenter, imageData->getStarCenters()) { - int const w = std::round(starCenter->width * ratio); + int const w = std::round(starCenter->width); // Draw a circle around the detected star. // SEP coordinates are in the center of pixels, and Qt at the boundary. const double xCoord = starCenter->x - 0.5; const double yCoord = starCenter->y - 0.5; - const double radius = starCenter->HFR > 0 ? 2.0f * starCenter->HFR * ratio : w; - painter->drawEllipse(QPointF(xCoord * ratio, yCoord * ratio), radius, radius); + const double radius = starCenter->HFR > 0 ? 2.0f * starCenter->HFR : w; + painter->drawEllipse(QPointF(xCoord, yCoord), radius, radius); if (showStarsHFR) { - int const x1 = std::round((xCoord - starCenter->width / 2.0f) * ratio); - int const y1 = std::round((yCoord - starCenter->width / 2.0f) * ratio); + int const x1 = std::round(xCoord - starCenter->width / 2.0f); + int const y1 = std::round(yCoord - starCenter->width / 2.0f); // Ask the painter how large will the HFR text be QString const hfr = QString("%1").arg(starCenter->HFR, 0, 'f', 2); @@ -807,25 +833,25 @@ // Render the HFR text only if it can be displayed entirely if (boundingRect.contains(hfrRect)) { - painter->setPen(QPen(Qt::red, 3)); + painter->setPen(QPen(Qt::red, scaleSize(3))); painter->drawText(hfrBottomLeft, hfr); - painter->setPen(QPen(Qt::red, 2)); + painter->setPen(QPen(Qt::red, scaleSize(2))); } } } } void FITSView::drawTrackingBox(QPainter * painter) { - painter->setPen(QPen(Qt::green, 2)); + painter->setPen(QPen(Qt::green, scaleSize(2))); if (trackingBox.isNull()) return; - int x1 = trackingBox.x() * (currentZoom / ZOOM_DEFAULT); - int y1 = trackingBox.y() * (currentZoom / ZOOM_DEFAULT); - int w = trackingBox.width() * (currentZoom / ZOOM_DEFAULT); - int h = trackingBox.height() * (currentZoom / ZOOM_DEFAULT); + const int x1 = trackingBox.x(); + const int y1 = trackingBox.y(); + const int w = trackingBox.width(); + const int h = trackingBox.height(); painter->drawRect(x1, y1, w, h); } @@ -837,17 +863,16 @@ void FITSView::drawCrosshair(QPainter * painter) { if (!imageData) return; - int image_width = imageData->width(); - int image_height = imageData->height(); - float scale = (currentZoom / ZOOM_DEFAULT); - QPointF c = QPointF((qreal)image_width / 2 * scale, (qreal)image_height / 2 * scale); - float midX = (float)image_width / 2 * scale; - float midY = (float)image_height / 2 * scale; - float maxX = (float)image_width * scale; - float maxY = (float)image_height * scale; - float r = 50 * scale; + const int image_width = imageData->width(); + const int image_height = imageData->height(); + const QPointF c = QPointF((qreal)image_width / 2, (qreal)image_height / 2); + const float midX = (float)image_width / 2; + const float midY = (float)image_height / 2; + const float maxX = (float)image_width; + const float maxY = (float)image_height; + constexpr float r = 50; - painter->setPen(QPen(QColor(KStarsData::Instance()->colorScheme()->colorNamed("TargetColor")))); + painter->setPen(QPen(QColor(KStarsData::Instance()->colorScheme()->colorNamed("TargetColor")), scaleSize(1))); //Horizontal Line to Circle painter->drawLine(0, midY, midX - r, midY); @@ -876,36 +901,40 @@ void FITSView::drawPixelGrid(QPainter * painter) { - float scale = (currentZoom / ZOOM_DEFAULT); - float width = imageData->width() * scale; - float height = imageData->height() * scale; - float cX = width / 2; - float cY = height / 2; - float deltaX = width / 10; - float deltaY = height / 10; + const float width = imageData->width(); + const float height = imageData->height(); + const float cX = width / 2; + const float cY = height / 2; + const float deltaX = width / 10; + const float deltaY = height / 10; + QFontMetrics fm(painter->font()); + //draw the Axes - painter->setPen(QPen(Qt::red)); - painter->drawText(cX - 30, height - 5, QString::number((int)((cX) / scale))); - painter->drawText(width - 30, cY - 5, QString::number((int)((cY) / scale))); + painter->setPen(QPen(Qt::red, scaleSize(1))); + painter->drawText(cX - 30, height - 5, QString::number((int)(cX))); + QString str = QString::number((int)(cY)); + painter->drawText(width - (fm.width(str)+10), cY - 5, str); if (!showCrosshair) { painter->drawLine(cX, 0, cX, height); painter->drawLine(0, cY, width, cY); } - painter->setPen(QPen(Qt::gray)); + painter->setPen(QPen(Qt::gray, scaleSize(1))); //Start one iteration past the Center and draw 4 lines on either side of 0 for (int x = deltaX; x < cX - deltaX; x += deltaX) { - painter->drawText(cX + x - 30, height - 5, QString::number((int)((cX + x) / scale))); - painter->drawText(cX - x - 30, height - 5, QString::number((int)((cX - x) / scale))); + painter->drawText(cX + x - 30, height - 5, QString::number((int)(cX + x))); + painter->drawText(cX - x - 30, height - 5, QString::number((int)(cX - x))); painter->drawLine(cX - x, 0, cX - x, height); painter->drawLine(cX + x, 0, cX + x, height); } //Start one iteration past the Center and draw 4 lines on either side of 0 for (int y = deltaY; y < cY - deltaY; y += deltaY) { - painter->drawText(width - 30, cY + y - 5, QString::number((int)((cY + y) / scale))); - painter->drawText(width - 30, cY - y - 5, QString::number((int)((cY - y) / scale))); + QString str = QString::number((int)(cY + y)); + painter->drawText(width - (fm.width(str) + 10), cY + y - 5, str); + str = QString::number((int)(cY - y)); + painter->drawText(width - (fm.width(str) + 10), cY - y - 5, str); painter->drawLine(0, cY + y, width, cY + y); painter->drawLine(0, cY - y, width, cY - y); } @@ -921,11 +950,10 @@ void FITSView::drawObjectNames(QPainter * painter) { painter->setPen(QPen(QColor(KStarsData::Instance()->colorScheme()->colorNamed("FITSObjectLabelColor")))); - float scale = (currentZoom / ZOOM_DEFAULT); foreach (FITSSkyObject * listObject, imageData->getSkyObjects()) { - painter->drawRect(listObject->x() * scale - 5, listObject->y() * scale - 5, 10, 10); - painter->drawText(listObject->x() * scale + 10, listObject->y() * scale + 10, listObject->skyObject()->name()); + painter->drawRect(listObject->x() - 5, listObject->y() - 5, 10, 10); + painter->drawText(listObject->x() + 10, listObject->y() + 10, listObject->skyObject()->name()); } } @@ -938,16 +966,15 @@ void FITSView::drawEQGrid(QPainter * painter) { - float scale = (currentZoom / ZOOM_DEFAULT); - int image_width = imageData->width(); - int image_height = imageData->height(); + const int image_width = imageData->width(); + const int image_height = imageData->height(); if (imageData->hasWCS()) { wcs_point * wcs_coord = imageData->getWCSCoord(); if (wcs_coord != nullptr) { - int size = image_width * image_height; + const int size = image_width * image_height; double maxRA = -1000; double minRA = 1000; double maxDec = -1000; @@ -1031,28 +1058,22 @@ bool inImage = imageData->wcsToPixel(pointToGet, pixelPoint, imagePoint); if (inImage) { - QPointF pt(pixelPoint.x() * scale, pixelPoint.y() * scale); + QPointF pt(pixelPoint.x(), pixelPoint.y()); eqGridPoints.append(pt); } } if (eqGridPoints.count() > 1) { for (int i = 1; i < eqGridPoints.count(); i++) painter->drawLine(eqGridPoints.value(i - 1), eqGridPoints.value(i)); - QPointF pt = getPointForGridLabel(); + QString str = QString::number(dms(target).hour()) + "h " + + QString::number(dms(target).minute()) + '\''; + if (maxDec <= 50 && maxDec >= -50) + str = str + " " + QString::number(dms(target).second()) + "''"; + QPointF pt = getPointForGridLabel(painter, str); if (pt.x() != -100) - { - if (maxDec > 50 || maxDec < -50) - painter->drawText(pt.x(), pt.y(), - QString::number(dms(target).hour()) + "h " + - QString::number(dms(target).minute()) + '\''); - else - painter->drawText(pt.x() - 20, pt.y(), - QString::number(dms(target).hour()) + "h " + - QString::number(dms(target).minute()) + "' " + - QString::number(dms(target).second()) + "''"); - } + painter->drawText(pt.x(), pt.y(), str); } } @@ -1073,19 +1094,18 @@ bool inImage = imageData->wcsToPixel(pointToGet, pixelPoint, imagePoint); if (inImage) { - QPointF pt(pixelPoint.x() * scale, pixelPoint.y() * scale); + QPointF pt(pixelPoint.x(), pixelPoint.y()); eqGridPoints.append(pt); } } if (eqGridPoints.count() > 1) { for (int i = 1; i < eqGridPoints.count(); i++) painter->drawLine(eqGridPoints.value(i - 1), eqGridPoints.value(i)); - QPointF pt = getPointForGridLabel(); + QString str = QString::number(dms(target).degree()) + "° " + QString::number(dms(target).arcmin()) + '\''; + QPointF pt = getPointForGridLabel(painter, str); if (pt.x() != -100) - painter->drawText(pt.x(), pt.y(), - QString::number(dms(target).degree()) + "° " + - QString::number(dms(target).arcmin()) + '\''); + painter->drawText(pt.x(), pt.y(), str); } } @@ -1099,9 +1119,9 @@ (pPoint.x() > 0 && pPoint.x() < image_width) && (pPoint.y() > 0 && pPoint.y() < image_height); if (NCPinImage) { - painter->fillRect(pPoint.x() * scale - 2, pPoint.y() * scale - 2, 4, 4, + painter->fillRect(pPoint.x() - 2, pPoint.y() - 2, 4, 4, KStarsData::Instance()->colorScheme()->colorNamed("TargetColor")); - painter->drawText(pPoint.x() * scale + 15, pPoint.y() * scale + 15, + painter->drawText(pPoint.x() + 15, pPoint.y() + 15, i18nc("North Celestial Pole", "NCP")); } } @@ -1116,92 +1136,90 @@ (pPoint.x() > 0 && pPoint.x() < image_width) && (pPoint.y() > 0 && pPoint.y() < image_height); if (SCPinImage) { - painter->fillRect(pPoint.x() * scale - 2, pPoint.y() * scale - 2, 4, 4, + painter->fillRect(pPoint.x() - 2, pPoint.y() - 2, 4, 4, KStarsData::Instance()->colorScheme()->colorNamed("TargetColor")); - painter->drawText(pPoint.x() * scale + 15, pPoint.y() * scale + 15, + painter->drawText(pPoint.x() + 15, pPoint.y() + 15, i18nc("South Celestial Pole", "SCP")); } } } } } -bool FITSView::pointIsInImage(QPointF pt, bool scaled) +bool FITSView::pointIsInImage(QPointF pt) { int image_width = imageData->width(); int image_height = imageData->height(); - float scale = (currentZoom / ZOOM_DEFAULT); - if (scaled) - return pt.x() < image_width * scale && pt.y() < image_height * scale && pt.x() > 0 && pt.y() > 0; - else - return pt.x() < image_width && pt.y() < image_height && pt.x() > 0 && pt.y() > 0; + return pt.x() < image_width && pt.y() < image_height && pt.x() > 0 && pt.y() > 0; } -QPointF FITSView::getPointForGridLabel() +QPointF FITSView::getPointForGridLabel(QPainter *painter, const QString& str) { + QFontMetrics fm(painter->font()); + int strWidth = fm.width(str); + int strHeight = fm.height(); int image_width = imageData->width(); int image_height = imageData->height(); - float scale = (currentZoom / ZOOM_DEFAULT); //These get the maximum X and Y points in the list that are in the image - QPointF maxXPt(image_width * scale / 2, image_height * scale / 2); + QPointF maxXPt(image_width / 2, image_height / 2); for (auto &p : eqGridPoints) { - if (p.x() > maxXPt.x() && pointIsInImage(p, true)) + if (p.x() > maxXPt.x() && pointIsInImage(p)) maxXPt = p; } - QPointF maxYPt(image_width * scale / 2, image_height * scale / 2); + QPointF maxYPt(image_width / 2, image_height / 2); for (auto &p : eqGridPoints) { - if (p.y() > maxYPt.y() && pointIsInImage(p, true)) + if (p.y() > maxYPt.y() && pointIsInImage(p)) maxYPt = p; } - QPointF minXPt(image_width * scale / 2, image_height * scale / 2); + QPointF minXPt(image_width / 2, image_height / 2); for (auto &p : eqGridPoints) { - if (p.x() < minXPt.x() && pointIsInImage(p, true)) + if (p.x() < minXPt.x() && pointIsInImage(p)) minXPt = p; } - QPointF minYPt(image_width * scale / 2, image_height * scale / 2); + QPointF minYPt(image_width / 2, image_height / 2); for (auto &p : eqGridPoints) { - if (p.y() < minYPt.y() && pointIsInImage(p, true)) + if (p.y() < minYPt.y() && pointIsInImage(p)) minYPt = p; } //This gives preference to points that are on the right hand side and bottom. //But if the line doesn't intersect the right or bottom, it then tries for the top and left. //If no points are found in the image, it returns a point off the screen //If all else fails, like in the case of a circle on the image, it returns the far right point. - if (image_width * scale - maxXPt.x() < 10) + if (image_width - maxXPt.x() < strWidth) { return QPointF( - image_width * scale - 50, + image_width - (strWidth + 10), maxXPt.y() - - 10); //This will draw the text on the right hand side, up and to the left of the point where the line intersects + strHeight); //This will draw the text on the right hand side, up and to the left of the point where the line intersects } - if (image_height * scale - maxYPt.y() < 10) + if (image_height - maxYPt.y() < strHeight) return QPointF( - maxYPt.x() - 40, - image_height * scale - - 10); //This will draw the text on the bottom side, up and to the left of the point where the line intersects - if (minYPt.y() * scale < 30) + maxYPt.x() - (strWidth + 10), + image_height - + (strHeight + 10)); //This will draw the text on the bottom side, up and to the left of the point where the line intersects + if (minYPt.y() < strHeight) return QPointF( minYPt.x() + 10, - 20); //This will draw the text on the top side, down and to the right of the point where the line intersects - if (minXPt.x() * scale < 30) + strHeight + 20); //This will draw the text on the top side, down and to the right of the point where the line intersects + if (minXPt.x() < strWidth) return QPointF( 10, minXPt.y() + - 20); //This will draw the text on the left hand side, down and to the right of the point where the line intersects - if (maxXPt.x() == image_width * scale / 2 && maxXPt.y() == image_height * scale / 2) + strHeight + 20); //This will draw the text on the left hand side, down and to the right of the point where the line intersects + if (maxXPt.x() == image_width / 2 && maxXPt.y() == image_height / 2) return QPointF(-100, -100); //All of the points were off the screen - return QPoint(maxXPt.x() - 40, maxXPt.y() - 10); + return QPoint(maxXPt.x() - (strWidth + 10), maxXPt.y() - (strHeight + 10)); } void FITSView::setFirstLoad(bool value) @@ -1214,10 +1232,10 @@ if (trackingBox.isNull()) return trackingBoxPixmap; - int x1 = (trackingBox.x() - margin) * (currentZoom / ZOOM_DEFAULT); - int y1 = (trackingBox.y() - margin) * (currentZoom / ZOOM_DEFAULT); - int w = (trackingBox.width() + margin * 2) * (currentZoom / ZOOM_DEFAULT); - int h = (trackingBox.height() + margin * 2) * (currentZoom / ZOOM_DEFAULT); + int x1 = (trackingBox.x() - margin); + int y1 = (trackingBox.y() - margin); + int w = (trackingBox.width() + margin * 2); + int h = (trackingBox.height() + margin * 2); trackingBoxPixmap = image_frame->grab(QRect(x1, y1, w, h));