前言
? ? ? ? 本篇為持續更新狀態,內容包含window、Linux下打動態庫包,以及引入動態庫包的方式。
一、window
1、動態庫打包
以百度的OCR接口調用打dll庫為例,以下為qtcreator創建動態庫過程:
1.1Qtcreator創建lib項目
創建成功后,即包含以下5個文件,其中baiduocrlib.h和baiduocrlib.cpp是生成動態庫文件的主要文件,baiduocrlib_global.h是引入baiduocrlib動態庫時,必須包含的文件(在引入動態庫時詳細介紹)。
1.2修改動態庫輸出目錄
動態庫是通過“構建”生成的,不能“運行”生成,在.pro文件中,加入一行
#在baiduocrlib.cpp的同級目錄,創建一個dll目錄,生成的動態庫將存在此目錄下
DESTDIR = ../dll
點擊左下角的“錘子”進行項目構建,即可在dll下看到生成的動態庫文件,如下圖所示
1.3編寫動態庫內容
與常規編寫的類是一樣,即在頭文件中定義,在cpp文件中定義,頭文件baiduocrlib.h內容如下
#ifndef BAIDUOCRLIB_H
#define BAIDUOCRLIB_H#include <QNetworkAccessManager>
#include <QNetworkRequest>
#include <QNetworkReply>
#include <QEventLoop>
#include <QUrl>
#include <QUrlQuery>
#include <QJsonDocument>
#include <QJsonObject>
#include <QObject>
#include <QDebug>
#include <QFile>
#include <QImage>
#include <QBuffer>
#include <QtCore/qglobal.h>#if defined(BAIDUOCRLIB_LIBRARY)
# define BAIDUOCRLIB_EXPORT Q_DECL_EXPORT
#else
# define BAIDUOCRLIB_EXPORT Q_DECL_IMPORT
#endifclass BAIDUOCRLIB_EXPORT Baiduocrlib
{
public:Baiduocrlib();QByteArray block_post_data(const QNetworkRequest& request,const QUrlQuery& postData);QString get_access_token(const QString& client_id,const QString& client_secret) ;QByteArray get_ocr_data_by_png(const QString& access_token,const QString& img_base64_content);QByteArray get_ocr_data_by_pdf(const QString& access_token,const QString& pdf_base64_content);int get_pdf_urlcontent(const QString& pdfFilePath,QString& urlEncodedString);int get_img_urlcontent(const QString& imagePath,QString& urlEncodedString);
};#endif // BAIDUOCRLIB_H
cpp文件baiduocrlib.cpp內容如下
#include "baiduocrlib.h"Baiduocrlib::Baiduocrlib()
{
}QString Baiduocrlib::get_access_token(const QString& client_id,const QString& client_secret) {QString access_token;QUrl url("https://aip.baidubce.com/oauth/2.0/token");QNetworkRequest request(url);request.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded");request.setRawHeader("Accept", "application/json");// 創建 POST 數據QUrlQuery postData;postData.addQueryItem("grant_type", "client_credentials");postData.addQueryItem("client_id", client_id);postData.addQueryItem("client_secret", client_secret);//發送Post包(通過阻塞方式獲取返回結果)QByteArray jsonData=block_post_data(request,postData);// 解析 JSON 數據QJsonDocument jsonDoc = QJsonDocument::fromJson(jsonData);if (jsonDoc.isNull()) {qDebug() << "Failed to create JSON doc.";return "";}// 檢查 JSON 文檔類型if (jsonDoc.isObject()) {QJsonObject jsonObj = jsonDoc.object();//qDebug() << "JSON Object:" << jsonObj;// 訪問 JSON 對象中的數據if (jsonObj.contains("access_token")) {access_token = jsonObj["access_token"].toString();qDebug() << "access_token:" << access_token;}} else {qDebug() << "JSON is not an object.";}return access_token;
}QByteArray Baiduocrlib::block_post_data(const QNetworkRequest& request,const QUrlQuery& postData){//QString resstr;QByteArray responseData;// 創建網絡訪問管理器QNetworkAccessManager block_manager;// 發送POST請求QNetworkReply* reply = block_manager.post(request, postData.toString(QUrl::FullyEncoded).toUtf8());// 創建一個事件循環來阻塞當前線程QEventLoop loop;QObject::connect(reply, &QNetworkReply::finished, &loop, &QEventLoop::quit);// 阻塞當前線程直到網絡請求完成loop.exec();// 檢查請求結果if (reply->error() == QNetworkReply::NoError) {// 請求成功,處理返回的數據/*QByteArray */responseData = reply->readAll();//resstr = QString::fromUtf8(responseData);//qDebug() << __LINE__ <<"Response:" << resstr;} else {// 請求失敗,處理錯誤qDebug() << "Error:" << reply->errorString();responseData="";}// 清理reply->deleteLater();return responseData;
}QByteArray Baiduocrlib::get_ocr_data_by_png(const QString& access_token,const QString& img_base64_content){//QString urlstr=QString("https://aip.baidubce.com/rest/2.0/ocr/v1/general?access_token=%1").arg(access_token);//標準含位置版本QString urlstr=QString("https://aip.baidubce.com/rest/2.0/ocr/v1/accurate?access_token=%1").arg(access_token);//高精度含位置版本QUrl url(urlstr);QNetworkRequest request(url);request.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded");request.setRawHeader("Accept", "application/json");// 創建 POST 數據QUrlQuery postData;postData.addQueryItem("image", img_base64_content);postData.addQueryItem("detect_direction", "false");postData.addQueryItem("paragraph", "false");postData.addQueryItem("probability", "false");postData.addQueryItem("multidirectional_recognize", "false");//發送Post包(通過阻塞方式獲取返回結果)QByteArray jsonData=block_post_data(request,postData);//qDebug() << __LINE__ <<"jsonData:" << jsonData;return jsonData;
}QByteArray Baiduocrlib::get_ocr_data_by_pdf(const QString& access_token,const QString& pdf_base64_content){qDebug() << __LINE__ << __FUNCTION__;//QString urlstr=QString("https://aip.baidubce.com/rest/2.0/ocr/v1/general?access_token=%1").arg(access_token);//標準含位置版本QString urlstr=QString("https://aip.baidubce.com/rest/2.0/ocr/v1/accurate?access_token=%1").arg(access_token);//高精度含位置版本QUrl url(urlstr);QNetworkRequest request(url);request.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded");request.setRawHeader("Accept", "application/json");// 創建 POST 數據QUrlQuery postData;postData.addQueryItem("pdf_file", pdf_base64_content);postData.addQueryItem("detect_direction", "false");postData.addQueryItem("paragraph", "false");postData.addQueryItem("probability", "false");postData.addQueryItem("multidirectional_recognize", "false");//發送Post包(通過阻塞方式獲取返回結果)QByteArray jsonData=block_post_data(request,postData);//qDebug() << __LINE__ <<"jsonData:" << jsonData;return jsonData;
}int Baiduocrlib::get_pdf_urlcontent(const QString& pdfFilePath,QString& urlEncodedString){// 讀取 PDF 文件QFile file(pdfFilePath);if (!file.open(QIODevice::ReadOnly)) {qDebug() << "無法打開文件:" << pdfFilePath;return -1;}QByteArray pdfData = file.readAll();file.close();// Base64 編碼QByteArray base64Encoded = pdfData.toBase64();// URL 編碼urlEncodedString = QUrl::toPercentEncoding(base64Encoded);return 0;
}int Baiduocrlib::get_img_urlcontent(const QString& imagePath,QString& urlEncodedString){// 加載圖片QImage image(imagePath);if (image.isNull()) {qDebug() << "無法加載圖片:" << imagePath;return -1;}// 將圖片保存到QByteArray中QByteArray byteArray;QBuffer buffer(&byteArray);buffer.open(QIODevice::WriteOnly);// 將圖片保存為PNG格式,你也可以選擇其他格式如JPEGif (!image.save(&buffer, "PNG")) {qDebug() << "無法將圖片保存到緩沖區";return -1;}buffer.close();// 將二進制數據轉換為Base64編碼QByteArray base64Data = byteArray.toBase64();// 轉換為QStringQString base64String = QString::fromLatin1(base64Data);// URL編碼urlEncodedString = QUrl::toPercentEncoding(base64String);qDebug() << __LINE__ << urlEncodedString.size();return 0;
}
1.4生成的動態庫
以上內容進行構建之后,在dll目錄下將會看到兩個文件Baiduocrlib.dll和libBaiduocrlib.a
主要是使用xxx.dll文件,引用前最好把頭文件也放在同一個目錄下(別的項目引用此動態庫時,需要引用到這個頭文件)。
2、動態庫引入
上面生成了兩個文件:dll和.a(mingw32編譯器生成的動態庫),其他項目引入時,只需要其中一個動態庫文件
1、在.pro文件中加入以下示例內容
#創建lib目錄,把commdll.dll文件和commdll.h文件放到lib目錄下HEADERS += \lib/commdll.h \ #增加頭文件,通過頭文件來引用mainwindow.h
LIBS +=-L$$PWD/lib -lcommdll # $$PWD表示當前路徑
然后在mainwindow.h文件中加入#include "lib/commdll.h"即可,調用時,按照常規類的方式來調用,可以理解為dll文件封裝了自定義類。
Linux
1、動態庫打包
linux下Qtcreator生成動態庫的操作方法與window是一樣的,區別是Linux下生成的是so文件
2、動態庫引入
除了window中直接修改.pro文件,也可以在qtcreator中添加庫,如下所示:
2.1右鍵點擊左上角的項目,選中右鍵菜單【添加庫】
2.2 選中【外部庫】,點擊下一步
2.3
2.3 選擇library type類型為【Linux(lib*.so,lib*.a)】,選擇庫文件和路徑,點擊下一步
2.4點擊完成即可
在pro文件中,可看到如下信息,還缺動態庫的頭文件,在HEADERS中加上動態庫的頭文件即可
結尾
? ? ? ? QT打包的動態庫SO包,后臺g++編譯的程序不一定能調用,受g++版本,以及QT的依賴庫等因素的影響。如果一個SO包既要同時支持g++編譯的程序和QT程序調用,可以用傳統C/C++的打包方式【Linux C/C++開發】編譯及引用so動態庫。