一、概述
需求:
1.编写一个小工具实现图片压缩
2.图片仅支持JPEG和PNG格式
3.目的是压缩图片在磁盘中所占用的大小
4.使用的开发语言是Qt、C++、OpenCV
5.压缩的质量可以动态调节
如下图所示:
ps:
1.如果图片是jpeg压缩质量可以设置10~100,值越大质量越好,图片所占用的磁盘空间也就越大。综合测试下来值设置30的时候压缩的最为合理,且图片不失真,如果图片要求质量较高建议设置40以上。
2.如果图片是png格式,压缩质量是从0~9,值越大压缩率越高,如果没有特殊要求直接设置压缩率为9,直接压缩到最小就行。
二、代码示例
点击查看代码
#include "ImageCompressTool.h"
ImageCompressTool::ImageCompressTool(QWidget* parent)
: CommonGraphicsView{ parent }
{
this->setWindowTitle("图片压缩");
this->setFixedSize(QSize(320, 800));
QVBoxLayout* vLayout = new QVBoxLayout(this);
QHBoxLayout* hLayout = new QHBoxLayout(this);
EditText* et = new EditText(this);
et->setEnabled(false);
et->setFixedHeight(30);
Button* btnChoiceBtn = new Button(this);
btnChoiceBtn->setText("请选择图片");
hLayout->addWidget(et);
hLayout->addWidget(btnChoiceBtn);
hLayout->setAlignment(Qt::AlignTop);
QHBoxLayout* radioTypeHLayout = new QHBoxLayout(this);
QButtonGroup* group = new QButtonGroup(this);
QRadioButton* radioButtonJPEG = new QRadioButton("JPEG", this);
radioButtonJPEG->setFixedSize(60, 30);
QRadioButton* radioButton2PNG = new QRadioButton("PNG", this);
radioButton2PNG->setFixedSize(60, 30);
group->addButton(radioButtonJPEG, 1);
group->addButton(radioButton2PNG, 2);
radioTypeHLayout->addWidget(radioButtonJPEG);
radioTypeHLayout->addWidget(radioButton2PNG);
radioTypeHLayout->setAlignment(Qt::AlignLeft);
//图片质量(JPEG)
qualitLabel = new QLabel(this);
qualitLabel->setText("图片质量:" + QString::number(mKsize));
qualitLabel->setFixedHeight(15);
//显示原图大小(KB)
srcImageKb = new QLabel(this);
srcImageKb->setText("原图大小:");
srcImageKb->setFixedHeight(15);
//显示压缩后图片大小(KB)
compressImageKb = new QLabel(this);
compressImageKb->setText("压缩后图片大小:");
compressImageKb->setFixedHeight(15);
//开始压缩按钮
Button* startCompressBtn = new Button(this);
startCompressBtn->resize(60, 30);
startCompressBtn->setText("开始压缩");
QLabel* comBoxLabel = new QLabel(this);
comBoxLabel->setText("请选择图片质量:");
comBoxLabel->setFixedHeight(15);
//ComBox选择图片质量
comBox = new ComboBox(this);
for (int i = 10;i <= 100;i += 10) {
comBox->addItem(QString::number(i));
}
QHBoxLayout* comBoxHLayout2 = new QHBoxLayout(this);
comBoxHLayout2->addWidget(comBoxLabel);
comBoxHLayout2->addWidget(comBox);
imageViewResult = new QLabel(this);
vLayout->addLayout(hLayout);
vLayout->addLayout(radioTypeHLayout);
//vLayout->addWidget(imageViewSrc);
vLayout->addWidget(imageViewResult);
vLayout->setAlignment(Qt::AlignTop);
vLayout->addWidget(qualitLabel);
vLayout->addWidget(srcImageKb);
vLayout->addWidget(compressImageKb);
vLayout->addLayout(comBoxHLayout2);
vLayout->addWidget(startCompressBtn);
this->setLayout(vLayout);
connect(btnChoiceBtn, &Button::clicked, this, [=]() {
QFileInfo fileInfo;
filePath = QFileDialog::getOpenFileName(this, tr("请选择图片"), "C:/Users/DBF-DEV-103/Downloads/", tr("Image Files(*.jpg *.png *.jpeg)"));
et->setText(filePath);
fileInfo = QFileInfo(filePath);
//获取文件后缀名
QString fileSuffix = fileInfo.suffix();
qDebug() << "文件的后缀名为:" << fileSuffix;
if (fileSuffix == "jpeg" || fileSuffix == "jpg") {
imageType = 0;
radioButtonJPEG->setChecked(true);
comBox->clear();
for (int i = 10;i <= 100; i += 10) {
comBox->addItem(QString::number(i));
}
}
else if (fileSuffix == "png") {
imageType = 1;
radioButton2PNG->setChecked(true);
comBox->clear();
for (int i = 0;i <= 10; i++) {
comBox->addItem(QString::number(i));
}
}
//compressImage();
});
//选择了JPEG
connect(radioButtonJPEG, &QRadioButton::clicked, this, [=]() {
imageType = 0;
qDebug() << "图片类型" << imageType;
});
//选择了PNG
connect(radioButton2PNG, &QRadioButton::clicked, this, [=]() {
imageType = 1;
qDebug() << "图片类型:" << imageType;
});
//开始压缩按钮信号槽(点击事件)
connect(startCompressBtn, &Button::clicked, this, [=]() {
compressImage();
});
//选择图片质量信号槽
connect(comBox, &ComboBox::currentTextChanged, [=](const QString value) {
qDebug() << "选择的value值:" << value;
mKsize = value.toInt();
qualitLabel->setText("图片质量:" + QString::number(mKsize));
});
}
//压缩图片
void ImageCompressTool::compressImage() {
cv::Mat src = cv::imread(this->filePath.toStdString().c_str());
//imshow("src", src);
double srcKb = matSizeInKB(filePath.toStdString());
srcImageKb->setText("原图大小:" + QString::number(srcKb));
std::cout << "原图大小:" << srcKb << std::endl;
std::vector<int> compression_params;
if (imageType == 0) {
compression_params.push_back(cv::IMWRITE_JPEG_QUALITY);
//压缩级别范围从0~100,值越小压缩率越高,即在磁盘占用的空间越小,相应的图片的质量越差
compression_params.push_back(mKsize);
}
else {
compression_params.push_back(cv::IMWRITE_PNG_COMPRESSION);
if (mKsize > 10) {
mKsize = 3;
}
compression_params.push_back(mKsize); // 压缩级别范围从0到9,9是最高压缩
}
//将图片以jpg的格式存入文件
char* compressImgPath = "E://opencv_compress_img.jpeg";
if (imageType == 1) {
compressImgPath = "E://opencv_compress_img.png";
}
bool result = cv::imwrite(compressImgPath, src, compression_params);
if (!result) {
std::cout << "压缩图片失败" << endl;
return;
}
QFile compressFile = QFile(compressImgPath);
double compressSizeKb = matSizeInKB(compressImgPath);
compressImageKb->setText("压缩后的图片大小:" + QString::number(compressSizeKb));
std::cout << "压缩后的图片大小为:" << compressSizeKb << std::endl;
std::cout << "压缩图片成功,存储路径为:" << compressImgPath << std::endl;
}
long ImageCompressTool::matSizeInKB(std::string filePath) {
std::ifstream mFile(filePath, std::ifstream::binary);
if (mFile) {
mFile.seekg(0, mFile.end);
long size = mFile.tellg(); // 获取文件大小(字节)
mFile.close();
return size / 1024; // 转换为KB
}
return -1; // 文件打开失败,返回-1
}
ImageCompressTool::~ImageCompressTool()
{
}