This commit is contained in:
恍兮惚兮 2024-11-04 23:10:41 +08:00 committed by GitHub
parent b9697820c5
commit 7cd7c77848
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
34 changed files with 930 additions and 115 deletions

6
.gitignore vendored
View File

@ -34,3 +34,9 @@ src/run3732.bat
src/plugins/builds src/plugins/builds
src/plugins/libs/webview2 src/plugins/libs/webview2
src/plugins/.vscode/settings.json 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
View File

@ -13,3 +13,6 @@
[submodule "src/plugins/libs/Detours"] [submodule "src/plugins/libs/Detours"]
path = src/plugins/libs/Detours path = src/plugins/libs/Detours
url = https://github.com/microsoft/Detours url = https://github.com/microsoft/Detours
[submodule "src/plugins/libs/Clipper2"]
path = src/plugins/libs/Clipper2
url = https://github.com/AngusJohnson/Clipper2

View File

@ -20,7 +20,7 @@
- **HOOK** 支持使用[HOOK](https://github.com/HIllya51/LunaHook)方式获取文本支持使用特殊码支持自动保存游戏及HOOK、自动加载HOOK等。对于部分引擎还支持内嵌翻译。对于不支持或支持不好的游戏请[提交反馈](https://lunatranslator.org/Resource/game_support) - **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兼容接口 )
- **剪贴板** 支持从剪贴板中获取文本进行翻译 - **剪贴板** 支持从剪贴板中获取文本进行翻译

View File

@ -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) - **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 - **Clipboard** Supports obtaining text from the clipboard for translation

View File

@ -21,7 +21,7 @@
- **HOOK** Поддерживает получение текста с использованием метода [HOOK](https://github.com/HIllya51/LunaHook), поддерживает использование специальных кодов, поддерживает автоматическое сохранение игр и HOOK, автоматическое загрузка HOOK и т.д. Для некоторых движков также поддерживается встроенная трансляция. Для игр, которые не поддерживаются или плохо поддерживаются, пожалуйста, [отправьте обратную связь](https://lunatranslator.org/Resource/game_support) - **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).
- **Буфер обмена** Поддерживает получение текста из буфера обмена для перевода - **Буфер обмена** Поддерживает получение текста из буфера обмена для перевода

View File

@ -1,6 +1,6 @@
import os, zipfile import os, zipfile
from myutils.utils import dynamiclink 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 ocrengines.baseocrclass import baseocr
from ctypes import ( from ctypes import (
CDLL, CDLL,
@ -12,6 +12,9 @@ from ctypes import (
Structure, Structure,
pointer, pointer,
c_char_p, c_char_p,
c_wchar_p,
c_bool,
CFUNCTYPE,
) )
import os import os
import gobject, functools import gobject, functools
@ -40,69 +43,42 @@ class ocrwrapper:
self.pOcrObj = None self.pOcrObj = None
self.__OcrInit(det, rec, key) 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 = self.dll.OcrInit
_OcrInit.restype = c_void_p _OcrInit.restype = c_void_p
self.pOcrObj = _OcrInit( _OcrInit.argtypes = c_wchar_p, c_wchar_p, c_wchar_p, c_int32
c_char_p(szDetModel.encode("utf8")), self.pOcrObj = _OcrInit(szDetModel, szRecModel, szKeyPath, nThreads)
c_char_p(szClsModel.encode("utf8")),
c_char_p(szRecModel.encode("utf8")), def __OcrDetect(self, data: bytes, rotate: bool):
c_char_p(szKeyPath.encode("utf8")),
nThreads, 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 = self.dll.OcrDetect
_OcrDetect.argtypes = ( _OcrDetect.argtypes = (
c_void_p, c_void_p,
c_void_p, c_void_p,
c_size_t, c_size_t,
c_int32, c_bool,
POINTER(c_int32), c_void_p,
POINTER(POINTER(ocrpoints)),
POINTER(POINTER(c_char_p)),
) )
_OcrDetect(
_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(
self.pOcrObj, self.pOcrObj,
data, data,
len(data), len(data),
c_int32(angle), rotate,
pointer(num), CFUNCTYPE(None, ocrpoints, c_char_p)(cb),
pointer(ps),
pointer(chars),
) )
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 return pss, texts
def ocr(self, data, angle=0): def ocr(self, data, rotate=False):
try: try:
return self.__OcrDetect(data, angle) return self.__OcrDetect(data, rotate)
except: except:
print_exc() print_exc()
return [], [] return [], []
@ -226,6 +202,6 @@ class OCR(baseocr):
pss, texts = self._ocr.ocr( pss, texts = self._ocr.ocr(
imagebinary, imagebinary,
0, globalconfig["verticalocr"] == 1,
) )
return {"box": pss, "text": texts} return {"box": pss, "text": texts}

View File

@ -29,7 +29,6 @@ mylinks = {
"ja.zip": "https://github.com/test123456654321/RESOURCES/releases/download/ocr_models/ja.zip", "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", "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", "magpie.zip": "https://github.com/HIllya51/RESOURCES/releases/download/common/magpie.zip",
"themes.zip": "https://github.com/HIllya51/RESOURCES/releases/download/common/themes.zip", "themes.zip": "https://github.com/HIllya51/RESOURCES/releases/download/common/themes.zip",
} }
@ -121,8 +120,6 @@ def downloadcommon():
downloadlr() downloadlr()
subprocess.run(f"curl -LO {mylinks['mecab.zip']}") subprocess.run(f"curl -LO {mylinks['mecab.zip']}")
subprocess.run(f"7z x mecab.zip -oALL") 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"curl -LO {mylinks['magpie.zip']}")
subprocess.run(f"7z x magpie.zip -oALL") subprocess.run(f"7z x magpie.zip -oALL")

View File

@ -29,7 +29,7 @@ include(generate_product_version)
set(VERSION_MAJOR 5) set(VERSION_MAJOR 5)
set(VERSION_MINOR 55) set(VERSION_MINOR 55)
set(VERSION_PATCH 2) set(VERSION_PATCH 3)
add_library(pch pch.cpp) add_library(pch pch.cpp)
target_precompile_headers(pch PUBLIC pch.h) target_precompile_headers(pch PUBLIC pch.h)
@ -42,3 +42,4 @@ add_subdirectory(hookmagpie)
add_subdirectory(shareddllproxy) add_subdirectory(shareddllproxy)
add_subdirectory(applicationloopbackaudio) add_subdirectory(applicationloopbackaudio)
add_subdirectory(wcocr) add_subdirectory(wcocr)
add_subdirectory(LunaOCR)

View 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
View 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;
}

View File

@ -14,4 +14,4 @@ generate_product_version(
add_library(loopbackaudio MODULE runer.cpp LoopbackCapture.cpp ${versioninfo}) add_library(loopbackaudio MODULE runer.cpp LoopbackCapture.cpp ${versioninfo})
target_precompile_headers(loopbackaudio REUSE_FROM pch) target_precompile_headers(loopbackaudio REUSE_FROM pch)
target_link_libraries(loopbackaudio Mfplat mfuuid ) target_link_libraries(loopbackaudio Mfplat mfuuid wil)

View File

@ -1,8 +1,8 @@
#include "LoopbackCapture.h" #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); auto mutex = CreateSemaphoreW(NULL, 0, 1, NULL);
handlecb(mutex); 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()); datacb(loopbackCapture.buffer.data(), loopbackCapture.buffer.size());
} }
DECLARE void StopCaptureAsync(HANDLE m) DECLARE_API void StopCaptureAsync(HANDLE m)
{ {
ReleaseSemaphore(m, 1, NULL); ReleaseSemaphore(m, 1, NULL);
} }

@ -0,0 +1 @@
Subproject commit ed98928c66707988d4eb2c49a31c41380a08931c

View File

@ -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) 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)
include_directories(${CMAKE_CURRENT_LIST_DIR}) target_include_directories(Detours PUBLIC ${CMAKE_CURRENT_LIST_DIR}/Detours/src)
include_directories(${CMAKE_CURRENT_LIST_DIR}/Detours/src)
include_directories(${CMAKE_CURRENT_LIST_DIR}/wil/include) add_library(nlohmann INTERFACE)
include_directories(${CMAKE_CURRENT_LIST_DIR}/miniaudio) target_include_directories(nlohmann INTERFACE ${CMAKE_CURRENT_LIST_DIR})
include_directories(${CMAKE_CURRENT_LIST_DIR}/tinymp3)
include_directories(${CMAKE_CURRENT_LIST_DIR}/rapidfuzz-cpp)
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) if(${CMAKE_SIZEOF_VOID_P} EQUAL 4)
set(LTLPlatform "Win32") set(LTLPlatform "Win32")
endif() endif()
include("${CMAKE_CURRENT_LIST_DIR}/VC-LTL helper for cmake.cmake") 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)

View 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 ()

View 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

View File

@ -19,6 +19,7 @@
#include <algorithm> #include <algorithm>
#include <functional> #include <functional>
#include <fstream> #include <fstream>
#include <numeric>
#include <filesystem> #include <filesystem>
#include <stdexcept> #include <stdexcept>
#include <cstdint> #include <cstdint>
@ -69,7 +70,6 @@
#include <crtdefs.h> #include <crtdefs.h>
#include <memory> #include <memory>
#include <nlohmann/json.hpp>
#pragma comment(lib, "shlwapi.lib") #pragma comment(lib, "shlwapi.lib")

View File

@ -6,6 +6,7 @@ if x86:
shutil.copy('../builds/_x86/winrtutils32.dll','../../files/plugins/DLL32') shutil.copy('../builds/_x86/winrtutils32.dll','../../files/plugins/DLL32')
shutil.copy('../builds/_x86/winsharedutils32.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/wcocr.dll','../../files/plugins/DLL32')
shutil.copy('../builds/_x86/LunaOCR32.dll','../../files/plugins/DLL32')
else: else:
shutil.copy('../builds/_x64/shareddllproxy64.exe','../../files/plugins') shutil.copy('../builds/_x64/shareddllproxy64.exe','../../files/plugins')
shutil.copy('../builds/_x64/loopbackaudio.dll','../../files/plugins/DLL64') 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/winrtutils64.dll','../../files/plugins/DLL64')
shutil.copy('../builds/_x64/winsharedutils64.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/wcocr.dll','../../files/plugins/DLL64')
shutil.copy('../builds/_x64/LunaOCR64.dll','../../files/plugins/DLL64')

View File

@ -8,7 +8,7 @@ nuget_exe = os.path.join(target, "nuget.exe")
print(nuget_exe) print(nuget_exe)
if os.path.exists(nuget_exe) == False: if os.path.exists(nuget_exe) == False:
os.system( 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}") 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( subprocess.run(
rf'"{nuget_exe}" install Microsoft.Web.Webview2 -Verbosity quiet -Version "{mswebview2_version}" -OutputDirectory {target}' 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)}')

View File

@ -11,18 +11,23 @@ generate_product_version(
VERSION_PATCH ${VERSION_PATCH} 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) 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") set_target_properties(shareddllproxy PROPERTIES OUTPUT_NAME "shareddllproxy64")
else() 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(voiceroid2 REUSE_FROM pch)
target_precompile_headers(x86lib REUSE_FROM pch) target_link_libraries(shareddllproxy nlohmann Mfplat mfuuid voiceroid2 Detours)
target_link_libraries(shareddllproxy Mfplat mfuuid x86lib voiceroid2)
set_target_properties(shareddllproxy PROPERTIES OUTPUT_NAME "shareddllproxy32") set_target_properties(shareddllproxy PROPERTIES OUTPUT_NAME "shareddllproxy32")
endif() endif()

View File

@ -1,4 +1,6 @@
#include <nlohmann/json.hpp>
HANDLE runexe(const std::wstring &exe, const std::optional<std::wstring> &startup_argument) HANDLE runexe(const std::wstring &exe, const std::optional<std::wstring> &startup_argument)
{ {
STARTUPINFOW si; STARTUPINFOW si;

View File

@ -1,8 +1,8 @@
#include <stdafx.h> #include <stdafx.h>
#include <wechatocr.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); auto obj = new CWeChatOCR(wexe, wwcdir);
if (obj->wait_connection(5000)) 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) if (!pobj)
return; return;
auto obj = reinterpret_cast<CWeChatOCR *>(pobj); auto obj = reinterpret_cast<CWeChatOCR *>(pobj);
delete obj; 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) if (!pobj)
return false; return false;

View File

@ -84,7 +84,7 @@ typedef BOOL(WINAPI *pfnSetWindowCompositionAttribute)(HWND, WINDOWCOMPOSITIONAT
if (!setWindowCompositionAttribute) \ if (!setWindowCompositionAttribute) \
return false; return false;
DECLARE bool setAcrylicEffect(HWND hwnd, bool isEnableShadow) DECLARE_API bool setAcrylicEffect(HWND hwnd, bool isEnableShadow)
{ {
// win7全都用areo // win7全都用areo
DWM_BLURBEHIND bb = {0}; DWM_BLURBEHIND bb = {0};
@ -102,7 +102,7 @@ DECLARE bool setAcrylicEffect(HWND hwnd, bool isEnableShadow)
accentPolicy.AccentFlags = accentFlags; accentPolicy.AccentFlags = accentFlags;
return setWindowCompositionAttribute(hwnd, &winCompAttrData); return setWindowCompositionAttribute(hwnd, &winCompAttrData);
} }
DECLARE bool setAeroEffect(HWND hwnd, bool isEnableShadow) DECLARE_API bool setAeroEffect(HWND hwnd, bool isEnableShadow)
{ {
DWM_BLURBEHIND bb = {0}; DWM_BLURBEHIND bb = {0};
bb.dwFlags = DWM_BB_ENABLE; bb.dwFlags = DWM_BB_ENABLE;
@ -117,7 +117,7 @@ DECLARE bool setAeroEffect(HWND hwnd, bool isEnableShadow)
accentPolicy.AccentFlags = accentFlags; accentPolicy.AccentFlags = accentFlags;
return setWindowCompositionAttribute(hwnd, &winCompAttrData); return setWindowCompositionAttribute(hwnd, &winCompAttrData);
} }
DECLARE bool clearEffect(HWND hwnd) DECLARE_API bool clearEffect(HWND hwnd)
{ {
DWM_BLURBEHIND bb = {0}; DWM_BLURBEHIND bb = {0};
bb.dwFlags = DWM_BB_ENABLE; bb.dwFlags = DWM_BB_ENABLE;

View File

@ -10,10 +10,9 @@ generate_product_version(
VERSION_MINOR ${VERSION_MINOR} VERSION_MINOR ${VERSION_MINOR}
VERSION_PATCH ${VERSION_PATCH} 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}) 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_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) if(${CMAKE_SIZEOF_VOID_P} EQUAL 8)
set_target_properties(winsharedutils PROPERTIES OUTPUT_NAME "winsharedutils64") set_target_properties(winsharedutils PROPERTIES OUTPUT_NAME "winsharedutils64")
else() else()

View File

@ -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); HANDLE hsema = CreateSemaphoreW(0, 0, 10, 0);
HWND hwnd; HWND hwnd;
@ -137,7 +137,7 @@ DECLARE HWND clipboard_callback(void (*callback)(const wchar_t *, bool))
else else
return NULL; return NULL;
} }
DECLARE void clipboard_callback_stop(HWND hwnd) DECLARE_API void clipboard_callback_stop(HWND hwnd)
{ {
if (!hwnd) if (!hwnd)
return; return;
@ -145,7 +145,7 @@ DECLARE void clipboard_callback_stop(HWND hwnd)
DestroyWindow(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); size -= sizeof(BITMAPFILEHEADER);
HGLOBAL hDib = GlobalAlloc(GMEM_MOVEABLE, size); HGLOBAL hDib = GlobalAlloc(GMEM_MOVEABLE, size);

View File

@ -1,5 +1,5 @@
#pragma once #pragma once
#define DECLARE extern "C" __declspec(dllexport) #define DECLARE_API extern "C" __declspec(dllexport)
extern "C" extern "C"
{ {

View File

@ -52,12 +52,12 @@ void globalmessagelistener_1(void *callback)
DispatchMessage(&msg); DispatchMessage(&msg);
} }
} }
DECLARE void globalmessagelistener(void *callback) DECLARE_API void globalmessagelistener(void *callback)
{ {
std::thread(std::bind(globalmessagelistener_1, callback)).detach(); std::thread(std::bind(globalmessagelistener_1, callback)).detach();
} }
DECLARE void dispatchcloseevent() DECLARE_API void dispatchcloseevent()
{ {
PostMessage(HWND_BROADCAST, LUNA_UPDATE_PREPARED_OK, 0, 0); PostMessage(HWND_BROADCAST, LUNA_UPDATE_PREPARED_OK, 0, 0);
} }

View File

@ -1,6 +1,6 @@
#include "define.h" #include "define.h"
#include <shellscalingapi.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会改变窗口样式因此只对无边框窗口使用。 // WS_EX_TOOLWINDOW可以立即生效WS_EX_APPWINDOW必须切换焦点才生效。但是WS_EX_TOOLWINDOW会改变窗口样式因此只对无边框窗口使用。
LONG style = GetWindowLong(hwnd, GWL_STYLE); 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); SetWindowLong(hwnd, GWL_EXSTYLE, style_ex);
} }
DECLARE bool pid_running(DWORD pid) DECLARE_API bool pid_running(DWORD pid)
{ {
DWORD code; DWORD code;
GetExitCodeProcess(AutoHandle(OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, pid)), &code); GetExitCodeProcess(AutoHandle(OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, pid)), &code);
@ -54,14 +54,14 @@ BOOL CALLBACK EnumWindowsProc(HWND hwnd, LPARAM lParam)
} }
return TRUE; return TRUE;
} }
DECLARE HWND getpidhwndfirst(DWORD pid) DECLARE_API HWND getpidhwndfirst(DWORD pid)
{ {
__EnumWindowsProc info = {pid, 0}; __EnumWindowsProc info = {pid, 0};
EnumWindows(EnumWindowsProc, (LPARAM)&info); EnumWindows(EnumWindowsProc, (LPARAM)&info);
return info.hwnd; return info.hwnd;
} }
DECLARE bool Is64bit(DWORD pid) DECLARE_API bool Is64bit(DWORD pid)
{ {
SYSTEM_INFO sysinfo; SYSTEM_INFO sysinfo;
GetNativeSystemInfo(&sysinfo); GetNativeSystemInfo(&sysinfo);
@ -78,7 +78,7 @@ DECLARE bool Is64bit(DWORD pid)
return false; 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; std::unordered_map<std::wstring, std::vector<int>> exe_pid;
AutoHandle hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); AutoHandle hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
@ -96,7 +96,7 @@ DECLARE void getprocesses(void (*cb)(DWORD, const wchar_t *))
} while (Process32Next(hSnapshot, &pe32)); } while (Process32Next(hSnapshot, &pe32));
} }
} }
DECLARE UINT GetMonitorDpiScaling(HWND hwnd) DECLARE_API UINT GetMonitorDpiScaling(HWND hwnd)
{ {
HMONITOR hMonitor = MonitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST); HMONITOR hMonitor = MonitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST);
if (!hMonitor) if (!hMonitor)

View File

@ -12,7 +12,7 @@
int stereo = STEREO; 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_config_t config;
shine_t s; shine_t s;

View File

@ -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); auto _c = std::wstring(Content);
if (auto _ = std::move(SAPI::Speak(_c, version, voiceid, rate, volume))) if (auto _ = std::move(SAPI::Speak(_c, version, voiceid, rate, volume)))

View File

@ -157,7 +157,7 @@ std::vector<byte> SaveBitmapToBuffer(HBITMAP hBitmap)
return data; 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) if (rect.bottom == rect.top || rect.left == rect.right)
return; return;
@ -176,7 +176,7 @@ DECLARE void gdi_screenshot(HWND hwnd, RECT rect, void (*cb)(byte *, size_t))
ReleaseDC(hwnd, hdc); ReleaseDC(hwnd, hdc);
} }
DECLARE void maximum_window(HWND hwnd) DECLARE_API void maximum_window(HWND hwnd)
{ {
RECT rect; RECT rect;
GetVirtualDesktopRect(rect); GetVirtualDesktopRect(rect);

View File

@ -150,13 +150,13 @@ static void SetWindowTheme(HWND hWnd, bool darkBorder, bool darkMenu) noexcept
RefreshImmersiveColorPolicyState(); RefreshImmersiveColorPolicyState();
FlushMenuThemes(); FlushMenuThemes();
} }
DECLARE void setdwmextendframe(HWND hwnd) DECLARE_API void setdwmextendframe(HWND hwnd)
{ {
MARGINS mar{-1, -1, -1, -1}; MARGINS mar{-1, -1, -1, -1};
DwmExtendFrameIntoClientArea(hwnd, &mar); DwmExtendFrameIntoClientArea(hwnd, &mar);
} }
DECLARE void _SetTheme( DECLARE_API void _SetTheme(
HWND _hWnd, HWND _hWnd,
bool dark, bool dark,
int backdrop) int backdrop)
@ -191,7 +191,7 @@ DECLARE void _SetTheme(
DwmSetWindowAttribute(_hWnd, DWMWA_SYSTEMBACKDROP_TYPE, &value, sizeof(value)); DwmSetWindowAttribute(_hWnd, DWMWA_SYSTEMBACKDROP_TYPE, &value, sizeof(value));
} }
DECLARE bool isDark() DECLARE_API bool isDark()
{ {
HKEY hKey; HKEY hKey;
const char *subKey = "Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize"; const char *subKey = "Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize";

View File

@ -11,7 +11,7 @@ using namespace Microsoft::WRL;
if (FAILED((x))) \ if (FAILED((x))) \
return x; return x;
DECLARE void set_transparent_background(void* m_host){ DECLARE_API void set_transparent_background(void* m_host){
COREWEBVIEW2_COLOR color; COREWEBVIEW2_COLOR color;
ZeroMemory(&color,sizeof(color)); ZeroMemory(&color,sizeof(color));
wil::com_ptr<ICoreWebView2Controller> m_controller(reinterpret_cast<ICoreWebView2Controller *>(m_host)); 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)); 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; 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; EventRegistrationToken *m_zoomFactorChangedToken = new EventRegistrationToken;
// Register a handler for the ZoomFactorChanged event. // Register a handler for the ZoomFactorChanged event.
@ -58,19 +58,19 @@ DECLARE void *add_ZoomFactorChanged(void *m_host, void (*signal)(double))
m_zoomFactorChangedToken); m_zoomFactorChangedToken);
return 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)); reinterpret_cast<ICoreWebView2Controller *>(m_host)->remove_ZoomFactorChanged(*reinterpret_cast<EventRegistrationToken *>(m_zoomFactorChangedToken));
delete m_zoomFactorChangedToken; delete m_zoomFactorChangedToken;
} }
DECLARE double get_ZoomFactor(void *m_host) DECLARE_API double get_ZoomFactor(void *m_host)
{ {
double zoomFactor; double zoomFactor;
reinterpret_cast<ICoreWebView2Controller *>(m_host)->get_ZoomFactor(&zoomFactor); reinterpret_cast<ICoreWebView2Controller *>(m_host)->get_ZoomFactor(&zoomFactor);
return 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); reinterpret_cast<ICoreWebView2Controller *>(m_host)->put_ZoomFactor(zoomFactor);
} }