拷打Qt中的图片缩放功能

引入问题

我这里有一张图片,它是在是太大了以至于我将其设置到QLabel中,我的屏幕完全装不下:
在这里插入图片描述
你可以看到,我的屏幕可能只装下了整张图片的四分之一。

上面的图片,我使用了如下的Qt代码对其进行展示:

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);
    QImage image(QString(":/images/5.jpg"));
    QLabel w;
    w.setFixedSize(image.size());
    w.setPixmap(QPixmap::fromImage(image));
    w.show();
    return app.exec();
}

我就想了,既然图片太大,那我们缩小不就完了吗?问题是怎么缩小呢?猜测Qt中有相应的缩放接口。

果不其然,我在Qt对于QImage的帮助文档中找到了一个名为scaled()的函数。

QImage::scaled()

QImage QImage::scaled(
	int width,
	int height,
	Qt::AspectRatioMode aspectRatioMode = Qt::IgnoreAspectRatio,
	Qt::TransformationMode transformMode = Qt::FastTransformation
) const;

Qt帮助文档中说,这个函数返回根据后面两个名字很长的参数,返回一个原本的QImage被压缩到长为height,宽为width的矩形中。

我不太懂啊,所以先试一下在说,先不用后面两个名字很长的参数,看看胡乱指定前面两个参数看看结果是什么样的先。

于是我在原本的代码中添加了这样一行:

image = image.scaled(1000, 200);

在这里插入图片描述
虽然我做到了缩小图片,让图片完全展示在屏幕里。但是这人都被压扁了!图片的缩放比例明显不正确,我需要的是等比例缩放,难道我还得自己定义计算这个等比例缩放的值?

所以我改善了原本随意设置宽和高的做法,转而通过采集原有图片的大小,然后等比例缩小这个大小从而达到缩放的目的:

QImage image("/path/to/your/image");
QSize size = image.size();
size = size / 5;
image = image.scaled(size.width(), size.height());

这样子缩放的图片展示的效果如下:

在这里插入图片描述
这下终于有个人样了,不是被“压扁的”了。

我在了解缩放功能之前,使用各种PDF阅读器的时候,经常会有缩放100%,缩放200%这样的数字出现,我之前一直不知道是什么意思。

ε=(´ο`*)))唉,我现在似乎理解了,莫非就是放缩后的size / 原本的size得到的一个值?对于我们上面这个例子,这个值是1 / 5也就是20%。

那么我们,后续只需要定义一个缩放因子zoomFactor,将图片原本的size乘以这个因子,然后在使用scaled()对图片进行缩放操作就可以了。


等等,其实我们还有一个问题没有解决,那么就是scaled()后面两个参数有什么作用呢?

我们都学了一半了,再一半也没有什么难度的,就看看,说不定这个特性哪天就遇上了呢?

(1)Qt::AspectRatioMode

  1. Qt::IgnoreAspectRatio:大小可以自由缩放,不保留纵横比。这个是scaled()默认指定的。
  2. Qt::KeepAspectRatio:大小将缩放给定矩形内尽可能大的矩形,同时保持纵横比。你可以把它想象成一个本来非常大的图片,然后你指定了一个非常小的矩形,它逐渐等比例缩小,然后最终完全落在你给定的矩形之内,但是它不保证这个图片将你给定的矩形整个占满。
  3. Qt::KeepAspectRatioByExpanding:大小将缩放为给定矩形之外尽可能小,同时保持横纵比。你可以把它想象成一个本来非常大的图片,然后你指定了一个非常小的矩形,它逐渐等比例缩小,然后最终达到一种情况:它如果在等比例缩小它就填不满你给定的这个矩形了。

(2)Qt::TransformationMode

  1. Qt::FastTransformation:转换将快速执行,没有平滑。
  2. Qt::SmoothTransformation:生成的图像使用双线性筛选进行转换。

说真的,我也不知道这个转换模式平不平滑到底是啥意思?这里就先不管了。

实战演练

现在,我们有这样一个需求:我们前面不是说了因为屏幕装不下图片所以才需要进行缩放吗?现在我告诉你,屏幕装不下整个图片是我故意这么干的,因为我想要细致地,额,欣赏图片(嗯,没错)。但现在,图片只展示了左上角的区域,有没有办法把图片的中间区域完全展示在窗口上?

没有什么目的,我就只是单纯有这个需求而已,经常用pdf阅读器的同志们都知道,有的时候需要放大pdf以看得更清楚,然后可能会移动pdf页面查看图片不同区域的细节是吧。很正常的需求。怎么解决?

于是我完成了如下的代码,用来展示我想欣赏的区域:

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);
    // 定义要展示区域的大小
    QSize size(600, 600);
    // 中心区域的展示画布
    QPixmap pix(size);
    // 原图
    QImage image(QString(":/images/5.jpg"));
    QRect rect = image.rect();
    QRect srcRect(rect.center().x() - size.width() / 2,
                  rect.center().y() - size.height() / 2,
                  size.width(), size.height()); // 指定中心的矩形
    QPainter painter(&pix);
    painter.drawImage(QRect(QPoint(0, 0), size), image, srcRect);
  
    QLabel w;
    w.setFixedSize(size);
    w.setPixmap(pix);
    w.show();
    return app.exec();
}

它的效果如下:

在这里插入图片描述
但是这串代码好像和缩放没有什么关系吧,啊喂!别着急,虽然我们将图片的中心区域600*600的图片展示了出来,但是现在这个情况就是,我们观察的太细致了以至于我们没有看到全貌,所以我们这时候就需要进行缩放,从局部到全局:

于是我们再次对图片进行缩放操作,这次的缩放比例先设置为75%:

    image = image.scaled(image.width() * 0.75, image.height(), Qt::KeepAspectRatio);

新的效果如下:

在这里插入图片描述
还是不够全局,于是我将缩放比例调整到0.4:

在这里插入图片描述
这个效果是不是既有全局又有局部呢?

如果你想要看左上角一点,那么你就可以将srcRect的中心点稍微往左上角移一下。如果你想要继续局部观察,那么你就可以将缩放因子进行放大,或者全局观察,将缩放因子缩小。

于是呢,你们从上面得出了什么结论呢?我就得出了这样的结论:

  1. 在窗口大小固定的情况下,我们可以通过调整drawImage中srcRect的中心点,达到展示图片不同的区域的效果。这个中心点的位置如果可以和鼠标事件相结合,那么就可以实现鼠标移动图片的效果。
  2. 在窗口大小固定的情况下,中心点如果固定,我们可以通过调整缩放因子的大小,从而实现从图片的某个位置缩放图片的效果。

这是什么?这不就图片查看器吗?上面那几串代码就可以作为图片查看器的核心代码封装起来,将其中的缩放因子搞成可以通过滚动调整的变量,中心点可以通过鼠标事件进行移动,再加上一些限制移动的逻辑,再添加一些旋转图片的按钮,甚至裁剪图片就是也可以做到(本质就是将选中的区域拿出来)。剩下的不就是一些额外业务逻辑的搭建了吗?

总结

我们从简单的缩放入手,逐步了解如何对图片进行缩放。然后实战演练一个查看图片的需求,推导出了实现图片查看器的核心代码,最终探讨了一下利用这串核心代码进行功能扩展的可能。

希望这篇文章对你了解图片的缩放有帮助。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值