mirror of
https://github.com/HIllya51/LunaTranslator.git
synced 2024-12-26 23:24:13 +08:00
many (#1134)
This commit is contained in:
parent
b9697820c5
commit
7cd7c77848
6
.gitignore
vendored
6
.gitignore
vendored
@ -34,3 +34,9 @@ src/run3732.bat
|
||||
src/plugins/builds
|
||||
src/plugins/libs/webview2
|
||||
src/plugins/.vscode/settings.json
|
||||
src/plugins/libs/opencv-static/windows-x86
|
||||
src/plugins/libs/opencv-static/windows-x64
|
||||
src/plugins/libs/onnxruntime-static/windows-x86
|
||||
src/plugins/libs/onnxruntime-static/windows-x64
|
||||
src/plugins/libs/opencv-static.zip
|
||||
src/plugins/libs/onnxruntime-static.zip
|
||||
|
3
.gitmodules
vendored
3
.gitmodules
vendored
@ -13,3 +13,6 @@
|
||||
[submodule "src/plugins/libs/Detours"]
|
||||
path = src/plugins/libs/Detours
|
||||
url = https://github.com/microsoft/Detours
|
||||
[submodule "src/plugins/libs/Clipper2"]
|
||||
path = src/plugins/libs/Clipper2
|
||||
url = https://github.com/AngusJohnson/Clipper2
|
||||
|
@ -20,7 +20,7 @@
|
||||
- **HOOK** 支持使用[HOOK](https://github.com/HIllya51/LunaHook)方式获取文本,支持使用特殊码,支持自动保存游戏及HOOK、自动加载HOOK等。对于部分引擎,还支持内嵌翻译。对于不支持或支持不好的游戏,请[提交反馈](https://lunatranslator.org/Resource/game_support)
|
||||
|
||||
|
||||
- **OCR** 支持 **离线OCR** ( 除[内置OCR引擎](https://github.com/HIllya51/LunaOCR)外,还支持WindowsOCR、Tessearact5、manga-ocr、WeChat/QQ OCR ) 和 **在线OCR** ( 百度、有道、飞书、讯飞、Google Lens、Google Cloud Vision、docsumo、ocrspace、Gemini、ChatGPT兼容接口 )
|
||||
- **OCR** 支持 **离线OCR** ( 除内置OCR引擎外,还支持WindowsOCR、Tessearact5、manga-ocr、WeChat/QQ OCR ) 和 **在线OCR** ( 百度、有道、飞书、讯飞、Google Lens、Google Cloud Vision、docsumo、ocrspace、Gemini、ChatGPT兼容接口 )
|
||||
|
||||
- **剪贴板** 支持从剪贴板中获取文本进行翻译
|
||||
|
||||
|
@ -20,7 +20,7 @@
|
||||
|
||||
- **HOOK** Supports obtaining text using [HOOK](https://github.com/HIllya51/LunaHook) methods, supports the use of special codes, supports automatic saving of games and HOOKs, automatic loading of HOOKs, etc. For some engines, it also supports embedded translation. For games that are not supported or not well supported, please [submit feedback](https://lunatranslator.org/Resource/game_support)
|
||||
|
||||
- **OCR** supports **offline OCR** (in addition to the [built-in OCR engine](https://github.com/HIllya51/LunaOCR), it also supports WindowsOCR, Tesseract5, manga-ocr, WeChat/QQ OCR) and **online OCR** (Baidu, Youdao, Feishu, iFlytek, Google Lens, Google Cloud Vision, docsumo, ocrspace, Gemini, ChatGPT-compatible interfaces).
|
||||
- **OCR** supports **offline OCR** (in addition to the built-in OCR engine, it also supports WindowsOCR, Tesseract5, manga-ocr, WeChat/QQ OCR) and **online OCR** (Baidu, Youdao, Feishu, iFlytek, Google Lens, Google Cloud Vision, docsumo, ocrspace, Gemini, ChatGPT-compatible interfaces).
|
||||
|
||||
- **Clipboard** Supports obtaining text from the clipboard for translation
|
||||
|
||||
|
@ -21,7 +21,7 @@
|
||||
- **HOOK** Поддерживает получение текста с использованием метода [HOOK](https://github.com/HIllya51/LunaHook), поддерживает использование специальных кодов, поддерживает автоматическое сохранение игр и HOOK, автоматическое загрузка HOOK и т.д. Для некоторых движков также поддерживается встроенная трансляция. Для игр, которые не поддерживаются или плохо поддерживаются, пожалуйста, [отправьте обратную связь](https://lunatranslator.org/Resource/game_support)
|
||||
|
||||
|
||||
- **OCR** поддерживает **офлайн OCR** (помимо [встроенного OCR-движка](https://github.com/HIllya51/LunaOCR), также поддерживает WindowsOCR, Tesseract5, manga-ocr, WeChat/QQ OCR) и **онлайн OCR** (Baidu, Youdao, Feishu, iFlytek, Google Lens, Google Cloud Vision, docsumo, ocrspace, Gemini, совместимые интерфейсы ChatGPT).
|
||||
- **OCR** поддерживает **офлайн OCR** (помимо встроенного OCR-движка, также поддерживает WindowsOCR, Tesseract5, manga-ocr, WeChat/QQ OCR) и **онлайн OCR** (Baidu, Youdao, Feishu, iFlytek, Google Lens, Google Cloud Vision, docsumo, ocrspace, Gemini, совместимые интерфейсы ChatGPT).
|
||||
|
||||
- **Буфер обмена** Поддерживает получение текста из буфера обмена для перевода
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
import os, zipfile
|
||||
from myutils.utils import dynamiclink
|
||||
from myutils.config import _TR, getlang_inner2show
|
||||
from myutils.config import _TR, getlang_inner2show, globalconfig
|
||||
from ocrengines.baseocrclass import baseocr
|
||||
from ctypes import (
|
||||
CDLL,
|
||||
@ -12,6 +12,9 @@ from ctypes import (
|
||||
Structure,
|
||||
pointer,
|
||||
c_char_p,
|
||||
c_wchar_p,
|
||||
c_bool,
|
||||
CFUNCTYPE,
|
||||
)
|
||||
import os
|
||||
import gobject, functools
|
||||
@ -40,69 +43,42 @@ class ocrwrapper:
|
||||
self.pOcrObj = None
|
||||
self.__OcrInit(det, rec, key)
|
||||
|
||||
def __OcrInit(self, szDetModel, szRecModel, szKeyPath, szClsModel="", nThreads=4):
|
||||
def __OcrInit(self, szDetModel, szRecModel, szKeyPath, nThreads=4):
|
||||
|
||||
_OcrInit = self.dll.OcrInit
|
||||
_OcrInit.restype = c_void_p
|
||||
self.pOcrObj = _OcrInit(
|
||||
c_char_p(szDetModel.encode("utf8")),
|
||||
c_char_p(szClsModel.encode("utf8")),
|
||||
c_char_p(szRecModel.encode("utf8")),
|
||||
c_char_p(szKeyPath.encode("utf8")),
|
||||
nThreads,
|
||||
)
|
||||
_OcrInit.argtypes = c_wchar_p, c_wchar_p, c_wchar_p, c_int32
|
||||
self.pOcrObj = _OcrInit(szDetModel, szRecModel, szKeyPath, nThreads)
|
||||
|
||||
def __OcrDetect(self, data: bytes, rotate: bool):
|
||||
|
||||
texts = []
|
||||
pss = []
|
||||
|
||||
def cb(ps: ocrpoints, text: bytes):
|
||||
pss.append((ps.x1, ps.y1, ps.x2, ps.y2, ps.x3, ps.y3, ps.x4, ps.y4))
|
||||
texts.append(text.decode("utf8"))
|
||||
|
||||
def __OcrDetect(self, data: bytes, angle):
|
||||
_OcrDetect = self.dll.OcrDetect
|
||||
_OcrDetect.argtypes = (
|
||||
c_void_p,
|
||||
c_void_p,
|
||||
c_size_t,
|
||||
c_int32,
|
||||
POINTER(c_int32),
|
||||
POINTER(POINTER(ocrpoints)),
|
||||
POINTER(POINTER(c_char_p)),
|
||||
c_bool,
|
||||
c_void_p,
|
||||
)
|
||||
|
||||
_OcrFreeptr = self.dll.OcrFreeptr
|
||||
_OcrFreeptr.argtypes = c_int32, c_void_p, c_void_p
|
||||
|
||||
num = c_int32()
|
||||
ps = POINTER(ocrpoints)()
|
||||
chars = POINTER(c_char_p)()
|
||||
res = _OcrDetect(
|
||||
_OcrDetect(
|
||||
self.pOcrObj,
|
||||
data,
|
||||
len(data),
|
||||
c_int32(angle),
|
||||
pointer(num),
|
||||
pointer(ps),
|
||||
pointer(chars),
|
||||
rotate,
|
||||
CFUNCTYPE(None, ocrpoints, c_char_p)(cb),
|
||||
)
|
||||
if not res:
|
||||
return [], []
|
||||
texts = []
|
||||
pss = []
|
||||
for i in range((num.value)):
|
||||
texts.append(chars[i].decode("utf8"))
|
||||
pss.append(
|
||||
(
|
||||
ps[i].x1,
|
||||
ps[i].y1,
|
||||
ps[i].x2,
|
||||
ps[i].y2,
|
||||
ps[i].x3,
|
||||
ps[i].y3,
|
||||
ps[i].x4,
|
||||
ps[i].y4,
|
||||
)
|
||||
)
|
||||
_OcrFreeptr(num, ps, chars)
|
||||
return pss, texts
|
||||
|
||||
def ocr(self, data, angle=0):
|
||||
def ocr(self, data, rotate=False):
|
||||
try:
|
||||
return self.__OcrDetect(data, angle)
|
||||
return self.__OcrDetect(data, rotate)
|
||||
except:
|
||||
print_exc()
|
||||
return [], []
|
||||
@ -226,6 +202,6 @@ class OCR(baseocr):
|
||||
|
||||
pss, texts = self._ocr.ocr(
|
||||
imagebinary,
|
||||
0,
|
||||
globalconfig["verticalocr"] == 1,
|
||||
)
|
||||
return {"box": pss, "text": texts}
|
||||
|
@ -29,7 +29,6 @@ mylinks = {
|
||||
"ja.zip": "https://github.com/test123456654321/RESOURCES/releases/download/ocr_models/ja.zip",
|
||||
},
|
||||
"mecab.zip": "https://github.com/HIllya51/RESOURCES/releases/download/common/mecab.zip",
|
||||
"ocr.zip": "https://github.com/HIllya51/RESOURCES/releases/download/common/ocr.zip",
|
||||
"magpie.zip": "https://github.com/HIllya51/RESOURCES/releases/download/common/magpie.zip",
|
||||
"themes.zip": "https://github.com/HIllya51/RESOURCES/releases/download/common/themes.zip",
|
||||
}
|
||||
@ -121,8 +120,6 @@ def downloadcommon():
|
||||
downloadlr()
|
||||
subprocess.run(f"curl -LO {mylinks['mecab.zip']}")
|
||||
subprocess.run(f"7z x mecab.zip -oALL")
|
||||
subprocess.run(f"curl -LO {mylinks['ocr.zip']}")
|
||||
subprocess.run(f"7z x ocr.zip -oALL")
|
||||
subprocess.run(f"curl -LO {mylinks['magpie.zip']}")
|
||||
subprocess.run(f"7z x magpie.zip -oALL")
|
||||
|
||||
|
@ -29,7 +29,7 @@ include(generate_product_version)
|
||||
|
||||
set(VERSION_MAJOR 5)
|
||||
set(VERSION_MINOR 55)
|
||||
set(VERSION_PATCH 2)
|
||||
set(VERSION_PATCH 3)
|
||||
|
||||
add_library(pch pch.cpp)
|
||||
target_precompile_headers(pch PUBLIC pch.h)
|
||||
@ -42,3 +42,4 @@ add_subdirectory(hookmagpie)
|
||||
add_subdirectory(shareddllproxy)
|
||||
add_subdirectory(applicationloopbackaudio)
|
||||
add_subdirectory(wcocr)
|
||||
add_subdirectory(LunaOCR)
|
49
src/plugins/LunaOCR/CMakeLists.txt
Normal file
49
src/plugins/LunaOCR/CMakeLists.txt
Normal file
@ -0,0 +1,49 @@
|
||||
project(LunaOCR)
|
||||
|
||||
generate_product_version(
|
||||
versioninfo
|
||||
NAME "LunaTranslator OCR"
|
||||
COMPANY_COPYRIGHT "HIllya51 (C) 2024"
|
||||
VERSION_MAJOR ${VERSION_MAJOR}
|
||||
VERSION_MINOR ${VERSION_MINOR}
|
||||
VERSION_PATCH ${VERSION_PATCH}
|
||||
)
|
||||
|
||||
|
||||
set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")
|
||||
|
||||
include(${CMAKE_CURRENT_SOURCE_DIR}/../libs/onnxruntime-static/OnnxRuntimeWrapper.cmake)
|
||||
|
||||
find_package(OnnxRuntime REQUIRED)
|
||||
if (OnnxRuntime_FOUND)
|
||||
message(STATUS "OnnxRuntime_LIBS: ${OnnxRuntime_LIBS}")
|
||||
message(STATUS "OnnxRuntime_INCLUDE_DIRS: ${OnnxRuntime_INCLUDE_DIRS}")
|
||||
else ()
|
||||
message(FATAL_ERROR "onnxruntime Not Found!")
|
||||
endif (OnnxRuntime_FOUND)
|
||||
|
||||
# OpenCV
|
||||
set(BUILD_SHARED_LIBS false)
|
||||
if (CMAKE_CL_64)
|
||||
set(OpenCV_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../libs/opencv-static/windows-x64")
|
||||
link_directories(${OpenCV_DIR}/x64/vc16/staticlib)
|
||||
include(${OpenCV_DIR}/x64/vc16/staticlib/OpenCVConfig.cmake)
|
||||
|
||||
else ()
|
||||
set(OpenCV_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../libs/opencv-static/windows-x86")
|
||||
link_directories(${OpenCV_DIR}/x86/vc16/staticlib)
|
||||
include(${OpenCV_DIR}/x86/vc16/staticlib/OpenCVConfig.cmake)
|
||||
endif ()
|
||||
|
||||
set(OpenCV_LIBS opencv_core;opencv_features2d;opencv_flann;opencv_highgui;opencv_imgcodecs;opencv_imgproc;opencv_photo;opencv_video)
|
||||
|
||||
add_library(LunaOCR SHARED OCR.cpp ${versioninfo})
|
||||
target_link_libraries(LunaOCR ${OnnxRuntime_LIBS} ${OpenCV_LIBS} Clipper2Lib)
|
||||
target_include_directories(LunaOCR PRIVATE ${OpenCV_DIR}/include)
|
||||
target_precompile_headers(LunaOCR REUSE_FROM pch)
|
||||
|
||||
if(${CMAKE_SIZEOF_VOID_P} EQUAL 8)
|
||||
set_target_properties(LunaOCR PROPERTIES OUTPUT_NAME "LunaOCR64")
|
||||
else()
|
||||
set_target_properties(LunaOCR PROPERTIES OUTPUT_NAME "LunaOCR32")
|
||||
endif()
|
702
src/plugins/LunaOCR/OCR.cpp
Normal file
702
src/plugins/LunaOCR/OCR.cpp
Normal file
@ -0,0 +1,702 @@
|
||||
#include <onnxruntime/core/session/onnxruntime_cxx_api.h>
|
||||
#include <opencv2/opencv.hpp>
|
||||
#include <opencv2/imgproc.hpp>
|
||||
#include <opencv2/imgcodecs.hpp>
|
||||
#include <clipper2/clipper.h>
|
||||
typedef std::vector<cv::Point> TextBox;
|
||||
typedef std::string TextLine;
|
||||
typedef std::pair<TextBox, TextLine> TextBlock;
|
||||
|
||||
struct ScaleParam {
|
||||
int srcWidth;
|
||||
int srcHeight;
|
||||
int dstWidth;
|
||||
int dstHeight;
|
||||
float ratioWidth;
|
||||
float ratioHeight;
|
||||
};
|
||||
#define getinputoutputNames(Func1, vec, Func2) \
|
||||
do \
|
||||
{ \
|
||||
Ort::AllocatorWithDefaultOptions allocator; \
|
||||
const size_t numInputNodes = session->Func1(); \
|
||||
\
|
||||
vec.reserve(numInputNodes); \
|
||||
std::vector<int64_t> input_node_dims; \
|
||||
\
|
||||
for (size_t i = 0; i < numInputNodes; i++) \
|
||||
{ \
|
||||
auto inputName = session->Func2(i, allocator); \
|
||||
vec.push_back(std::move(inputName)); \
|
||||
} \
|
||||
} while (0);
|
||||
|
||||
class CommonOnnxModel
|
||||
{
|
||||
std::vector<Ort::AllocatedStringPtr> inputNamesPtr;
|
||||
std::vector<Ort::AllocatedStringPtr> outputNamesPtr;
|
||||
std::unique_ptr<Ort::Session> session;
|
||||
Ort::Env env = Ort::Env(ORT_LOGGING_LEVEL_ERROR);
|
||||
Ort::SessionOptions sessionOptions = Ort::SessionOptions();
|
||||
const std::array<float, 3> meanValues;
|
||||
const std::array<float, 3> normValues;
|
||||
|
||||
std::vector<float> substractMeanNormalize(cv::Mat &src, const float *meanVals, const float *normVals)
|
||||
{
|
||||
auto inputTensorSize = src.cols * src.rows * src.channels();
|
||||
std::vector<float> inputTensorValues(inputTensorSize);
|
||||
size_t numChannels = src.channels();
|
||||
size_t imageSize = src.cols * src.rows;
|
||||
|
||||
for (size_t pid = 0; pid < imageSize; pid++)
|
||||
{
|
||||
for (size_t ch = 0; ch < numChannels; ++ch)
|
||||
{
|
||||
float data = (float)(src.data[pid * numChannels + ch] * normVals[ch] - meanVals[ch] * normVals[ch]);
|
||||
inputTensorValues[ch * imageSize + pid] = data;
|
||||
}
|
||||
}
|
||||
return inputTensorValues;
|
||||
}
|
||||
|
||||
void setNumThread(int numOfThread)
|
||||
{
|
||||
sessionOptions.SetInterOpNumThreads(numOfThread);
|
||||
sessionOptions.SetGraphOptimizationLevel(GraphOptimizationLevel::ORT_ENABLE_EXTENDED);
|
||||
}
|
||||
|
||||
public:
|
||||
std::pair<std::vector<float>, std::vector<int64_t>> RunSession(cv::Mat src)
|
||||
{
|
||||
auto inputTensorValues = substractMeanNormalize(src, meanValues.data(), normValues.data());
|
||||
std::array<int64_t, 4> inputShape{1, src.channels(), src.rows, src.cols};
|
||||
auto memoryInfo = Ort::MemoryInfo::CreateCpu(OrtDeviceAllocator, OrtMemTypeCPU);
|
||||
Ort::Value inputTensor = Ort::Value::CreateTensor<float>(memoryInfo, inputTensorValues.data(),
|
||||
inputTensorValues.size(), inputShape.data(),
|
||||
inputShape.size());
|
||||
assert(inputTensor.IsTensor());
|
||||
std::vector<const char *> inputNames = {inputNamesPtr.data()->get()};
|
||||
std::vector<const char *> outputNames = {outputNamesPtr.data()->get()};
|
||||
auto outputTensor = session->Run(Ort::RunOptions{nullptr}, inputNames.data(), &inputTensor,
|
||||
inputNames.size(), outputNames.data(), outputNames.size());
|
||||
assert(outputTensor.size() == 1 && outputTensor.front().IsTensor());
|
||||
std::vector<int64_t> outputShape = outputTensor[0].GetTensorTypeAndShapeInfo().GetShape();
|
||||
auto outputCount = outputTensor.front().GetTensorTypeAndShapeInfo().GetElementCount();
|
||||
float *floatArray = outputTensor.front().GetTensorMutableData<float>();
|
||||
std::vector<float> outputData(floatArray, floatArray + outputCount);
|
||||
return {outputData, outputShape};
|
||||
}
|
||||
CommonOnnxModel(const std::wstring &path, const std::array<float, 3> &_meanValues, const std::array<float, 3> &_normValues, int numOfThread = 4) : meanValues(_meanValues), normValues(_normValues)
|
||||
{
|
||||
setNumThread(numOfThread);
|
||||
session = std::make_unique<Ort::Session>(env, path.c_str(), sessionOptions);
|
||||
getinputoutputNames(GetInputCount, inputNamesPtr, GetInputNameAllocated);
|
||||
getinputoutputNames(GetOutputCount, outputNamesPtr, GetOutputNameAllocated);
|
||||
}
|
||||
};
|
||||
|
||||
class CrnnNet:public CommonOnnxModel{
|
||||
public:
|
||||
CrnnNet(const std::wstring &pathStr, const std::wstring &keysPath, int numOfThread);
|
||||
std::vector<TextLine> getTextLines(std::vector<cv::Mat> &partImg);
|
||||
|
||||
private:
|
||||
const float meanValues[3] = {127.5, 127.5, 127.5};
|
||||
const float normValues[3] = {1.0 / 127.5, 1.0 / 127.5, 1.0 / 127.5};
|
||||
const int dstHeight = 48;
|
||||
|
||||
std::vector<std::string> keys;
|
||||
|
||||
TextLine scoreToTextLine(const std::vector<float> &outputData, size_t h, size_t w);
|
||||
|
||||
TextLine getTextLine(const cv::Mat &src);
|
||||
};
|
||||
|
||||
class DbNet:public CommonOnnxModel{
|
||||
public:
|
||||
DbNet(const std::wstring &pathStr, int numOfThread);
|
||||
std::vector<TextBox> getTextBoxes(cv::Mat &src, ScaleParam &s, float boxScoreThresh,
|
||||
float boxThresh, float unClipRatio);
|
||||
|
||||
private:
|
||||
const float meanValues[3] = {0.485 * 255, 0.456 * 255, 0.406 * 255};
|
||||
const float normValues[3] = {1.0 / 0.229 / 255.0, 1.0 / 0.224 / 255.0, 1.0 / 0.225 / 255.0};
|
||||
};
|
||||
|
||||
//onnxruntime init windows
|
||||
ScaleParam getScaleParam(cv::Mat &src, const float scale) {
|
||||
int srcWidth = src.cols;
|
||||
int srcHeight = src.rows;
|
||||
int dstWidth = int((float) srcWidth * scale);
|
||||
int dstHeight = int((float) srcHeight * scale);
|
||||
if (dstWidth % 32 != 0) {
|
||||
dstWidth = (dstWidth / 32 - 1) * 32;
|
||||
dstWidth = (std::max)(dstWidth, 32);
|
||||
}
|
||||
if (dstHeight % 32 != 0) {
|
||||
dstHeight = (dstHeight / 32 - 1) * 32;
|
||||
dstHeight = (std::max)(dstHeight, 32);
|
||||
}
|
||||
float scaleWidth = (float) dstWidth / (float) srcWidth;
|
||||
float scaleHeight = (float) dstHeight / (float) srcHeight;
|
||||
return {srcWidth, srcHeight, dstWidth, dstHeight, scaleWidth, scaleHeight};
|
||||
}
|
||||
|
||||
ScaleParam getScaleParam(cv::Mat &src, const int targetSize) {
|
||||
int srcWidth, srcHeight, dstWidth, dstHeight;
|
||||
srcWidth = dstWidth = src.cols;
|
||||
srcHeight = dstHeight = src.rows;
|
||||
|
||||
float ratio = 1.f;
|
||||
if (srcWidth > srcHeight) {
|
||||
ratio = float(targetSize) / float(srcWidth);
|
||||
} else {
|
||||
ratio = float(targetSize) / float(srcHeight);
|
||||
}
|
||||
dstWidth = int(float(srcWidth) * ratio);
|
||||
dstHeight = int(float(srcHeight) * ratio);
|
||||
if (dstWidth % 32 != 0) {
|
||||
dstWidth = (dstWidth / 32) * 32;
|
||||
dstWidth = (std::max)(dstWidth, 32);
|
||||
}
|
||||
if (dstHeight % 32 != 0) {
|
||||
dstHeight = (dstHeight / 32) * 32;
|
||||
dstHeight = (std::max)(dstHeight, 32);
|
||||
}
|
||||
float ratioWidth = (float) dstWidth / (float) srcWidth;
|
||||
float ratioHeight = (float) dstHeight / (float) srcHeight;
|
||||
return {srcWidth, srcHeight, dstWidth, dstHeight, ratioWidth, ratioHeight};
|
||||
}
|
||||
|
||||
std::vector<cv::Point2f> getBox(const cv::RotatedRect &rect) {
|
||||
cv::Point2f vertices[4];
|
||||
rect.points(vertices);
|
||||
//std::vector<cv::Point2f> ret(4);
|
||||
std::vector<cv::Point2f> ret2(vertices, vertices + sizeof(vertices) / sizeof(vertices[0]));
|
||||
//memcpy(vertices, &ret[0], ret.size() * sizeof(ret[0]));
|
||||
return ret2;
|
||||
}
|
||||
|
||||
cv::Mat getRotateCropImage(const cv::Mat &src, std::vector<cv::Point> box) {
|
||||
cv::Mat image;
|
||||
src.copyTo(image);
|
||||
std::vector<cv::Point> points = box;
|
||||
|
||||
int collectX[4] = {box[0].x, box[1].x, box[2].x, box[3].x};
|
||||
int collectY[4] = {box[0].y, box[1].y, box[2].y, box[3].y};
|
||||
int left = int(*std::min_element(collectX, collectX + 4));
|
||||
int right = int(*std::max_element(collectX, collectX + 4));
|
||||
int top = int(*std::min_element(collectY, collectY + 4));
|
||||
int bottom = int(*std::max_element(collectY, collectY + 4));
|
||||
|
||||
cv::Mat imgCrop;
|
||||
image(cv::Rect(left, top, right - left, bottom - top)).copyTo(imgCrop);
|
||||
|
||||
for (auto &point: points) {
|
||||
point.x -= left;
|
||||
point.y -= top;
|
||||
}
|
||||
|
||||
int imgCropWidth = int(sqrt(pow(points[0].x - points[1].x, 2) +
|
||||
pow(points[0].y - points[1].y, 2)));
|
||||
int imgCropHeight = int(sqrt(pow(points[0].x - points[3].x, 2) +
|
||||
pow(points[0].y - points[3].y, 2)));
|
||||
|
||||
cv::Point2f ptsDst[4];
|
||||
ptsDst[0] = cv::Point2f(0., 0.);
|
||||
ptsDst[1] = cv::Point2f(imgCropWidth, 0.);
|
||||
ptsDst[2] = cv::Point2f(imgCropWidth, imgCropHeight);
|
||||
ptsDst[3] = cv::Point2f(0.f, imgCropHeight);
|
||||
|
||||
cv::Point2f ptsSrc[4];
|
||||
ptsSrc[0] = cv::Point2f(points[0].x, points[0].y);
|
||||
ptsSrc[1] = cv::Point2f(points[1].x, points[1].y);
|
||||
ptsSrc[2] = cv::Point2f(points[2].x, points[2].y);
|
||||
ptsSrc[3] = cv::Point2f(points[3].x, points[3].y);
|
||||
|
||||
cv::Mat M = cv::getPerspectiveTransform(ptsSrc, ptsDst);
|
||||
|
||||
cv::Mat partImg;
|
||||
cv::warpPerspective(imgCrop, partImg, M,
|
||||
cv::Size(imgCropWidth, imgCropHeight),
|
||||
cv::BORDER_REPLICATE);
|
||||
|
||||
// if (float(partImg.rows) >= float(partImg.cols) * 1.5) {
|
||||
// cv::Mat srcCopy = cv::Mat(partImg.rows, partImg.cols, partImg.depth());
|
||||
// cv::transpose(partImg, srcCopy);
|
||||
// cv::flip(srcCopy, srcCopy, 0);
|
||||
// return srcCopy;
|
||||
// } else {
|
||||
// return partImg;
|
||||
// }
|
||||
|
||||
return partImg;
|
||||
}
|
||||
|
||||
bool cvPointCompare(const cv::Point &a, const cv::Point &b) {
|
||||
return a.x < b.x;
|
||||
}
|
||||
|
||||
std::vector<cv::Point2f> getMinBoxes(const cv::RotatedRect &boxRect, float &maxSideLen) {
|
||||
maxSideLen = std::max(boxRect.size.width, boxRect.size.height);
|
||||
std::vector<cv::Point2f> boxPoint = getBox(boxRect);
|
||||
std::sort(boxPoint.begin(), boxPoint.end(), cvPointCompare);
|
||||
int index1, index2, index3, index4;
|
||||
if (boxPoint[1].y > boxPoint[0].y) {
|
||||
index1 = 0;
|
||||
index4 = 1;
|
||||
} else {
|
||||
index1 = 1;
|
||||
index4 = 0;
|
||||
}
|
||||
if (boxPoint[3].y > boxPoint[2].y) {
|
||||
index2 = 2;
|
||||
index3 = 3;
|
||||
} else {
|
||||
index2 = 3;
|
||||
index3 = 2;
|
||||
}
|
||||
std::vector<cv::Point2f> minBox(4);
|
||||
minBox[0] = boxPoint[index1];
|
||||
minBox[1] = boxPoint[index2];
|
||||
minBox[2] = boxPoint[index3];
|
||||
minBox[3] = boxPoint[index4];
|
||||
return minBox;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline T clamp(T x, T min, T max)
|
||||
{
|
||||
if (x > max)
|
||||
return max;
|
||||
if (x < min)
|
||||
return min;
|
||||
return x;
|
||||
}
|
||||
float boxScoreFast(const std::vector<cv::Point2f> &boxes, const cv::Mat &pred) {
|
||||
int width = pred.cols;
|
||||
int height = pred.rows;
|
||||
|
||||
float arrayX[4] = {boxes[0].x, boxes[1].x, boxes[2].x, boxes[3].x};
|
||||
float arrayY[4] = {boxes[0].y, boxes[1].y, boxes[2].y, boxes[3].y};
|
||||
|
||||
int minX = clamp(int(std::floor(*(std::min_element(arrayX, arrayX + 4)))), 0, width - 1);
|
||||
int maxX = clamp(int(std::ceil(*(std::max_element(arrayX, arrayX + 4)))), 0, width - 1);
|
||||
int minY = clamp(int(std::floor(*(std::min_element(arrayY, arrayY + 4)))), 0, height - 1);
|
||||
int maxY = clamp(int(std::ceil(*(std::max_element(arrayY, arrayY + 4)))), 0, height - 1);
|
||||
|
||||
cv::Mat mask = cv::Mat::zeros(maxY - minY + 1, maxX - minX + 1, CV_8UC1);
|
||||
|
||||
cv::Point box[4];
|
||||
box[0] = cv::Point(int(boxes[0].x) - minX, int(boxes[0].y) - minY);
|
||||
box[1] = cv::Point(int(boxes[1].x) - minX, int(boxes[1].y) - minY);
|
||||
box[2] = cv::Point(int(boxes[2].x) - minX, int(boxes[2].y) - minY);
|
||||
box[3] = cv::Point(int(boxes[3].x) - minX, int(boxes[3].y) - minY);
|
||||
const cv::Point *pts[1] = {box};
|
||||
int npts[] = {4};
|
||||
cv::fillPoly(mask, pts, npts, 1, cv::Scalar(1));
|
||||
|
||||
cv::Mat croppedImg;
|
||||
pred(cv::Rect(minX, minY, maxX - minX + 1, maxY - minY + 1))
|
||||
.copyTo(croppedImg);
|
||||
|
||||
auto score = (float) cv::mean(croppedImg, mask)[0];
|
||||
return score;
|
||||
}
|
||||
|
||||
float getContourArea(const std::vector<cv::Point2f> &box, float unClipRatio) {
|
||||
size_t size = box.size();
|
||||
float area = 0.0f;
|
||||
float dist = 0.0f;
|
||||
for (size_t i = 0; i < size; i++) {
|
||||
area += box[i].x * box[(i + 1) % size].y -
|
||||
box[i].y * box[(i + 1) % size].x;
|
||||
dist += sqrtf((box[i].x - box[(i + 1) % size].x) *
|
||||
(box[i].x - box[(i + 1) % size].x) +
|
||||
(box[i].y - box[(i + 1) % size].y) *
|
||||
(box[i].y - box[(i + 1) % size].y));
|
||||
}
|
||||
area = fabs(float(area / 2.0));
|
||||
|
||||
return area * unClipRatio / dist;
|
||||
}
|
||||
|
||||
cv::RotatedRect unClip(std::vector<cv::Point2f> box, float unClipRatio) {
|
||||
float distance = getContourArea(box, unClipRatio);
|
||||
|
||||
Clipper2Lib::ClipperOffset offset;
|
||||
Clipper2Lib::Path64 p;
|
||||
p.push_back(Clipper2Lib::Point64(int(box[0].x), int(box[0].y)));
|
||||
p.push_back(Clipper2Lib::Point64(int(box[1].x), int(box[1].y)));
|
||||
p.push_back(Clipper2Lib::Point64(int(box[2].x), int(box[2].y)));
|
||||
p.push_back(Clipper2Lib::Point64(int(box[3].x), int(box[3].y)));
|
||||
offset.AddPath(p, Clipper2Lib::JoinType::Round, Clipper2Lib::EndType::Polygon);
|
||||
Clipper2Lib::Paths64 soln;
|
||||
offset.Execute(distance, soln);
|
||||
std::vector<cv::Point2f> points;
|
||||
|
||||
for (size_t j = 0; j < soln.size(); j++) {
|
||||
for (size_t i = 0; i < soln[soln.size() - 1].size(); i++) {
|
||||
points.emplace_back(cv::Point2f{float(soln[j][i].x), float(soln[j][i].y)});
|
||||
}
|
||||
}
|
||||
cv::RotatedRect res;
|
||||
if (points.empty()) {
|
||||
res = cv::RotatedRect(cv::Point2f(0, 0), cv::Size2f(1, 1), 0);
|
||||
} else {
|
||||
res = cv::minAreaRect(points);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
CrnnNet::CrnnNet(const std::wstring &pathStr, const std::wstring &keysPath, int numOfThread) : CommonOnnxModel(pathStr, {127.5, 127.5, 127.5}, {1.0 / 127.5, 1.0 / 127.5, 1.0 / 127.5}, numOfThread)
|
||||
{
|
||||
// load keys
|
||||
std::ifstream in(keysPath.c_str());
|
||||
std::string line;
|
||||
if (in)
|
||||
{
|
||||
while (getline(in, line))
|
||||
{ // line中不包括每行的换行符
|
||||
keys.push_back(line);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return;
|
||||
}
|
||||
keys.insert(keys.begin(), "#");
|
||||
keys.emplace_back(" ");
|
||||
}
|
||||
|
||||
template <class ForwardIterator>
|
||||
inline static size_t argmax(ForwardIterator first, ForwardIterator last)
|
||||
{
|
||||
return std::distance(first, std::max_element(first, last));
|
||||
}
|
||||
|
||||
TextLine CrnnNet::scoreToTextLine(const std::vector<float> &outputData, size_t h, size_t w)
|
||||
{
|
||||
auto keySize = keys.size();
|
||||
auto dataSize = outputData.size();
|
||||
std::string strRes;
|
||||
std::vector<float> scores;
|
||||
size_t lastIndex = 0;
|
||||
size_t maxIndex;
|
||||
float maxValue;
|
||||
|
||||
for (size_t i = 0; i < h; i++)
|
||||
{
|
||||
size_t start = i * w;
|
||||
size_t stop = (i + 1) * w;
|
||||
if (stop > dataSize - 1)
|
||||
{
|
||||
stop = (i + 1) * w - 1;
|
||||
}
|
||||
maxIndex = int(argmax(&outputData[start], &outputData[stop]));
|
||||
maxValue = float(*std::max_element(&outputData[start], &outputData[stop]));
|
||||
|
||||
if (maxIndex > 0 && maxIndex < keySize && (!(i > 0 && maxIndex == lastIndex)))
|
||||
{
|
||||
scores.emplace_back(maxValue);
|
||||
strRes.append(keys[maxIndex]);
|
||||
}
|
||||
lastIndex = maxIndex;
|
||||
}
|
||||
return strRes;
|
||||
}
|
||||
|
||||
TextLine CrnnNet::getTextLine(const cv::Mat &src)
|
||||
{
|
||||
float scale = (float)dstHeight / (float)src.rows;
|
||||
int dstWidth = int((float)src.cols * scale);
|
||||
cv::Mat srcResize;
|
||||
resize(src, srcResize, cv::Size(dstWidth, dstHeight));
|
||||
auto &&[outputData, outputShape] = RunSession(srcResize);
|
||||
return scoreToTextLine(outputData, outputShape[1], outputShape[2]);
|
||||
}
|
||||
|
||||
std::vector<TextLine> CrnnNet::getTextLines(std::vector<cv::Mat> &partImg)
|
||||
{
|
||||
int size = partImg.size();
|
||||
std::vector<TextLine> textLines(size);
|
||||
for (int i = 0; i < size; ++i)
|
||||
{
|
||||
TextLine textLine = getTextLine(partImg[i]);
|
||||
textLines[i] = textLine;
|
||||
}
|
||||
return textLines;
|
||||
}
|
||||
|
||||
DbNet::DbNet(const std::wstring &pathStr, int numOfThread) : CommonOnnxModel(pathStr, {0.485 * 255, 0.456 * 255, 0.406 * 255}, {1.0 / 0.229 / 255.0, 1.0 / 0.224 / 255.0, 1.0 / 0.225 / 255.0}, numOfThread)
|
||||
{
|
||||
}
|
||||
|
||||
std::vector<TextBox> findRsBoxes(const cv::Mat &predMat, const cv::Mat &dilateMat, ScaleParam &s,
|
||||
const float boxScoreThresh, const float unClipRatio)
|
||||
{
|
||||
const int longSideThresh = 3; // minBox 长边门限
|
||||
const int maxCandidates = 1000;
|
||||
|
||||
std::vector<std::vector<cv::Point>> contours;
|
||||
std::vector<cv::Vec4i> hierarchy;
|
||||
|
||||
cv::findContours(dilateMat, contours, hierarchy, cv::RETR_LIST,
|
||||
cv::CHAIN_APPROX_SIMPLE);
|
||||
|
||||
size_t numContours = contours.size() >= maxCandidates ? maxCandidates : contours.size();
|
||||
|
||||
std::vector<TextBox> rsBoxes;
|
||||
|
||||
for (size_t i = 0; i < numContours; i++)
|
||||
{
|
||||
if (contours[i].size() <= 2)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
cv::RotatedRect minAreaRect = cv::minAreaRect(contours[i]);
|
||||
|
||||
float longSide;
|
||||
std::vector<cv::Point2f> minBoxes = getMinBoxes(minAreaRect, longSide);
|
||||
|
||||
if (longSide < longSideThresh)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
float boxScore = boxScoreFast(minBoxes, predMat);
|
||||
if (boxScore < boxScoreThresh)
|
||||
continue;
|
||||
|
||||
//-----unClip-----
|
||||
cv::RotatedRect clipRect = unClip(minBoxes, unClipRatio);
|
||||
if (clipRect.size.height < 1.001 && clipRect.size.width < 1.001)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
//-----unClip-----
|
||||
|
||||
std::vector<cv::Point2f> clipMinBoxes = getMinBoxes(clipRect, longSide);
|
||||
if (longSide < longSideThresh + 2)
|
||||
continue;
|
||||
|
||||
std::vector<cv::Point> intClipMinBoxes;
|
||||
|
||||
for (auto &clipMinBox : clipMinBoxes)
|
||||
{
|
||||
float x = clipMinBox.x / s.ratioWidth;
|
||||
float y = clipMinBox.y / s.ratioHeight;
|
||||
int ptX = (std::min)((std::max)(int(x), 0), s.srcWidth - 1);
|
||||
int ptY = (std::min)((std::max)(int(y), 0), s.srcHeight - 1);
|
||||
cv::Point point{ptX, ptY};
|
||||
intClipMinBoxes.push_back(point);
|
||||
}
|
||||
rsBoxes.push_back(intClipMinBoxes);
|
||||
}
|
||||
reverse(rsBoxes.begin(), rsBoxes.end());
|
||||
return rsBoxes;
|
||||
}
|
||||
|
||||
std::vector<TextBox> DbNet::getTextBoxes(cv::Mat &src, ScaleParam &s, float boxScoreThresh, float boxThresh, float unClipRatio)
|
||||
{
|
||||
cv::Mat srcResize;
|
||||
resize(src, srcResize, cv::Size(s.dstWidth, s.dstHeight));
|
||||
auto &&[outputData, outputShape] = RunSession(srcResize);
|
||||
|
||||
//-----Data preparation-----
|
||||
int outHeight = (int)outputShape[2];
|
||||
int outWidth = (int)outputShape[3];
|
||||
size_t area = outHeight * outWidth;
|
||||
|
||||
std::vector<float> predData(area, 0.0);
|
||||
std::vector<unsigned char> cbufData(area, ' ');
|
||||
|
||||
for (int i = 0; i < area; i++)
|
||||
{
|
||||
predData[i] = float(outputData[i]);
|
||||
cbufData[i] = (unsigned char)((outputData[i]) * 255);
|
||||
}
|
||||
|
||||
cv::Mat predMat(outHeight, outWidth, CV_32F, (float *)predData.data());
|
||||
cv::Mat cBufMat(outHeight, outWidth, CV_8UC1, (unsigned char *)cbufData.data());
|
||||
|
||||
//-----boxThresh-----
|
||||
const double maxValue = 255;
|
||||
const double threshold = boxThresh * 255;
|
||||
cv::Mat thresholdMat;
|
||||
cv::threshold(cBufMat, thresholdMat, threshold, maxValue, cv::THRESH_BINARY);
|
||||
|
||||
//-----dilate-----
|
||||
cv::Mat dilateMat;
|
||||
cv::Mat dilateElement = cv::getStructuringElement(cv::MORPH_RECT, cv::Size(2, 2));
|
||||
cv::dilate(thresholdMat, dilateMat, dilateElement);
|
||||
|
||||
return findRsBoxes(predMat, dilateMat, s, boxScoreThresh, unClipRatio);
|
||||
}
|
||||
|
||||
class OcrLite
|
||||
{
|
||||
public:
|
||||
OcrLite(const std::wstring &detPath,
|
||||
const std::wstring &recPath, const std::wstring &keysPath, int numOfThread) : crnnNet(recPath, keysPath, numOfThread), dbNet(detPath, numOfThread)
|
||||
{
|
||||
}
|
||||
|
||||
std::vector<TextBlock> detect(const void *binptr, size_t size,
|
||||
int padding, int maxSideLen,
|
||||
float boxScoreThresh, float boxThresh, float unClipRatio, bool rotate);
|
||||
|
||||
private:
|
||||
DbNet dbNet;
|
||||
CrnnNet crnnNet;
|
||||
|
||||
std::vector<cv::Mat> getPartImages(cv::Mat &src, std::vector<TextBox> &textBoxes);
|
||||
|
||||
std::vector<TextBlock> detect_internal(cv::Mat &src, cv::Rect &originRect, ScaleParam &scale,
|
||||
float boxScoreThresh = 0.6f, float boxThresh = 0.3f,
|
||||
float unClipRatio = 2.0f, bool rotate = true);
|
||||
};
|
||||
|
||||
cv::Mat makePadding(cv::Mat &src, const int padding)
|
||||
{
|
||||
if (padding <= 0)
|
||||
return src;
|
||||
cv::Scalar paddingScalar = {255, 255, 255};
|
||||
cv::Mat paddingSrc;
|
||||
cv::copyMakeBorder(src, paddingSrc, padding, padding, padding, padding, cv::BORDER_ISOLATED, paddingScalar);
|
||||
return paddingSrc;
|
||||
}
|
||||
|
||||
std::vector<TextBlock> OcrLite::detect(const void *binptr, size_t size,
|
||||
const int padding, const int maxSideLen,
|
||||
float boxScoreThresh, float boxThresh, float unClipRatio, bool rotate)
|
||||
{
|
||||
std::vector<uchar> bytes{(uchar *)binptr, (uchar *)binptr + size};
|
||||
cv::Mat originSrc = imdecode(bytes, cv::IMREAD_COLOR); // default : BGR
|
||||
int originMaxSide = (std::max)(originSrc.cols, originSrc.rows);
|
||||
int resize;
|
||||
if (maxSideLen <= 0 || maxSideLen > originMaxSide)
|
||||
{
|
||||
resize = originMaxSide;
|
||||
}
|
||||
else
|
||||
{
|
||||
resize = maxSideLen;
|
||||
}
|
||||
resize += 2 * padding;
|
||||
cv::Rect paddingRect(padding, padding, originSrc.cols, originSrc.rows);
|
||||
cv::Mat paddingSrc = makePadding(originSrc, padding);
|
||||
ScaleParam scale = getScaleParam(paddingSrc, resize);
|
||||
return detect_internal(paddingSrc, paddingRect, scale,
|
||||
boxScoreThresh, boxThresh, unClipRatio, rotate);
|
||||
}
|
||||
|
||||
std::vector<cv::Mat> OcrLite::getPartImages(cv::Mat &src, std::vector<TextBox> &textBoxes)
|
||||
{
|
||||
std::vector<cv::Mat> partImages;
|
||||
for (size_t i = 0; i < textBoxes.size(); ++i)
|
||||
{
|
||||
cv::Mat partImg = getRotateCropImage(src, textBoxes[i]);
|
||||
partImages.emplace_back(partImg);
|
||||
}
|
||||
return partImages;
|
||||
}
|
||||
|
||||
cv::Mat matRotateClockWise180(cv::Mat src) {
|
||||
flip(src, src, 0);
|
||||
flip(src, src, 1);
|
||||
return src;
|
||||
}
|
||||
|
||||
cv::Mat matRotateClockWise90(cv::Mat src) {
|
||||
transpose(src, src);
|
||||
flip(src, src, 1);
|
||||
return src;
|
||||
}
|
||||
|
||||
std::vector<TextBlock> OcrLite::detect_internal(cv::Mat &src, cv::Rect &originRect, ScaleParam &scale,
|
||||
float boxScoreThresh, float boxThresh, float unClipRatio, bool rotate)
|
||||
{
|
||||
|
||||
std::vector<TextBox> textBoxes = dbNet.getTextBoxes(src, scale, boxScoreThresh, boxThresh, unClipRatio);
|
||||
std::vector<cv::Mat> partImages = getPartImages(src, textBoxes);
|
||||
for (size_t i = 0; i < partImages.size(); ++i)
|
||||
{
|
||||
if (rotate)
|
||||
{
|
||||
partImages.at(i) = matRotateClockWise180(partImages[i]);
|
||||
partImages.at(i) = matRotateClockWise90(partImages[i]);
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<TextLine> textLines = crnnNet.getTextLines(partImages);
|
||||
|
||||
std::vector<TextBlock> textBlocks;
|
||||
for (size_t i = 0; i < textLines.size(); ++i)
|
||||
{
|
||||
std::vector<cv::Point> boxPoint = std::vector<cv::Point>(4);
|
||||
int padding = originRect.x; // padding conversion
|
||||
boxPoint[0] = cv::Point(textBoxes[i][0].x - padding, textBoxes[i][0].y - padding);
|
||||
boxPoint[1] = cv::Point(textBoxes[i][1].x - padding, textBoxes[i][1].y - padding);
|
||||
boxPoint[2] = cv::Point(textBoxes[i][2].x - padding, textBoxes[i][2].y - padding);
|
||||
boxPoint[3] = cv::Point(textBoxes[i][3].x - padding, textBoxes[i][3].y - padding);
|
||||
TextBlock textBlock{boxPoint, textLines[i]};
|
||||
textBlocks.emplace_back(textBlock);
|
||||
}
|
||||
|
||||
return textBlocks;
|
||||
}
|
||||
|
||||
#define DECLARE_API extern "C" __declspec(dllexport)
|
||||
|
||||
struct ocrpoints
|
||||
{
|
||||
int x1, y1, x2, y2, x3, y3, x4, y4;
|
||||
};
|
||||
DECLARE_API OcrLite *OcrInit(const wchar_t *szDetModel, const wchar_t *szRecModel, const wchar_t *szKeyPath, int nThreads)
|
||||
{
|
||||
OcrLite *pOcrObj = nullptr;
|
||||
try
|
||||
{
|
||||
pOcrObj = new OcrLite(szDetModel, szRecModel, szKeyPath, nThreads);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
}
|
||||
if (pOcrObj)
|
||||
{
|
||||
return pOcrObj;
|
||||
}
|
||||
else
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
DECLARE_API void OcrDetect(OcrLite *pOcrObj, const void *binptr, size_t size, bool rotate, void (*cb)(ocrpoints, const char *))
|
||||
{
|
||||
if (!pOcrObj)
|
||||
return;
|
||||
|
||||
try
|
||||
{
|
||||
auto result = pOcrObj->detect(binptr, size, 50, 1024, 0.1, 0.1, 2.0, rotate);
|
||||
|
||||
for (auto item : result)
|
||||
{
|
||||
cb({item.first[0].x, item.first[0].y,
|
||||
item.first[1].x, item.first[1].y,
|
||||
item.first[2].x, item.first[2].y,
|
||||
item.first[3].x, item.first[3].y},
|
||||
item.second.c_str());
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
DECLARE_API void OcrDestroy(OcrLite *pOcrObj)
|
||||
{
|
||||
if (pOcrObj)
|
||||
delete pOcrObj;
|
||||
}
|
@ -14,4 +14,4 @@ generate_product_version(
|
||||
|
||||
add_library(loopbackaudio MODULE runer.cpp LoopbackCapture.cpp ${versioninfo})
|
||||
target_precompile_headers(loopbackaudio REUSE_FROM pch)
|
||||
target_link_libraries(loopbackaudio Mfplat mfuuid )
|
||||
target_link_libraries(loopbackaudio Mfplat mfuuid wil)
|
@ -1,8 +1,8 @@
|
||||
|
||||
#include "LoopbackCapture.h"
|
||||
#define DECLARE extern "C" __declspec(dllexport)
|
||||
#define DECLARE_API extern "C" __declspec(dllexport)
|
||||
|
||||
DECLARE void StartCaptureAsync(void (*datacb)(void *ptr, size_t size), void (*handlecb)(HANDLE))
|
||||
DECLARE_API void StartCaptureAsync(void (*datacb)(void *ptr, size_t size), void (*handlecb)(HANDLE))
|
||||
{
|
||||
auto mutex = CreateSemaphoreW(NULL, 0, 1, NULL);
|
||||
handlecb(mutex);
|
||||
@ -14,7 +14,7 @@ DECLARE void StartCaptureAsync(void (*datacb)(void *ptr, size_t size), void (*ha
|
||||
datacb(loopbackCapture.buffer.data(), loopbackCapture.buffer.size());
|
||||
}
|
||||
|
||||
DECLARE void StopCaptureAsync(HANDLE m)
|
||||
DECLARE_API void StopCaptureAsync(HANDLE m)
|
||||
{
|
||||
ReleaseSemaphore(m, 1, NULL);
|
||||
}
|
1
src/plugins/libs/Clipper2
Submodule
1
src/plugins/libs/Clipper2
Submodule
@ -0,0 +1 @@
|
||||
Subproject commit ed98928c66707988d4eb2c49a31c41380a08931c
|
@ -1,16 +1,26 @@
|
||||
|
||||
set(Detours ${CMAKE_CURRENT_LIST_DIR}/Detours/src/creatwth.cpp ${CMAKE_CURRENT_LIST_DIR}/Detours/src/detours.cpp ${CMAKE_CURRENT_LIST_DIR}/Detours/src/modules.cpp ${CMAKE_CURRENT_LIST_DIR}/Detours/src/disasm.cpp)
|
||||
include_directories(${CMAKE_CURRENT_LIST_DIR})
|
||||
include_directories(${CMAKE_CURRENT_LIST_DIR}/Detours/src)
|
||||
add_library(Detours ${CMAKE_CURRENT_LIST_DIR}/Detours/src/creatwth.cpp ${CMAKE_CURRENT_LIST_DIR}/Detours/src/detours.cpp ${CMAKE_CURRENT_LIST_DIR}/Detours/src/modules.cpp ${CMAKE_CURRENT_LIST_DIR}/Detours/src/disasm.cpp)
|
||||
target_include_directories(Detours PUBLIC ${CMAKE_CURRENT_LIST_DIR}/Detours/src)
|
||||
|
||||
include_directories(${CMAKE_CURRENT_LIST_DIR}/wil/include)
|
||||
include_directories(${CMAKE_CURRENT_LIST_DIR}/miniaudio)
|
||||
include_directories(${CMAKE_CURRENT_LIST_DIR}/tinymp3)
|
||||
include_directories(${CMAKE_CURRENT_LIST_DIR}/rapidfuzz-cpp)
|
||||
add_library(nlohmann INTERFACE)
|
||||
target_include_directories(nlohmann INTERFACE ${CMAKE_CURRENT_LIST_DIR})
|
||||
|
||||
include_directories(${CMAKE_CURRENT_LIST_DIR}/webview2/Microsoft.Web.WebView2.1.0.2535.41/build/native/include)
|
||||
add_library(wil INTERFACE)
|
||||
target_include_directories(wil INTERFACE ${CMAKE_CURRENT_LIST_DIR}/wil/include)
|
||||
|
||||
add_subdirectory(${CMAKE_CURRENT_LIST_DIR}/tinymp3)
|
||||
add_subdirectory(${CMAKE_CURRENT_LIST_DIR}/rapidfuzz-cpp)
|
||||
|
||||
|
||||
add_library(webview2 INTERFACE)
|
||||
target_include_directories(webview2 INTERFACE ${CMAKE_CURRENT_LIST_DIR}/webview2/Microsoft.Web.WebView2.1.0.2535.41/build/native/include)
|
||||
|
||||
if(${CMAKE_SIZEOF_VOID_P} EQUAL 4)
|
||||
set(LTLPlatform "Win32")
|
||||
endif()
|
||||
include("${CMAKE_CURRENT_LIST_DIR}/VC-LTL helper for cmake.cmake")
|
||||
|
||||
|
||||
file(GLOB Clipper2LibSrc ${CMAKE_CURRENT_LIST_DIR}/Clipper2/CPP/Clipper2Lib/src/*.cpp)
|
||||
add_library(Clipper2Lib ${Clipper2LibSrc})
|
||||
target_include_directories(Clipper2Lib PUBLIC ${CMAKE_CURRENT_LIST_DIR}/Clipper2/CPP/Clipper2Lib/include)
|
16
src/plugins/libs/onnxruntime-static/OnnxRuntimeWrapper.cmake
Normal file
16
src/plugins/libs/onnxruntime-static/OnnxRuntimeWrapper.cmake
Normal file
@ -0,0 +1,16 @@
|
||||
if (APPLE)
|
||||
message("配置macOS OnnxRuntime 路径: ${CMAKE_CURRENT_LIST_DIR}/macos")
|
||||
set(OnnxRuntime_DIR "${CMAKE_CURRENT_LIST_DIR}/macos")
|
||||
elseif (WIN32)
|
||||
if (CMAKE_CL_64)
|
||||
message("配置WINDOWS OnnxRuntime x64 路径: ${CMAKE_CURRENT_LIST_DIR}/windows-x64")
|
||||
set(OnnxRuntime_DIR "${CMAKE_CURRENT_LIST_DIR}/windows-x64")
|
||||
else ()
|
||||
message("配置WINDOWS OnnxRuntime x86 路径: ${CMAKE_CURRENT_LIST_DIR}/windows-x86")
|
||||
set(OnnxRuntime_DIR "${CMAKE_CURRENT_LIST_DIR}/windows-x86")
|
||||
endif ()
|
||||
elseif (UNIX)
|
||||
message("配置Linux OnnxRuntime 路径: ${CMAKE_CURRENT_LIST_DIR}/linux")
|
||||
set(OnnxRuntime_DIR "${CMAKE_CURRENT_LIST_DIR}/linux")
|
||||
endif ()
|
||||
|
15
src/plugins/libs/opencv-static/OpenCVWrapperConfig.cmake
Normal file
15
src/plugins/libs/opencv-static/OpenCVWrapperConfig.cmake
Normal file
@ -0,0 +1,15 @@
|
||||
if (WIN32)
|
||||
if (CMAKE_CL_64)
|
||||
message("配置WINDOWS OpenCV x64 路径: ${CMAKE_CURRENT_LIST_DIR}/windows-x64")
|
||||
set(OpenCV_DIR "${CMAKE_CURRENT_LIST_DIR}/windows-x64")
|
||||
else ()
|
||||
message("配置WINDOWS OpenCV x86 路径: ${CMAKE_CURRENT_LIST_DIR}/windows-x86")
|
||||
set(OpenCV_DIR "${CMAKE_CURRENT_LIST_DIR}/windows-x86")
|
||||
endif ()
|
||||
elseif (APPLE)
|
||||
message("配置macOS OpenCV 路径: ${CMAKE_CURRENT_LIST_DIR}/macos/lib/cmake/opencv4")
|
||||
set(OpenCV_DIR "${CMAKE_CURRENT_LIST_DIR}/macos/lib/cmake/opencv4")
|
||||
elseif (UNIX)
|
||||
message("配置Linux OpenCV 路径: ${CMAKE_CURRENT_LIST_DIR}/linux/lib/cmake/opencv4")
|
||||
set(OpenCV_DIR "${CMAKE_CURRENT_LIST_DIR}/linux/lib/cmake/opencv4")
|
||||
endif ()
|
@ -1 +1 @@
|
||||
Subproject commit 9781d63bf7d057457b25b5e77492bcf2cfa109c5
|
||||
Subproject commit 579726185979f877f2672b956b23538ff00c08ba
|
@ -19,6 +19,7 @@
|
||||
#include <algorithm>
|
||||
#include <functional>
|
||||
#include <fstream>
|
||||
#include <numeric>
|
||||
#include <filesystem>
|
||||
#include <stdexcept>
|
||||
#include <cstdint>
|
||||
@ -69,7 +70,6 @@
|
||||
#include <crtdefs.h>
|
||||
|
||||
#include <memory>
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
|
||||
#pragma comment(lib, "shlwapi.lib")
|
||||
|
@ -6,6 +6,7 @@ if x86:
|
||||
shutil.copy('../builds/_x86/winrtutils32.dll','../../files/plugins/DLL32')
|
||||
shutil.copy('../builds/_x86/winsharedutils32.dll','../../files/plugins/DLL32')
|
||||
shutil.copy('../builds/_x86/wcocr.dll','../../files/plugins/DLL32')
|
||||
shutil.copy('../builds/_x86/LunaOCR32.dll','../../files/plugins/DLL32')
|
||||
else:
|
||||
shutil.copy('../builds/_x64/shareddllproxy64.exe','../../files/plugins')
|
||||
shutil.copy('../builds/_x64/loopbackaudio.dll','../../files/plugins/DLL64')
|
||||
@ -13,3 +14,4 @@ else:
|
||||
shutil.copy('../builds/_x64/winrtutils64.dll','../../files/plugins/DLL64')
|
||||
shutil.copy('../builds/_x64/winsharedutils64.dll','../../files/plugins/DLL64')
|
||||
shutil.copy('../builds/_x64/wcocr.dll','../../files/plugins/DLL64')
|
||||
shutil.copy('../builds/_x64/LunaOCR64.dll','../../files/plugins/DLL64')
|
||||
|
@ -8,7 +8,7 @@ nuget_exe = os.path.join(target, "nuget.exe")
|
||||
print(nuget_exe)
|
||||
if os.path.exists(nuget_exe) == False:
|
||||
os.system(
|
||||
rf'curl -sSLo "{nuget_exe}" https://dist.nuget.org/win-x86-commandline/latest/nuget.exe'
|
||||
rf'curl -SLo "{nuget_exe}" https://dist.nuget.org/win-x86-commandline/latest/nuget.exe'
|
||||
)
|
||||
|
||||
mswebview2_dir = os.path.join(target, f"Microsoft.Web.WebView2.{mswebview2_version}")
|
||||
@ -20,3 +20,34 @@ if os.path.exists(mswebview2_dir) == False:
|
||||
subprocess.run(
|
||||
rf'"{nuget_exe}" install Microsoft.Web.Webview2 -Verbosity quiet -Version "{mswebview2_version}" -OutputDirectory {target}'
|
||||
)
|
||||
|
||||
|
||||
onnx = os.path.normpath(
|
||||
os.path.join(
|
||||
os.path.dirname(__file__), "../libs/onnxruntime-static/windows-x64/lib/onnx.lib"
|
||||
)
|
||||
)
|
||||
opencv = os.path.normpath(
|
||||
os.path.join(
|
||||
os.path.dirname(__file__),
|
||||
r"..\libs\opencv-static\windows-x64\x64\vc16\staticlib\opencv_core470.lib",
|
||||
)
|
||||
)
|
||||
onnx_1 = os.path.normpath(
|
||||
os.path.join(os.path.dirname(__file__), "../libs/onnxruntime-static.zip")
|
||||
)
|
||||
opencv_1 = os.path.normpath(
|
||||
os.path.join(os.path.dirname(__file__), r"..\libs\opencv-static.zip")
|
||||
)
|
||||
|
||||
|
||||
if os.path.exists(onnx) == False:
|
||||
os.system(
|
||||
rf'curl -SLo "{onnx_1}" https://github.com/HIllya51/RESOURCES/releases/download/common/onnxruntime-static.zip'
|
||||
)
|
||||
os.system(rf'7z x -y "{onnx_1}" -o{os.path.dirname(opencv_1)}')
|
||||
if os.path.exists(opencv) == False:
|
||||
os.system(
|
||||
rf'curl -SLo "{opencv_1}" https://github.com/HIllya51/RESOURCES/releases/download/common/opencv-static.zip'
|
||||
)
|
||||
os.system(rf'7z x -y "{opencv_1}" -o{os.path.dirname(opencv_1)}')
|
||||
|
@ -11,18 +11,23 @@ generate_product_version(
|
||||
VERSION_PATCH ${VERSION_PATCH}
|
||||
)
|
||||
|
||||
set(shareddllproxy_common shareddllproxy.cpp dllinject.cpp ntleas.cpp aspatch.cpp update.cpp ${versioninfo})
|
||||
|
||||
add_executable(shareddllproxy shareddllproxy.cpp dllinject.cpp ntleas.cpp aspatch.cpp update.cpp ${versioninfo})
|
||||
target_precompile_headers(shareddllproxy REUSE_FROM pch)
|
||||
if(${CMAKE_SIZEOF_VOID_P} EQUAL 8)
|
||||
add_executable(shareddllproxy ${shareddllproxy_common})
|
||||
|
||||
target_link_libraries(shareddllproxy Mfplat mfuuid)
|
||||
else()
|
||||
add_executable(shareddllproxy ${shareddllproxy_common} Atlas.cpp eztrans.cpp dreye.cpp jbj7.cpp kingsoft.cpp le.cpp neospeech.cpp ../implsapi.cpp LR.cpp)
|
||||
add_subdirectory(voiceroid2)
|
||||
endif()
|
||||
|
||||
target_precompile_headers(shareddllproxy REUSE_FROM pch)
|
||||
|
||||
if(${CMAKE_SIZEOF_VOID_P} EQUAL 8)
|
||||
target_link_libraries(shareddllproxy nlohmann Mfplat mfuuid)
|
||||
set_target_properties(shareddllproxy PROPERTIES OUTPUT_NAME "shareddllproxy64")
|
||||
else()
|
||||
add_subdirectory(voiceroid2)
|
||||
add_library(x86lib Atlas.cpp eztrans.cpp dreye.cpp jbj7.cpp kingsoft.cpp le.cpp neospeech.cpp ../implsapi.cpp LR.cpp ${Detours})
|
||||
target_precompile_headers(voiceroid2 REUSE_FROM pch)
|
||||
target_precompile_headers(x86lib REUSE_FROM pch)
|
||||
target_link_libraries(shareddllproxy Mfplat mfuuid x86lib voiceroid2)
|
||||
target_link_libraries(shareddllproxy nlohmann Mfplat mfuuid voiceroid2 Detours)
|
||||
set_target_properties(shareddllproxy PROPERTIES OUTPUT_NAME "shareddllproxy32")
|
||||
endif()
|
@ -1,4 +1,6 @@
|
||||
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
HANDLE runexe(const std::wstring &exe, const std::optional<std::wstring> &startup_argument)
|
||||
{
|
||||
STARTUPINFOW si;
|
||||
|
@ -1,8 +1,8 @@
|
||||
#include <stdafx.h>
|
||||
#include <wechatocr.h>
|
||||
#define DECLARE extern "C" __declspec(dllexport)
|
||||
#define DECLARE_API extern "C" __declspec(dllexport)
|
||||
|
||||
DECLARE void *wcocr_init(const wchar_t *wexe, const wchar_t *wwcdir)
|
||||
DECLARE_API void *wcocr_init(const wchar_t *wexe, const wchar_t *wwcdir)
|
||||
{
|
||||
auto obj = new CWeChatOCR(wexe, wwcdir);
|
||||
if (obj->wait_connection(5000))
|
||||
@ -16,14 +16,14 @@ DECLARE void *wcocr_init(const wchar_t *wexe, const wchar_t *wwcdir)
|
||||
}
|
||||
}
|
||||
|
||||
DECLARE void wcocr_destroy(void *pobj)
|
||||
DECLARE_API void wcocr_destroy(void *pobj)
|
||||
{
|
||||
if (!pobj)
|
||||
return;
|
||||
auto obj = reinterpret_cast<CWeChatOCR *>(pobj);
|
||||
delete obj;
|
||||
}
|
||||
DECLARE bool wcocr_ocr(void *pobj, const char *u8path, void (*cb)(int, int, int, int, LPCSTR))
|
||||
DECLARE_API bool wcocr_ocr(void *pobj, const char *u8path, void (*cb)(int, int, int, int, LPCSTR))
|
||||
{
|
||||
if (!pobj)
|
||||
return false;
|
||||
|
@ -84,7 +84,7 @@ typedef BOOL(WINAPI *pfnSetWindowCompositionAttribute)(HWND, WINDOWCOMPOSITIONAT
|
||||
if (!setWindowCompositionAttribute) \
|
||||
return false;
|
||||
|
||||
DECLARE bool setAcrylicEffect(HWND hwnd, bool isEnableShadow)
|
||||
DECLARE_API bool setAcrylicEffect(HWND hwnd, bool isEnableShadow)
|
||||
{
|
||||
// win7全都用areo
|
||||
DWM_BLURBEHIND bb = {0};
|
||||
@ -102,7 +102,7 @@ DECLARE bool setAcrylicEffect(HWND hwnd, bool isEnableShadow)
|
||||
accentPolicy.AccentFlags = accentFlags;
|
||||
return setWindowCompositionAttribute(hwnd, &winCompAttrData);
|
||||
}
|
||||
DECLARE bool setAeroEffect(HWND hwnd, bool isEnableShadow)
|
||||
DECLARE_API bool setAeroEffect(HWND hwnd, bool isEnableShadow)
|
||||
{
|
||||
DWM_BLURBEHIND bb = {0};
|
||||
bb.dwFlags = DWM_BB_ENABLE;
|
||||
@ -117,7 +117,7 @@ DECLARE bool setAeroEffect(HWND hwnd, bool isEnableShadow)
|
||||
accentPolicy.AccentFlags = accentFlags;
|
||||
return setWindowCompositionAttribute(hwnd, &winCompAttrData);
|
||||
}
|
||||
DECLARE bool clearEffect(HWND hwnd)
|
||||
DECLARE_API bool clearEffect(HWND hwnd)
|
||||
{
|
||||
DWM_BLURBEHIND bb = {0};
|
||||
bb.dwFlags = DWM_BB_ENABLE;
|
||||
|
@ -10,10 +10,9 @@ generate_product_version(
|
||||
VERSION_MINOR ${VERSION_MINOR}
|
||||
VERSION_PATCH ${VERSION_PATCH}
|
||||
)
|
||||
add_library(tinymp3 ../libs/tinymp3/shine_mp3.c)
|
||||
add_library(winsharedutils MODULE mp3enc.cpp webview2_extra.cpp AreoAcrylic.cpp screenshot.cpp ../implsapi.cpp hwnd.cpp globalmessagelistener.cpp theme.cpp version.cpp otsu.cpp clipboard.cpp lnk.cpp dllmain.cpp levenshtein.cpp muteprocess.cpp sapi_dll.cpp simplemecab.cpp SimpleBrowser.cpp MWebBrowser.cpp icon.cpp ${versioninfo})
|
||||
target_precompile_headers(winsharedutils REUSE_FROM pch)
|
||||
target_link_libraries(winsharedutils tinymp3 Shcore)
|
||||
target_link_libraries(winsharedutils tinymp3 Shcore rapidfuzz wil webview2)
|
||||
if(${CMAKE_SIZEOF_VOID_P} EQUAL 8)
|
||||
set_target_properties(winsharedutils PROPERTIES OUTPUT_NAME "winsharedutils64")
|
||||
else()
|
||||
|
@ -123,7 +123,7 @@ static void clipboard_callback_1(void (*callback)(const wchar_t *, bool), HANDLE
|
||||
}
|
||||
}
|
||||
|
||||
DECLARE HWND clipboard_callback(void (*callback)(const wchar_t *, bool))
|
||||
DECLARE_API HWND clipboard_callback(void (*callback)(const wchar_t *, bool))
|
||||
{
|
||||
HANDLE hsema = CreateSemaphoreW(0, 0, 10, 0);
|
||||
HWND hwnd;
|
||||
@ -137,7 +137,7 @@ DECLARE HWND clipboard_callback(void (*callback)(const wchar_t *, bool))
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
DECLARE void clipboard_callback_stop(HWND hwnd)
|
||||
DECLARE_API void clipboard_callback_stop(HWND hwnd)
|
||||
{
|
||||
if (!hwnd)
|
||||
return;
|
||||
@ -145,7 +145,7 @@ DECLARE void clipboard_callback_stop(HWND hwnd)
|
||||
DestroyWindow(hwnd);
|
||||
}
|
||||
|
||||
DECLARE bool clipboard_set_image(HWND hwnd, void *ptr, size_t size)
|
||||
DECLARE_API bool clipboard_set_image(HWND hwnd, void *ptr, size_t size)
|
||||
{
|
||||
size -= sizeof(BITMAPFILEHEADER);
|
||||
HGLOBAL hDib = GlobalAlloc(GMEM_MOVEABLE, size);
|
||||
|
@ -1,5 +1,5 @@
|
||||
#pragma once
|
||||
#define DECLARE extern "C" __declspec(dllexport)
|
||||
#define DECLARE_API extern "C" __declspec(dllexport)
|
||||
extern "C"
|
||||
{
|
||||
|
||||
|
@ -52,12 +52,12 @@ void globalmessagelistener_1(void *callback)
|
||||
DispatchMessage(&msg);
|
||||
}
|
||||
}
|
||||
DECLARE void globalmessagelistener(void *callback)
|
||||
DECLARE_API void globalmessagelistener(void *callback)
|
||||
{
|
||||
std::thread(std::bind(globalmessagelistener_1, callback)).detach();
|
||||
}
|
||||
|
||||
DECLARE void dispatchcloseevent()
|
||||
DECLARE_API void dispatchcloseevent()
|
||||
{
|
||||
PostMessage(HWND_BROADCAST, LUNA_UPDATE_PREPARED_OK, 0, 0);
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
#include "define.h"
|
||||
#include <shellscalingapi.h>
|
||||
DECLARE void showintab(HWND hwnd, bool show, bool tool)
|
||||
DECLARE_API void showintab(HWND hwnd, bool show, bool tool)
|
||||
{
|
||||
// WS_EX_TOOLWINDOW可以立即生效,WS_EX_APPWINDOW必须切换焦点才生效。但是WS_EX_TOOLWINDOW会改变窗口样式,因此只对无边框窗口使用。
|
||||
LONG style = GetWindowLong(hwnd, GWL_STYLE);
|
||||
@ -22,7 +22,7 @@ DECLARE void showintab(HWND hwnd, bool show, bool tool)
|
||||
SetWindowLong(hwnd, GWL_EXSTYLE, style_ex);
|
||||
}
|
||||
|
||||
DECLARE bool pid_running(DWORD pid)
|
||||
DECLARE_API bool pid_running(DWORD pid)
|
||||
{
|
||||
DWORD code;
|
||||
GetExitCodeProcess(AutoHandle(OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, pid)), &code);
|
||||
@ -54,14 +54,14 @@ BOOL CALLBACK EnumWindowsProc(HWND hwnd, LPARAM lParam)
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
DECLARE HWND getpidhwndfirst(DWORD pid)
|
||||
DECLARE_API HWND getpidhwndfirst(DWORD pid)
|
||||
{
|
||||
__EnumWindowsProc info = {pid, 0};
|
||||
EnumWindows(EnumWindowsProc, (LPARAM)&info);
|
||||
return info.hwnd;
|
||||
}
|
||||
|
||||
DECLARE bool Is64bit(DWORD pid)
|
||||
DECLARE_API bool Is64bit(DWORD pid)
|
||||
{
|
||||
SYSTEM_INFO sysinfo;
|
||||
GetNativeSystemInfo(&sysinfo);
|
||||
@ -78,7 +78,7 @@ DECLARE bool Is64bit(DWORD pid)
|
||||
return false;
|
||||
}
|
||||
|
||||
DECLARE void getprocesses(void (*cb)(DWORD, const wchar_t *))
|
||||
DECLARE_API void getprocesses(void (*cb)(DWORD, const wchar_t *))
|
||||
{
|
||||
std::unordered_map<std::wstring, std::vector<int>> exe_pid;
|
||||
AutoHandle hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
|
||||
@ -96,7 +96,7 @@ DECLARE void getprocesses(void (*cb)(DWORD, const wchar_t *))
|
||||
} while (Process32Next(hSnapshot, &pe32));
|
||||
}
|
||||
}
|
||||
DECLARE UINT GetMonitorDpiScaling(HWND hwnd)
|
||||
DECLARE_API UINT GetMonitorDpiScaling(HWND hwnd)
|
||||
{
|
||||
HMONITOR hMonitor = MonitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST);
|
||||
if (!hMonitor)
|
||||
|
@ -12,7 +12,7 @@
|
||||
|
||||
int stereo = STEREO;
|
||||
|
||||
DECLARE void encodemp3(void *ptr, size_t size, void (*cb)(void *ptr, size_t size))
|
||||
DECLARE_API void encodemp3(void *ptr, size_t size, void (*cb)(void *ptr, size_t size))
|
||||
{
|
||||
shine_config_t config;
|
||||
shine_t s;
|
||||
|
@ -42,7 +42,7 @@ namespace SAPI
|
||||
}
|
||||
};
|
||||
|
||||
DECLARE bool SAPI_Speak(const wchar_t *Content, int version, int voiceid, int rate, int volume, void (*cb)(byte *, size_t))
|
||||
DECLARE_API bool SAPI_Speak(const wchar_t *Content, int version, int voiceid, int rate, int volume, void (*cb)(byte *, size_t))
|
||||
{
|
||||
auto _c = std::wstring(Content);
|
||||
if (auto _ = std::move(SAPI::Speak(_c, version, voiceid, rate, volume)))
|
||||
|
@ -157,7 +157,7 @@ std::vector<byte> SaveBitmapToBuffer(HBITMAP hBitmap)
|
||||
|
||||
return data;
|
||||
}
|
||||
DECLARE void gdi_screenshot(HWND hwnd, RECT rect, void (*cb)(byte *, size_t))
|
||||
DECLARE_API void gdi_screenshot(HWND hwnd, RECT rect, void (*cb)(byte *, size_t))
|
||||
{
|
||||
if (rect.bottom == rect.top || rect.left == rect.right)
|
||||
return;
|
||||
@ -176,7 +176,7 @@ DECLARE void gdi_screenshot(HWND hwnd, RECT rect, void (*cb)(byte *, size_t))
|
||||
ReleaseDC(hwnd, hdc);
|
||||
}
|
||||
|
||||
DECLARE void maximum_window(HWND hwnd)
|
||||
DECLARE_API void maximum_window(HWND hwnd)
|
||||
{
|
||||
RECT rect;
|
||||
GetVirtualDesktopRect(rect);
|
||||
|
@ -150,13 +150,13 @@ static void SetWindowTheme(HWND hWnd, bool darkBorder, bool darkMenu) noexcept
|
||||
RefreshImmersiveColorPolicyState();
|
||||
FlushMenuThemes();
|
||||
}
|
||||
DECLARE void setdwmextendframe(HWND hwnd)
|
||||
DECLARE_API void setdwmextendframe(HWND hwnd)
|
||||
{
|
||||
MARGINS mar{-1, -1, -1, -1};
|
||||
DwmExtendFrameIntoClientArea(hwnd, &mar);
|
||||
}
|
||||
|
||||
DECLARE void _SetTheme(
|
||||
DECLARE_API void _SetTheme(
|
||||
HWND _hWnd,
|
||||
bool dark,
|
||||
int backdrop)
|
||||
@ -191,7 +191,7 @@ DECLARE void _SetTheme(
|
||||
DwmSetWindowAttribute(_hWnd, DWMWA_SYSTEMBACKDROP_TYPE, &value, sizeof(value));
|
||||
}
|
||||
|
||||
DECLARE bool isDark()
|
||||
DECLARE_API bool isDark()
|
||||
{
|
||||
HKEY hKey;
|
||||
const char *subKey = "Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize";
|
||||
|
@ -11,7 +11,7 @@ using namespace Microsoft::WRL;
|
||||
if (FAILED((x))) \
|
||||
return x;
|
||||
|
||||
DECLARE void set_transparent_background(void* m_host){
|
||||
DECLARE_API void set_transparent_background(void* m_host){
|
||||
COREWEBVIEW2_COLOR color;
|
||||
ZeroMemory(&color,sizeof(color));
|
||||
wil::com_ptr<ICoreWebView2Controller> m_controller(reinterpret_cast<ICoreWebView2Controller *>(m_host));
|
||||
@ -22,7 +22,7 @@ DECLARE void set_transparent_background(void* m_host){
|
||||
}
|
||||
}
|
||||
|
||||
DECLARE HRESULT put_PreferredColorScheme(void *m_host, COREWEBVIEW2_PREFERRED_COLOR_SCHEME scheme)
|
||||
DECLARE_API HRESULT put_PreferredColorScheme(void *m_host, COREWEBVIEW2_PREFERRED_COLOR_SCHEME scheme)
|
||||
{
|
||||
|
||||
wil::com_ptr<ICoreWebView2Controller> m_controller(reinterpret_cast<ICoreWebView2Controller *>(m_host));
|
||||
@ -37,7 +37,7 @@ DECLARE HRESULT put_PreferredColorScheme(void *m_host, COREWEBVIEW2_PREFERRED_CO
|
||||
}
|
||||
return S_FALSE;
|
||||
}
|
||||
DECLARE void *add_ZoomFactorChanged(void *m_host, void (*signal)(double))
|
||||
DECLARE_API void *add_ZoomFactorChanged(void *m_host, void (*signal)(double))
|
||||
{
|
||||
EventRegistrationToken *m_zoomFactorChangedToken = new EventRegistrationToken;
|
||||
// Register a handler for the ZoomFactorChanged event.
|
||||
@ -58,19 +58,19 @@ DECLARE void *add_ZoomFactorChanged(void *m_host, void (*signal)(double))
|
||||
m_zoomFactorChangedToken);
|
||||
return m_zoomFactorChangedToken;
|
||||
}
|
||||
DECLARE void remove_ZoomFactorChanged(void *m_host, void *m_zoomFactorChangedToken)
|
||||
DECLARE_API void remove_ZoomFactorChanged(void *m_host, void *m_zoomFactorChangedToken)
|
||||
{
|
||||
|
||||
reinterpret_cast<ICoreWebView2Controller *>(m_host)->remove_ZoomFactorChanged(*reinterpret_cast<EventRegistrationToken *>(m_zoomFactorChangedToken));
|
||||
delete m_zoomFactorChangedToken;
|
||||
}
|
||||
DECLARE double get_ZoomFactor(void *m_host)
|
||||
DECLARE_API double get_ZoomFactor(void *m_host)
|
||||
{
|
||||
double zoomFactor;
|
||||
reinterpret_cast<ICoreWebView2Controller *>(m_host)->get_ZoomFactor(&zoomFactor);
|
||||
return zoomFactor;
|
||||
}
|
||||
DECLARE void put_ZoomFactor(void *m_host, double zoomFactor)
|
||||
DECLARE_API void put_ZoomFactor(void *m_host, double zoomFactor)
|
||||
{
|
||||
reinterpret_cast<ICoreWebView2Controller *>(m_host)->put_ZoomFactor(zoomFactor);
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user