# huaweicloud-CodeArts-RecognizeVatInvoiceSample-cpp **Repository Path**: HuaweiCloudDeveloper/huaweicloud-code-arts-recognize-vat-invoice-sample-cpp ## Basic Information - **Project Name**: huaweicloud-CodeArts-RecognizeVatInvoiceSample-cpp - **Description**: 基于华为云CodeArts IDE for C/C++开发的示例demo,通过调用华为云API,实现增值税发票图片的识别 - **Primary Language**: Unknown - **License**: Apache-2.0 - **Default Branch**: master-dev - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 1 - **Forks**: 0 - **Created**: 2023-08-04 - **Last Updated**: 2025-06-16 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README ## 1、介绍 CodeArts IDE面向华为云开发者提供的智能化可扩展桌面集成开发环境(IDE),结合华为云行业和产业开发套件,实现极致的一站式用云和开发体验。 - **连接华为云,用云更畅快**:内置华为云帐号支持和华为云API开发套件,支持一键登录后快速用云,浏览、查找、引用和调试云服务API,并有样例代码支持 - **编码新体验,开发更高效**:内置华为自研C/C++语言开发支持,提供全新的工程加载、语法着色、符号解析、编码重构和运行调试等开发体验,提升开发效率 - **能力可扩展,生态更开放**:支持基于插件的能力扩展,开放的插件标准,开源的插件框架,开放的插件市场,形成更加开放的生态系统 - **界面可裁剪,体验更优质**:支持基于组建的界面剪裁,在精简模式下形成专用工具的优质体验,又可以在需要时升级为全模式的全量IDE工具 **CodeArts IDE for C/C++**:基于C/C++语言开发CMake工程,并通过CodeArts IDE完成从工程创建、代码编写、运行调试到发布测试的全过程。基于插件扩展可以将个人开发者作业流集成其中,实现从需求到提交的全部过程,更可在业务中集成华为云所提供的的诸多能力,提升应用交付效率。 ### 您将学到什么? 本实验将指导开发者通过CodeArts IDE for C/C++平台,在本地桌面快速开发一个基于Qt实现的简单项目。通过本实验您将体验到: - 1.在CodeArts IDE for C/C++上进行基于CMake项目的本地编译构建 - 2.在CodeArts IDE上调试和运行 - 3.通过调用华为云API接口,实现一个简单的增值税发票图片文字识别功能 ## 2、前置条件 - 注册并登陆华为云账号 - 安装[CodeArts IDE for C/C++](https://devcloud.cn-north-4.huaweicloud.com/codeartside/home) - 使用前需获取账号的AK、SK、Project Id和请求Token,AK/SK在[华为云控制台“我的凭证-访问密钥”](https://console.huaweicloud.com/iam/?agencyId=0b1f24c5a780f4711f64c00993d09b37®ion=cn-north-4&locale=zh-cn#/mine/accessKey)页面上创建,项目Id和token的获取指南详见步骤3。 ## 3、编译构建与运行调试 通过CodeArts IDE以文件夹的形式打开代码包 认证用的ak和sk硬编码到代码中或者明文存储都有很大的安全风险,建议在配置文件或者环境变量中密文存放,使用时解密,确保安全; 本示例以ak和sk保存在环境变量中来实现身份验证为例,运行本示例前请先在本地环境中设置环境变量HUAWEICLOUD_SDK_AK和HUAWEICLOUD_SDK_SK,然后在MyWidget.cpp代码中添加IMAGE_REQUEST_URL和REQUEST TOKEN ```cpp static const std::string ACCESS_KEY = std::getenv("HUAWEICLOUD_SDK_AK"); static const std::string SECRET_KEY = std::getenv("HUAWEICLOUD_SDK_SK"); static const QString IMAGE_REQUEST_URL = ""; static const QString TOKEN_REQUEST_URL = ""; ``` IMAGE_REQUEST_URL和REQUEST TOKEN可参考IDE华为云API中增值税发票识别的文档,入口如下: ![img.png](assets/../asserts/6.png) ![img.png](assets/../asserts/7.png) 添加完成后,在IDE页面的右上角,点击构建项目按钮,或在页面上方的构建->构建项目,CMake构建类型选择Debug。 ![img.png](assets/../asserts/1.png) 然后在弹窗中选择all META,当编译构建成功后,日志打印finished,并显示成功的图示。 ![img.png](assets/../asserts/2.png) 构建成功后,在页面的右上角选择调试的目标,然后进行调试和运行。 ![img.png](assets/../asserts/3.png) 更多信息请参考CodeArts IDE [用户指南](https://support.huaweicloud.com/usermanual-codeartside/codeartside_01_0048.html) ## 4、关键代码片段 ```cpp int main(int argc, char *argv[]) { QApplication app(argc, argv); MyWidget widget; widget.show(); return app.exec(); } MyWidget::MyWidget(QWidget *parent) : QWidget(parent) { resize(800, 600); m_menuButtonLayout = new QVBoxLayout; m_menuButtonLayout->setAlignment(Qt::AlignTop); m_menuTitle = new QLabel(this); m_menuTitle->setText("Menu"); m_menuTitle->setAlignment(Qt::AlignCenter); m_imageRecognitionButton = new QPushButton("Image Recognition", this); m_imageRecognitionButton->setFixedSize(140, 30); m_menuButtonLayout->addWidget(m_menuTitle); m_menuButtonLayout->addWidget(m_imageRecognitionButton); m_menuWidget = new QWidget(this); m_menuWidget->setLayout(m_menuButtonLayout); QFrame* line = new QFrame(this); line->setFrameShape(QFrame::VLine); line->setFrameShadow(QFrame::Sunken); m_stackWidget = new QStackedWidget(this); QHBoxLayout *mainLayout = new QHBoxLayout; mainLayout->addWidget(m_menuWidget, 1); mainLayout->addWidget(line); mainLayout->addWidget(m_stackWidget, 4); setLayout(mainLayout); connect(m_imageRecognitionButton, &QPushButton::clicked, this, &MyWidget::ImageRecognition); } void MyWidget::ImageRecognition() { m_imageLayout = new QVBoxLayout; m_imageWidget = new QWidget(this); m_imageText = new QLabel(this); m_imageText->setText("Preview"); m_imageText->setAlignment(Qt::AlignCenter); m_imageLayout->addWidget(m_imageText); m_image = new QLabel(this); m_fileName = QFileDialog::getOpenFileName(this, "open image"); QString rootPath = QString::fromStdString(GetProjectRootPath()); QString defaultFile = rootPath + "/asserts/vat-invoice.png"; m_fileName = !m_fileName.isEmpty() ? m_fileName : defaultFile; QPixmap pixmap(m_fileName); m_image->setText("图片预览"); m_image->setPixmap(pixmap); m_image->setScaledContents(true); m_image->resize(pixmap.width(), pixmap.height()); m_imageLayout->addWidget(m_image); QPushButton *recogButton = new QPushButton("Recognition", this); m_imageLayout->addWidget(recogButton); m_imageWidget->setLayout(m_imageLayout); m_stackWidget->addWidget(m_imageWidget); m_stackWidget->setCurrentWidget(m_imageWidget); connect(recogButton, &QPushButton::clicked, this, &MyWidget::ShowRecognitionResult); return; } void MyWidget::ShowRecognitionResult() { QJsonDocument recogResult = GetImageRecognitionResult(); std::vector result = ParseJson(recogResult); m_recogWidget = new QListWidget(this); for (const QString& value : result) { m_recogWidget->addItem(value); } m_stackWidget->addWidget(m_recogWidget); m_stackWidget->setCurrentWidget(m_recogWidget); return; } QJsonDocument MyWidget::GetImageRecognitionResult() { QNetworkAccessManager manager; QNetworkRequest request; request.setUrl(QUrl(IMAGE_REQUEST_URL)); request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json"); m_token = GetToken(); request.setRawHeader("X-Auth-Token", m_token); QJsonObject requestBody; requestBody["image"] = ImageToBase64(m_fileName); QJsonDocument jsonDocument(requestBody); QByteArray requestData = jsonDocument.toJson(); QNetworkReply *reply = manager.post(request, requestData); QEventLoop loop; QObject::connect(reply, &QNetworkReply::finished, &loop, &QEventLoop::quit); loop.exec(); QJsonDocument jsonResponse; if (reply->error() == QNetworkReply::NoError) { QByteArray responseData = reply->readAll(); jsonResponse = QJsonDocument::fromJson(responseData); } else { qDebug() << "Error:" << reply->errorString(); } reply->deleteLater(); return jsonResponse; } static QJsonObject FillRequestBody() { QJsonObject requestBody; QJsonObject authObject; QJsonObject identityObject; QJsonArray methodsArray; methodsArray.append("hw_ak_sk"); QJsonObject akSkObject; QJsonObject accessObject; accessObject["key"] = ACCESS_KEY; QJsonObject secretObject; secretObject["key"] = SECRET_KEY; akSkObject["access"] = accessObject; akSkObject["secret"] = secretObject; identityObject["hw_ak_sk"] = akSkObject; identityObject["methods"] = methodsArray; authObject["identity"] = identityObject; QJsonObject scopeObject; QJsonObject projectObject; projectObject["name"] = "cn-north-4"; scopeObject["project"] = projectObject; authObject["scope"] = scopeObject; requestBody["auth"] = authObject; return requestBody; } QByteArray MyWidget::GetToken() { QNetworkAccessManager manager; QNetworkRequest request; request.setUrl(QUrl(TOKEN_REQUEST_URL)); request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json"); QJsonObject requestBody = FillRequestBody(); QJsonDocument jsonDocument(requestBody); QByteArray requestData = jsonDocument.toJson(); QNetworkReply *reply = manager.post(request, requestData); QEventLoop loop; QObject::connect(reply, &QNetworkReply::finished, &loop, &QEventLoop::quit); loop.exec(); QJsonDocument jsonResponse; if (reply->error() == QNetworkReply::NoError) { QVariant token = reply->rawHeader("X-Subject-Token"); m_token = token.toByteArray(); } else { qDebug() << "Error:" << reply->errorString(); } reply->deleteLater(); return m_token; } QString MyWidget::ImageToBase64(const QString& imagePath) { QImage image(imagePath); QByteArray byteArray; QBuffer buffer(&byteArray); image.save(&buffer, "PNG"); return QString(byteArray.toBase64()); } std::vector MyWidget::ParseItemList(const QJsonArray& itemArray) { std::vector result; for (const auto& itemValue : itemArray) { if (itemValue.isObject()) { QJsonObject itemObject = itemValue.toObject(); for (auto item = itemObject.begin(); item != itemObject.end(); ++item) { result.push_back(item.value().toString()); } } } return result; } std::vector MyWidget::ParseJson(const QJsonDocument& response) { std::vector result; if (!response.isNull() && response.isObject()) { QJsonObject jsonObject = response.object(); qDebug() << "Response:" << jsonObject; QJsonObject resultObject = jsonObject["result"].toObject(); for (auto it = resultObject.begin(); it != resultObject.end(); ++it) { if (it.key() == "item_list") { QJsonArray itemArray = it.value().toArray(); std::vector itemArrayResult = ParseItemList(itemArray); result.insert(result.end(), itemArrayResult.begin(), itemArrayResult.end()); continue; } result.push_back(it.value().toString()); } } return result; } ``` ## 5、运行结果 运行结果如下图,点击Image Recognition选择一张发票图片,点击Recognition按钮,即可得到识别的结果。 ![img.png](assets/../asserts/8.png) ## 6、参考 本示例的代码工程仅用于简单演示,实际开发过程中应严格遵循开发指南。访问以下链接可以获取详细信息:[开发指南](https://support.huaweicloud.com/usermanual-codeartside/codeartside_01_0042.html) ## 7、修订记录 | 发布日期 | 文档版本 | 修订说明 | | ------------ | ------------ | ------------ | | 2023-08-14 | 1.0 | 文档首次发布 |