diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..815758be3854bf468075f1907a11c0a7cd88730d --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,49 @@ +# SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. +# +# SPDX-License-Identifier: LGPL-3.0-or-later + +cmake_minimum_required(VERSION 3.10) +project(ocr-cmd) + +#for Qt +set(CMAKE_INCLUDE_CURRENT_DIR ON) +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_INCLUDE_CURRENT_DIR ON) +set(CMAKE_AUTOMOC ON) +set(CMAKE_AUTORCC ON) +set(CMAKE_AUTOUIC ON) + +set(QtModule Core Gui) +find_package(Qt5 REQUIRED ${QtModule}) + +include_directories( + ${Qt5Core_INCLUDE_DIRS} + ${Qt5Gui_INCLUDE_DIRS} +) +add_definitions(${QT_DEFINITIONS}) + +include(CMakePackageConfigHelpers) + +#for project files +include_directories(.) +aux_source_directory(. allSource) + +#for dtkocr +find_package(PkgConfig REQUIRED) +pkg_check_modules(dtk_lib REQUIRED dtkcore dtkocr) + +add_executable(${PROJECT_NAME} ${allSource}) + +target_include_directories(${PROJECT_NAME} PUBLIC + ${dtk_lib_INCLUDE_DIRS} + ${PROJECT_SOURCE_DIR}) + +target_link_libraries(${PROJECT_NAME} dtkocr Qt5::Core Qt5::Gui) + +set(CMAKE_INSTALL_PREFIX /usr) +set(PREFIX ${CMAKE_INSTALL_PREFIX}) +install(TARGETS ${PROJECT_NAME} + EXPORT ${PROJECT_NAME}Targets + LIBRARY DESTINATION ${PREFIX}/lib + ARCHIVE DESTINATION lib + RUNTIME DESTINATION ${PREFIX}/bin) diff --git a/cmdline.h b/cmdline.h new file mode 100644 index 0000000000000000000000000000000000000000..de9eaf74bacb2204759be6c7250897961a66ff4e --- /dev/null +++ b/cmdline.h @@ -0,0 +1,809 @@ +/* + Copyright (c) 2009, Hideyuki Tanaka + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of the nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY ''AS IS'' AND ANY + EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace cmdline{ + +namespace detail{ + +template +class lexical_cast_t{ +public: + static Target cast(const Source &arg){ + Target ret; + std::stringstream ss; + if (!(ss<>ret && ss.eof())) + throw std::bad_cast(); + + return ret; + } +}; + +template +class lexical_cast_t{ +public: + static Target cast(const Source &arg){ + return arg; + } +}; + +template +class lexical_cast_t{ +public: + static std::string cast(const Source &arg){ + std::ostringstream ss; + ss< +class lexical_cast_t{ +public: + static Target cast(const std::string &arg){ + Target ret; + std::istringstream ss(arg); + if (!(ss>>ret && ss.eof())) + throw std::bad_cast(); + return ret; + } +}; + +template +struct is_same { + static const bool value = false; +}; + +template +struct is_same{ + static const bool value = true; +}; + +template +Target lexical_cast(const Source &arg) +{ + return lexical_cast_t::value>::cast(arg); +} + +static inline std::string demangle(const std::string &name) +{ + int status=0; + char *p=abi::__cxa_demangle(name.c_str(), 0, 0, &status); + std::string ret(p); + free(p); + return ret; +} + +template +std::string readable_typename() +{ + return demangle(typeid(T).name()); +} + +template +std::string default_value(T def) +{ + return detail::lexical_cast(def); +} + +template <> +inline std::string readable_typename() +{ + return "string"; +} + +} // detail + +//----- + +class cmdline_error : public std::exception { +public: + cmdline_error(const std::string &msg): msg(msg){} + ~cmdline_error() throw() {} + const char *what() const throw() { return msg.c_str(); } +private: + std::string msg; +}; + +template +struct default_reader{ + T operator()(const std::string &str){ + return detail::lexical_cast(str); + } +}; + +template +struct range_reader{ + range_reader(const T &low, const T &high): low(low), high(high) {} + T operator()(const std::string &s) const { + T ret=default_reader()(s); + if (!(ret>=low && ret<=high)) throw cmdline::cmdline_error("range_error"); + return ret; + } +private: + T low, high; +}; + +template +range_reader range(const T &low, const T &high) +{ + return range_reader(low, high); +} + +template +struct oneof_reader{ + T operator()(const std::string &s){ + T ret=default_reader()(s); + if (std::find(alt.begin(), alt.end(), ret)==alt.end()) + throw cmdline_error(""); + return ret; + } + void add(const T &v){ alt.push_back(v); } +private: + std::vector alt; +}; + +template +oneof_reader oneof(T a1) +{ + oneof_reader ret; + ret.add(a1); + return ret; +} + +template +oneof_reader oneof(T a1, T a2) +{ + oneof_reader ret; + ret.add(a1); + ret.add(a2); + return ret; +} + +template +oneof_reader oneof(T a1, T a2, T a3) +{ + oneof_reader ret; + ret.add(a1); + ret.add(a2); + ret.add(a3); + return ret; +} + +template +oneof_reader oneof(T a1, T a2, T a3, T a4) +{ + oneof_reader ret; + ret.add(a1); + ret.add(a2); + ret.add(a3); + ret.add(a4); + return ret; +} + +template +oneof_reader oneof(T a1, T a2, T a3, T a4, T a5) +{ + oneof_reader ret; + ret.add(a1); + ret.add(a2); + ret.add(a3); + ret.add(a4); + ret.add(a5); + return ret; +} + +template +oneof_reader oneof(T a1, T a2, T a3, T a4, T a5, T a6) +{ + oneof_reader ret; + ret.add(a1); + ret.add(a2); + ret.add(a3); + ret.add(a4); + ret.add(a5); + ret.add(a6); + return ret; +} + +template +oneof_reader oneof(T a1, T a2, T a3, T a4, T a5, T a6, T a7) +{ + oneof_reader ret; + ret.add(a1); + ret.add(a2); + ret.add(a3); + ret.add(a4); + ret.add(a5); + ret.add(a6); + ret.add(a7); + return ret; +} + +template +oneof_reader oneof(T a1, T a2, T a3, T a4, T a5, T a6, T a7, T a8) +{ + oneof_reader ret; + ret.add(a1); + ret.add(a2); + ret.add(a3); + ret.add(a4); + ret.add(a5); + ret.add(a6); + ret.add(a7); + ret.add(a8); + return ret; +} + +template +oneof_reader oneof(T a1, T a2, T a3, T a4, T a5, T a6, T a7, T a8, T a9) +{ + oneof_reader ret; + ret.add(a1); + ret.add(a2); + ret.add(a3); + ret.add(a4); + ret.add(a5); + ret.add(a6); + ret.add(a7); + ret.add(a8); + ret.add(a9); + return ret; +} + +template +oneof_reader oneof(T a1, T a2, T a3, T a4, T a5, T a6, T a7, T a8, T a9, T a10) +{ + oneof_reader ret; + ret.add(a1); + ret.add(a2); + ret.add(a3); + ret.add(a4); + ret.add(a5); + ret.add(a6); + ret.add(a7); + ret.add(a8); + ret.add(a9); + ret.add(a10); + return ret; +} + +//----- + +class parser{ +public: + parser(){ + } + ~parser(){ + for (std::map::iterator p=options.begin(); + p!=options.end(); p++) + delete p->second; + } + + void add(const std::string &name, + char short_name=0, + const std::string &desc=""){ + if (options.count(name)) throw cmdline_error("multiple definition: "+name); + options[name]=new option_without_value(name, short_name, desc); + ordered.push_back(options[name]); + } + + template + void add(const std::string &name, + char short_name=0, + const std::string &desc="", + bool need=true, + const T def=T()){ + add(name, short_name, desc, need, def, default_reader()); + } + + template + void add(const std::string &name, + char short_name=0, + const std::string &desc="", + bool need=true, + const T def=T(), + F reader=F()){ + if (options.count(name)) throw cmdline_error("multiple definition: "+name); + options[name]=new option_with_value_with_reader(name, short_name, need, def, desc, reader); + ordered.push_back(options[name]); + } + + void footer(const std::string &f){ + ftr=f; + } + + void set_program_name(const std::string &name){ + prog_name=name; + } + + bool exist(const std::string &name) const { + if (options.count(name)==0) throw cmdline_error("there is no flag: --"+name); + return options.find(name)->second->has_set(); + } + + template + const T &get(const std::string &name) const { + if (options.count(name)==0) throw cmdline_error("there is no flag: --"+name); + const option_with_value *p=dynamic_cast*>(options.find(name)->second); + if (p==NULL) throw cmdline_error("type mismatch flag '"+name+"'"); + return p->get(); + } + + const std::vector &rest() const { + return others; + } + + bool parse(const std::string &arg){ + std::vector args; + + std::string buf; + bool in_quote=false; + for (std::string::size_type i=0; i=arg.length()){ + errors.push_back("unexpected occurrence of '\\' at end of string"); + return false; + } + } + + buf+=arg[i]; + } + + if (in_quote){ + errors.push_back("quote is not closed"); + return false; + } + + if (buf.length()>0) + args.push_back(buf); + + for (size_t i=0; i &args){ + int argc=static_cast(args.size()); + std::vector argv(argc); + + for (int i=0; i lookup; + for (std::map::iterator p=options.begin(); + p!=options.end(); p++){ + if (p->first.length()==0) continue; + char initial=p->second->short_name(); + if (initial){ + if (lookup.count(initial)>0){ + lookup[initial]=""; + errors.push_back(std::string("short option '")+initial+"' is ambiguous"); + return false; + } + else lookup[initial]=p->first; + } + } + + for (int i=1; i &args){ + if (!options.count("help")) + add("help", '?', "print this message"); + check(args.size(), parse(args)); + } + + void parse_check(int argc, char *argv[]){ + if (!options.count("help")) + add("help", '?', "print this message"); + check(argc, parse(argc, argv)); + } + + std::string error() const{ + return errors.size()>0?errors[0]:""; + } + + std::string error_full() const{ + std::ostringstream oss; + for (size_t i=0; imust()) + oss<short_description()<<" "; + } + + oss<<"[options] ... "<name().length()); + } + for (size_t i=0; ishort_name()){ + oss<<" -"<short_name()<<", "; + } + else{ + oss<<" "; + } + + oss<<"--"<name(); + for (size_t j=ordered[i]->name().length(); jdescription()<set()){ + errors.push_back("option needs value: --"+name); + return; + } + } + + void set_option(const std::string &name, const std::string &value){ + if (options.count(name)==0){ + errors.push_back("undefined option: --"+name); + return; + } + if (!options[name]->set(value)){ + errors.push_back("option value is invalid: --"+name+"="+value); + return; + } + } + + class option_base{ + public: + virtual ~option_base(){} + + virtual bool has_value() const=0; + virtual bool set()=0; + virtual bool set(const std::string &value)=0; + virtual bool has_set() const=0; + virtual bool valid() const=0; + virtual bool must() const=0; + + virtual const std::string &name() const=0; + virtual char short_name() const=0; + virtual const std::string &description() const=0; + virtual std::string short_description() const=0; + }; + + class option_without_value : public option_base { + public: + option_without_value(const std::string &name, + char short_name, + const std::string &desc) + :nam(name), snam(short_name), desc(desc), has(false){ + } + ~option_without_value(){} + + bool has_value() const { return false; } + + bool set(){ + has=true; + return true; + } + + bool set(const std::string &){ + return false; + } + + bool has_set() const { + return has; + } + + bool valid() const{ + return true; + } + + bool must() const{ + return false; + } + + const std::string &name() const{ + return nam; + } + + char short_name() const{ + return snam; + } + + const std::string &description() const { + return desc; + } + + std::string short_description() const{ + return "--"+nam; + } + + private: + std::string nam; + char snam; + std::string desc; + bool has; + }; + + template + class option_with_value : public option_base { + public: + option_with_value(const std::string &name, + char short_name, + bool need, + const T &def, + const std::string &desc) + : nam(name), snam(short_name), need(need), has(false) + , def(def), actual(def) { + this->desc=full_description(desc); + } + ~option_with_value(){} + + const T &get() const { + return actual; + } + + bool has_value() const { return true; } + + bool set(){ + return false; + } + + bool set(const std::string &value){ + try{ + actual=read(value); + has=true; + } + catch(const std::exception &e){ + return false; + } + return true; + } + + bool has_set() const{ + return has; + } + + bool valid() const{ + if (need && !has) return false; + return true; + } + + bool must() const{ + return need; + } + + const std::string &name() const{ + return nam; + } + + char short_name() const{ + return snam; + } + + const std::string &description() const { + return desc; + } + + std::string short_description() const{ + return "--"+nam+"="+detail::readable_typename(); + } + + protected: + std::string full_description(const std::string &desc){ + return + desc+" ("+detail::readable_typename()+ + (need?"":" [="+detail::default_value(def)+"]") + +")"; + } + + virtual T read(const std::string &s)=0; + + std::string nam; + char snam; + bool need; + std::string desc; + + bool has; + T def; + T actual; + }; + + template + class option_with_value_with_reader : public option_with_value { + public: + option_with_value_with_reader(const std::string &name, + char short_name, + bool need, + const T def, + const std::string &desc, + F reader) + : option_with_value(name, short_name, need, def, desc), reader(reader){ + } + + private: + T read(const std::string &s){ + return reader(s); + } + + F reader; + }; + + std::map options; + std::vector ordered; + std::string ftr; + + std::string prog_name; + std::vector others; + + std::vector errors; +}; + +} // cmdline diff --git a/debian/changelog b/debian/changelog new file mode 100644 index 0000000000000000000000000000000000000000..618e44d0e8561eb81494917ea455ed8a0532aaee --- /dev/null +++ b/debian/changelog @@ -0,0 +1,36 @@ +deepin-ocr (1.5.1) unstable; urgency=medium + + *remove env kwayland-shell + + -- Liu zheng Wed, 06 Nov 2024 15:33:24 +0800 + +deepin-ocr (1.5.0) unstable; urgency=medium + + * adapt treeland + + -- Liu zheng Tue, 22 Oct 2024 20:32:59 +0800 + +deepin-ocr (1.1.2) unstable; urgency=medium + + * New version 1.1.2. + + -- xiepengfei Wed, 16 Aug 2023 11:43:41 +0800 + +deepin-ocr (1.1.1) unstable; urgency=medium + + * New version 1.1.1. + + -- xiepengfei Thur, 13 Apr 2023 15:08:32 +0800 + +deepin-ocr (1.1.0) unstable; urgency=medium + + * Use dtkocr instead of PaddleOCR-NCNN + * Add language change + + -- TagBuilder Fri, 10 Mar 2023 10:16:55 +0800 + +deepin-ocr (1.0) unstable; urgency=medium + + * Pre-release for deepin-ocr 1.0 + + -- TagBuilder Fri, 10 May 2021 14:20:26 +0000 diff --git a/debian/compat b/debian/compat new file mode 100644 index 0000000000000000000000000000000000000000..b4de3947675361a7770d29b8982c407b0ec6b2a0 --- /dev/null +++ b/debian/compat @@ -0,0 +1 @@ +11 diff --git a/debian/control b/debian/control new file mode 100644 index 0000000000000000000000000000000000000000..de5c69e0a63c1f7b08de4faef3f33b7e84b175c2 --- /dev/null +++ b/debian/control @@ -0,0 +1,13 @@ +Source: deepin-ocr +Section: utils +Priority: optional +Maintainer: Deepin Packages Builder +Build-Depends: debhelper (>= 11), cmake, qtbase5-dev, pkg-config, qttools5-dev-tools, qttools5-dev, libdtkocr-dev +Standards-Version: 4.1.3 +Homepage: http://www.deepin.org/ + +Package: ocr-cmd +Architecture: any +Depends: ${shlibs:Depends}, ${misc:Depends} +Description: Ocr for cmd + Ocr is a text recognition software. diff --git a/debian/copyright b/debian/copyright new file mode 100644 index 0000000000000000000000000000000000000000..8470a51ab99a0f18604916652b41c1b57ac116dc --- /dev/null +++ b/debian/copyright @@ -0,0 +1,73 @@ +Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ +Upstream-Name: deepin-ocr +Upstream-Contact: https://github.com/linuxdeepin/deepin-ocr/issues +Source: https://github.com/linuxdeepin/deepin-ocr + +Files: * +Copyright: 2022 Deepin.Inc +License: GPL-3+ + +Files: debian/* +Copyright: 2022 Deepin.Inc +License: Expat + +Files: 3rdparty/stub_linux/* +Copyright: 2020 Zhang Yu +License: MIT + +License: GPL-3+ + This package is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + . + This package is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + . + You should have received a copy of the GNU General Public License + along with this program. If not, see + . + On Debian systems, the complete text of the GNU General + Public License version 3 can be found in "/usr/share/common-licenses/GPL-3". + +License: Expat + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + . + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + . + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFT + +License: MIT + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the + "Software"), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sub license, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + . + The above copyright notice and this permission notice (including the + next paragraph) shall be included in all copies or substantial portions + of the Software. + . + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/debian/files b/debian/files new file mode 100644 index 0000000000000000000000000000000000000000..73cf046bef21c33796dd3210514c206cd4f20010 --- /dev/null +++ b/debian/files @@ -0,0 +1,3 @@ +deepin-ocr_1.5.1_amd64.buildinfo utils optional +ocr-cmd-dbgsym_1.5.1_amd64.deb debug optional automatic=yes +ocr-cmd_1.5.1_amd64.deb utils optional diff --git a/debian/rules b/debian/rules new file mode 100755 index 0000000000000000000000000000000000000000..61707a86524dffc1747ee30cfba52c5651d4afb5 --- /dev/null +++ b/debian/rules @@ -0,0 +1,12 @@ +#!/usr/bin/make -f + +export QT_SELECT=5 +include /usr/share/dpkg/default.mk + +%: + dh $@ + + +override_dh_auto_configure: + dh_auto_configure -- VERSION=$(VERSION) LIB_INSTALL_DIR=/usr/lib/$(DEB_HOST_MULTIARCH) DEFINES+="VERSION=$(DEB_VERSION_UPSTREAM)" + diff --git a/debian/source/format b/debian/source/format new file mode 100644 index 0000000000000000000000000000000000000000..89ae9db8f88b823b6a7eabf55e203658739da122 --- /dev/null +++ b/debian/source/format @@ -0,0 +1 @@ +3.0 (native) diff --git a/main.cpp b/main.cpp new file mode 100644 index 0000000000000000000000000000000000000000..965bd57b3d2c891a3d0558d9da95bc27df3052ef --- /dev/null +++ b/main.cpp @@ -0,0 +1,104 @@ +// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: LGPL-3.0-or-later + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "cmdline.h" + +DOCR_USE_NAMESPACE +using namespace std; +int main(int argc, char *argv[]) +{ + cmdline::parser a; + + a.add("input", 'i', "input image", true, ""); + a.add("output", 'o', "output json", false, ""); + a.add("language", 'l', "select language", false, "zh-Hans_en", + cmdline::oneof("zh-Hans_en", "zh-Hant_en", "en")); + a.add("hardware", 'w', "use vulkan hardware", false, false); + a.set_program_name("ocr-cmd"); + + bool ok=a.parse(argc, argv); + + if (argc==1){ + cerr << a.usage(); + return 0; + } + + if (!ok){ + cerr << a.error() << endl << a.usage(); + return 0; + } + + QFileInfo info(QString::fromStdString(a.get("input"))); + if (a.get("input") == "" || !info.exists()) { + return 0; + } + + Dtk::Ocr::DOcr ocr; + ocr.loadDefaultPlugin(); + + if (a.get("hardware")) { + ocr.setUseHardware({{Dtk::Ocr::GPU_Vulkan, 0}}); + } + + ocr.setLanguage(QString::fromStdString(a.get("language"))); + ocr.setImageFile(QString::fromStdString(a.get("input"))); + + bool analyzeSuccess = ocr.analyze(); + + // 7.Get the recognition result + if (analyzeSuccess) { + QList boxs = ocr.textBoxes(); + QJsonArray textArray; + QJsonArray pointsArray; + QString result = ocr.simpleResult(); + QStringList list = result.split("\n", QString::SkipEmptyParts); + for (int i = 0; i < boxs.size(); i++) { + QStringList stringList; + TextBox box = boxs.at(i); + for (const QPointF &point : box.points) { + stringList.append(QString("%1, %2").arg(point.x()).arg(point.y())); + } + pointsArray.append(QJsonArray::fromStringList(stringList)); + textArray.append(pointsArray); + QJsonArray resultArray; + resultArray.append(list.at(i)); + textArray.append(resultArray); + } + + QJsonDocument doc; + doc.setArray(textArray); + + QString outFile = "./ocr.json"; + if (a.get("output") != "") { + outFile = QString::fromStdString(a.get("output")); + } + qDebug() << outFile; + QFile file(outFile); + if (!file.open(QIODevice::WriteOnly | QIODevice::Truncate)) { + qWarning() << "can't open error!"; + qInfo() << textArray; + return 0; + } + QTextStream stream(&file); + stream.setCodec("UTF-8"); + stream << doc.toJson(); + file.close(); + } else { + qInfo() << "OCR analyze have no result"; + } + + return 0; +}