[Qt Topic] – 二维绘图研习,做一个简单批量水印工具
作者:Jason Lee
日期:2010-05-02
平台:Qt SDK v2010.02.1 + Windows Xp
声明:文章作者仅在Intel软件网络和CSDN博客发表本文,如有转载,请注明出处
[1]二维绘图概览
Qt中的二维绘图是基于QPainter、QPaintEngine和QPaintDevice机制的:以QPaintEngine作为中间接口,使用QPainter在不同绘图设备上进行绘图操作,而QPaintDevice就是可使用QPainter进行绘图的二维空间。
使用QPainter可以在绘图设备上进行绘制以下类的实例:QImage、QBitmap、QIcon、QPixmap、QPicture等各种图像和QPoint、QLine、QPolygon等各种图形以及其它许多,难以列举。
目前QPaintDevice的子类有QWidget、QGLWidget、QImage、QPixmap、QGLPixelBuffer、QGLFrameBufferObject、QPicture、QPrinter。也就是说,可以使用QPainter对这些类的实例进行绘图操作。
[2]批量水印工具简单设想
第一,既然是批量处理,那么第一个要求是能够打开多个文件。在这里,我将之处理为打开一个文件夹下面所有可支持的图片,但并未继续递归深入地读取子文件夹。
第二,要有水印功能,就要求工具能够对打开的图片进行绘图操作。这一点比较简单,就是以上提到的使用QPainter在绘图设备上(比如QImage)进行绘图操作。针对这项功能,我只是简单地提供一个行文本框以输入要水印的文字。
第三,因为只是一个简单的、练手的小工具,所以我真的十分简单地实现了它的界面、功能。
第四,可以稍微讨论的扩展有:不只是可以用文本进行水印,也可以用图片,原理基本一致;可以继续递归地打开子文件夹中的图像;可以对QListWidget中的项进行右键处理,比如从列表中移除;其它……
[3]简单水印工具的实现
首先是布局代码。我简单地将界面分为3列:第一列用来打开目标文件夹,进而对里面的图片进行处理;第二列是图片列表,可以切换着观察图片;第三列就是图片浏览区域。以下是部分代码:
QLabel *markLabel; QLineEdit *markText; QHBoxLayout *markLayout; QLabel *folderLabel; QLineEdit *folderEdit; QPushButton *openFolderBtn; QHBoxLayout *folderLayout; QPushButton *applyBtn; QVBoxLayout *leftLayout; QListWidget *filesList; QLabel *imageLabel; QScrollArea *scrollArea; QHBoxLayout *mainLayout;
接着是打开目标文件夹,
connect(openFolderBtn, SIGNAL(clicked()), this, SLOT(slotOpenFolder())); dirPath = QFileDialog::getExistingDirectory(this, tr("Please Select a Directory"), "", QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks); folderEdit->setText(dirPath); QDir dir(dirPath);
然后读取该目录下所有可支持的图片:
QStringList filters; foreach (QByteArray format, QImageReader::supportedImageFormats()) filters += "*." + format; foreach (QString file, dir.entryList(filters, QDir::Files)){ files.append(file); filesList->addItem(file); }
并且浏览第一张图片:
if(!files.isEmpty()){ QImage image(dirPath + '/' + files.at(0)); imageLabel->setPixmap(QPixmap::fromImage(image)); imageLabel->adjustSize(); }
到这里,我们实现了打开目标文件夹并将目录下所有图像文件添加进来的功能。
为了实现点击不同的图片Item能达到切换图片进行观看的功能,首先连接信号和槽:
connect(filesList, SIGNAL(currentRowChanged(int)), this, SLOT(slotChangeImage(int)));
通过QListWidget当前Item的切换信号连接到切换图像的槽,具体代码如下:
void Topic::slotChangeImage(int i){ if(-1 == i) return; if(!files.isEmpty()){ QImage image(dirPath + '/' + files.at(i)); imageLabel->setPixmap(QPixmap::fromImage(image)); imageLabel->adjustSize(); } }
这就达到了切换浏览图片的目的了。
最后就是对所有图片进行水印处理了。
首先,要确保有用来水印的文字,markText就是此用途:
if(markText->text() == ""){ QMessageBox::warning(this, tr("Warning"), tr("No text for marking")); return; }
在有水印文本的条件下,使用QPainter对象来对QImage这个QPaintDevice的子类的实例进行绘图,本质就是简单地使用一下drawText成员函数:
for(int i=0; i<files.size(); ++i){ QImage image(dirPath + '/' + files.at(i)); QPainter painter(&image); painter.setRenderHint(QPainter::Antialiasing, true); painter.setPen(QPen(Qt::blue, 20, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin)); painter.drawText(10, 10, markText->text()); image.save(dirPath + '/' + files.at(i)); } imageLabel->setPixmap(QPixmap::fromImage(QImage(dirPath + '/' + files.at(0)))); imageLabel->adjustSize();
在上面代码中,每次处理完一张图片都立即保存,而如果需要的话可以稍微改动下仅仅实现预览功能,待用户确认后再进行应用以及保存。
水印后的效果图如下:
由于本次的代码挺简单的,就不特地做上传了。
各位晚安!