QT Image插件编写
QT的QImage用过都知道,真香!工作中遇到一个情况,需要编写一个包装一个私有的图像格式,其实就是为了不让人随意引用,防个君子而已。如果能做成插件形式,修改个格式名称,那么就和以前的QImage一样了,其他部分根本用不着修改。
看了下,网上也有权威链接资料。见下面附录链接。
下面说一下简单的步骤:
简单说,由两种plugin,一种高级版,一种底层版。很明显底层版更难些,高级版的更方便入门。其实我们的大部分需求都是高级版,QT已经搭好了很好的框架,我们只要“完型填空”就可以了。图像类型imageFormat就属于这种,是典型高层需求,有完善的架构。我们来看下:
项目搭建
![打开QT](https://img-blog.csdnimg.cn/20210520135948512.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3N0ZXZlbmtvaA==,size_16,color_FFFFFF,t_70)
![类型,选QTPlugin](https://img-blog.csdnimg.cn/20210520140221434.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3N0ZXZlbmtvaA==,size_16,color_FFFFFF,t_70)
![qimagioplugin](https://img-blog.csdnimg.cn/20210520140436581.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3N0ZXZlbmtvaA==,size_16,color_FFFFFF,t_70)
这样构建了基础的框架。看一下这个构建好的pro文件
系统自动生成的还三样必须的东西才能构建。两个必须填写的虚函数,以及一个json配置文件。
//头文件
#ifndef IMAGEIOPLUGIN_H
#define IMAGEIOPLUGIN_H
#include <QImageIOPlugin>
class ImageIOPlugin : public QImageIOPlugin
{
Q_OBJECT
#if QT_VERSION >= 0x050000
Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QImageIOHandlerFactoryInterface" FILE "testPlugin.json")
#endif // QT_VERSION >= 0x050000
public:
ImageIOPlugin(QObject *parent = 0);
//注意上面这句 Q_PLUGIN_METADATA,文件扩展名都在一个json配置文件内说明,并自动向qt系统注册。
//上述都是自动生成,下面两个是自己临时填写的。这两个是必须填写的虚函数
public:
Capabilities capabilities(QIODevice *device, const QByteArray &format) const override;
QImageIOHandler *create(QIODevice *device, const QByteArray &format = QByteArray()) const override;
};
#endif // IMAGEIOPLUGIN_H
//代码文件,主要是先跑起来,加点调试信息
#include <QDebug>
#include "imageioplugin.h"
ImageIOPlugin::ImageIOPlugin(QObject *parent) :
QImageIOPlugin(parent)
{
qDebug() << "22a" << __FUNCTION__ ;
}
QImageIOPlugin::Capabilities ImageIOPlugin::capabilities(QIODevice *device, const QByteArray &format) const
{
if (device){
qDebug() << "22a" << __FUNCTION__ << "isOpen:" << device->isOpen()\
<< "isRead:" << device->isReadable() \
<< format;
}
else {
qDebug() << "22a device is NULL" << format;
}
return (CanRead);
}
QImageIOHandler *ImageIOPlugin::create(QIODevice *device, const QByteArray &format) const
{
qDebug() << __FUNCTION__ << "isOpen:" << device->isOpen()\
<< "isRead:" << device->isReadable() \
<< format;
return NULL;
}
#if QT_VERSION < 0x050000
Q_EXPORT_PLUGIN2(testPlugin, ImageIOPlugin)
#endif // QT_VERSION < 0x050000
系统生成的plugin.json文件,有个问题,还需要加上mimeTypes才能写全,否则QImageReader::supportedImageFormats()和QImageReader::supportedMimeTypes()会查询不到你注册的图像类型。
//json配置文件,mimeTypes需要自己添加,瞎写的,跑起来再说。
{
"Keys" : ["22a", "22b"],
"MimeTypes": [
"image/22a", "image/22b"
]
}
构建成功以后,在imageformats目录里,就有dll/dxp等文件
QT的图像类型插件的结构图
QImageIOPlugin是一个factory类,QImageIOPlugin的主要工作不是“ImageIO”,而是Plugin。主要负责和qt的插件机制通信、注册。Image部分的话,QImageIOPlugin会首先被QImageReader调用询问,咨询QImageIOPlugin注册的文件类型是否支持,如果支持是支持读、写或全支持?
而QImageIOHandler是一个实际操作类,具体的文件读写由这个类完成。如果Plugin回答QImageReader支持该文件,那么Plugin会生成一个Handler,后续具体图像格式解码就由QImageIOHandler负责处理。
QImageIOHandler定义了一些基本的ImageOptions,这些options通过QVariant传递参数信息。这样我们在上层的QImage层面就能统一处理,就能方便地使用QImage这个类了。
真正处理Image格式的代码,都在QImageIOHandler的子类里。
发布和部署
一切都是自动的,甚至可以用static plugins的方式集成到程序内部。具体参见资料链接
注意。如果 qtplugin需要调用第三方dll,必须确保第三方dll在PATH目录内。
Writing a Qt Image Plugin
https://doc.qt.io/archives/qq/qq17-imageio.html
How to Create Qt Plugins
https://doc.qt.io/qt-5/plugins-howto.html