mirror of
https://bitbucket.org/smil3y/kde-extraapps.git
synced 2025-02-23 18:32:53 +00:00
205 lines
6.1 KiB
C++
205 lines
6.1 KiB
C++
/*
|
|
Gwenview: an image viewer
|
|
Copyright 2007 Aurélien Gâteau <agateau@kde.org>
|
|
|
|
This program is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU General Public License
|
|
as published by the Free Software Foundation; either version 2
|
|
of the License, or (at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to the Free Software
|
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
|
|
*/
|
|
#include "moc_imagescaler.cpp"
|
|
|
|
// Qt
|
|
#include <QImage>
|
|
#include <QRegion>
|
|
|
|
// KDE
|
|
#include <KDebug>
|
|
|
|
// Local
|
|
#include <lib/document/document.h>
|
|
#include <lib/paintutils.h>
|
|
|
|
namespace Gwenview
|
|
{
|
|
|
|
// Amount of pixels to keep so that smooth scale is correct
|
|
static const int SMOOTH_MARGIN = 3;
|
|
|
|
struct ImageScalerPrivate
|
|
{
|
|
Qt::TransformationMode mTransformationMode;
|
|
Document::Ptr mDocument;
|
|
qreal mZoom;
|
|
QRegion mRegion;
|
|
};
|
|
|
|
ImageScaler::ImageScaler(QObject* parent)
|
|
: QObject(parent)
|
|
, d(new ImageScalerPrivate)
|
|
{
|
|
d->mTransformationMode = Qt::FastTransformation;
|
|
d->mZoom = 0;
|
|
}
|
|
|
|
ImageScaler::~ImageScaler()
|
|
{
|
|
delete d;
|
|
}
|
|
|
|
void ImageScaler::setDocument(Document::Ptr document)
|
|
{
|
|
if (d->mDocument) {
|
|
disconnect(d->mDocument.data(), 0, this, 0);
|
|
}
|
|
d->mDocument = document;
|
|
// Used when scaler asked for a down-sampled image
|
|
connect(d->mDocument.data(), SIGNAL(downSampledImageReady()),
|
|
SLOT(doScale()));
|
|
// Used when scaler asked for a full image
|
|
connect(d->mDocument.data(), SIGNAL(loaded(KUrl)),
|
|
SLOT(doScale()));
|
|
}
|
|
|
|
void ImageScaler::setZoom(qreal zoom)
|
|
{
|
|
d->mZoom = zoom;
|
|
}
|
|
|
|
void ImageScaler::setTransformationMode(Qt::TransformationMode mode)
|
|
{
|
|
d->mTransformationMode = mode;
|
|
}
|
|
|
|
void ImageScaler::setDestinationRegion(const QRegion& region)
|
|
{
|
|
kDebug() << region;
|
|
d->mRegion = region;
|
|
if (d->mRegion.isEmpty()) {
|
|
return;
|
|
}
|
|
|
|
if (d->mDocument && d->mZoom > 0) {
|
|
doScale();
|
|
}
|
|
}
|
|
|
|
void ImageScaler::doScale()
|
|
{
|
|
if (d->mZoom < Document::maxDownSampledZoom()) {
|
|
if (!d->mDocument->prepareDownSampledImageForZoom(d->mZoom)) {
|
|
kDebug() << "Asked for a down sampled image";
|
|
return;
|
|
}
|
|
} else if (d->mDocument->image().isNull()) {
|
|
kDebug() << "Asked for the full image";
|
|
d->mDocument->startLoadingFullImage();
|
|
return;
|
|
}
|
|
|
|
kDebug() << "Starting";
|
|
Q_FOREACH(const QRect & rect, d->mRegion.rects()) {
|
|
kDebug() << rect;
|
|
scaleRect(rect);
|
|
}
|
|
kDebug() << "Done";
|
|
}
|
|
|
|
void ImageScaler::scaleRect(const QRect& rect)
|
|
{
|
|
const qreal REAL_DELTA = 0.001;
|
|
if (qAbs(d->mZoom - 1.0) < REAL_DELTA) {
|
|
QImage tmp = d->mDocument->image().copy(rect);
|
|
tmp = tmp.convertToFormat(QImage::Format_ARGB32_Premultiplied);
|
|
emit scaledRect(rect.left(), rect.top(), tmp);
|
|
return;
|
|
}
|
|
|
|
QImage image;
|
|
qreal zoom;
|
|
if (d->mZoom < Document::maxDownSampledZoom()) {
|
|
image = d->mDocument->downSampledImageForZoom(d->mZoom);
|
|
Q_ASSERT(!image.isNull());
|
|
qreal zoom1 = qreal(image.width()) / d->mDocument->width();
|
|
zoom = d->mZoom / zoom1;
|
|
} else {
|
|
image = d->mDocument->image();
|
|
zoom = d->mZoom;
|
|
}
|
|
// If rect contains "half" pixels, make sure sourceRect includes them
|
|
QRectF sourceRectF(
|
|
rect.left() / zoom,
|
|
rect.top() / zoom,
|
|
rect.width() / zoom,
|
|
rect.height() / zoom);
|
|
|
|
sourceRectF = sourceRectF.intersected(image.rect());
|
|
QRect sourceRect = PaintUtils::containingRect(sourceRectF);
|
|
if (sourceRect.isEmpty()) {
|
|
return;
|
|
}
|
|
|
|
// Compute smooth margin
|
|
bool needsSmoothMargins = d->mTransformationMode == Qt::SmoothTransformation;
|
|
|
|
int sourceLeftMargin, sourceRightMargin, sourceTopMargin, sourceBottomMargin;
|
|
int destLeftMargin, destRightMargin, destTopMargin, destBottomMargin;
|
|
if (needsSmoothMargins) {
|
|
sourceLeftMargin = qMin(sourceRect.left(), SMOOTH_MARGIN);
|
|
sourceTopMargin = qMin(sourceRect.top(), SMOOTH_MARGIN);
|
|
sourceRightMargin = qMin(image.rect().right() - sourceRect.right(), SMOOTH_MARGIN);
|
|
sourceBottomMargin = qMin(image.rect().bottom() - sourceRect.bottom(), SMOOTH_MARGIN);
|
|
sourceRect.adjust(
|
|
-sourceLeftMargin,
|
|
-sourceTopMargin,
|
|
sourceRightMargin,
|
|
sourceBottomMargin);
|
|
destLeftMargin = int(sourceLeftMargin * zoom);
|
|
destTopMargin = int(sourceTopMargin * zoom);
|
|
destRightMargin = int(sourceRightMargin * zoom);
|
|
destBottomMargin = int(sourceBottomMargin * zoom);
|
|
} else {
|
|
sourceLeftMargin = sourceRightMargin = sourceTopMargin = sourceBottomMargin = 0;
|
|
destLeftMargin = destRightMargin = destTopMargin = destBottomMargin = 0;
|
|
}
|
|
|
|
// destRect is almost like rect, but it contains only "full" pixels
|
|
QRectF destRectF = QRectF(
|
|
sourceRect.left() * zoom,
|
|
sourceRect.top() * zoom,
|
|
sourceRect.width() * zoom,
|
|
sourceRect.height() * zoom
|
|
);
|
|
QRect destRect = PaintUtils::containingRect(destRectF);
|
|
|
|
QImage tmp;
|
|
tmp = image.copy(sourceRect);
|
|
tmp = tmp.convertToFormat(QImage::Format_ARGB32_Premultiplied);
|
|
tmp = tmp.scaled(
|
|
destRect.width(),
|
|
destRect.height(),
|
|
Qt::IgnoreAspectRatio, // Do not use KeepAspectRatio, it can lead to skipped rows or columns
|
|
d->mTransformationMode);
|
|
|
|
if (needsSmoothMargins) {
|
|
tmp = tmp.copy(
|
|
destLeftMargin, destTopMargin,
|
|
destRect.width() - (destLeftMargin + destRightMargin),
|
|
destRect.height() - (destTopMargin + destBottomMargin)
|
|
);
|
|
}
|
|
|
|
emit scaledRect(destRect.left() + destLeftMargin, destRect.top() + destTopMargin, tmp);
|
|
}
|
|
|
|
} // namespace
|