目前测试完成了编译器下的使用,是没问题的,运行时有待测试,并且目前仅支持x64
构建方案参考自Gemini3Pro大模型。
写本文章时,使用的zxing-cpp 仓库提交版本为:zxing-cpp/zxing-cpp at d41fd4189266aaaeff0a15e1df02858084284bbf
准备
CMake:手动编译适用于UE的ZXing.dll
zxing-cpp:zxing库的C++实现源码库:zxing-cpp/zxing-cpp: C++ port of ZXing
Developer PowerShell for VS 2022:需要启用相关支持
编译过程
拉取仓库:
git clone https://github.com/zxing-cpp/zxing-cpp.git
cd zxing-cppgithub仓库依赖了一个字仓库,初始化一下
# 1. 初始化子模块(读取.gitmodules配置,注册子模块路径)
git submodule init
# 2. 拉取所有子模块的实际代码
git submodule update
#或者一步到位
# 初始化 + 拉取所有子模块(包括嵌套子模块)
git submodule update --init --recursive下面生成干净的 Include 和 Lib (使用 CMake Install)
启动Developer PowerShell for VS 2022 然后切到仓库根目录,在根目录下创建build 目录
mkdir build && cd build生成cmake工程:这里我们需要指定 CMAKE_INSTALL_PREFIX,告诉 CMake 把整理好的文件放到哪里(比如当前目录下的 output 文件夹)。
cmake .. -G "Visual Studio 17 2022" -A x64 -DCMAKE_CXX_STANDARD=20 -DBUILD_SHARED_LIBS=OFF -DZXING_BUILD_EXAMPLES=OFF -DZXING_BUILD_BLACKBOX_TESTS=OFF -DCMAKE_INSTALL_PREFIX="./output"编译我们需要的
cmake --build . --config Release --target install然后打开打开 build/output 文件夹,您会看到完美的结构:
include/ZXing/:里面是所有整理好的.h头文件。lib/:里面是ZXing.lib。
目录结构如下:
📂 output (D:\Other\zxing-cpp\build\output)
├─ 📂 bin
│ ├─ 📄 ZXingReader.exe (946.00 KB)
│ └─ 📄 ZXingWriter.exe (521.50 KB)
├─ 📂 include
│ └─ 📂 ZXing
│ ├─ 📄 Barcode.h (6.83 KB)
│ ├─ 📄 BarcodeFormat.h (2.93 KB)
│ ├─ 📄 BitHacks.h (6.14 KB)
│ ├─ 📄 BitMatrix.h (5.60 KB)
│ ├─ 📄 BitMatrixIO.h (643 B)
│ ├─ 📄 ByteArray.h (1.44 KB)
│ ├─ 📄 CharacterSet.h (782 B)
│ ├─ 📄 Content.h (2.41 KB)
│ ├─ 📄 DecodeHints.h (245 B)
│ ├─ 📄 Error.h (2.93 KB)
│ ├─ 📄 Flags.h (4.46 KB)
│ ├─ 📄 GTIN.h (1.49 KB)
│ ├─ 📄 ImageView.h (5.09 KB)
│ ├─ 📄 Matrix.h (2.30 KB)
│ ├─ 📄 MultiFormatWriter.h (1.35 KB)
│ ├─ 📄 Point.h (3.39 KB)
│ ├─ 📄 Quadrilateral.h (5.30 KB)
│ ├─ 📄 Range.h (3.79 KB)
│ ├─ 📄 ReadBarcode.h (870 B)
│ ├─ 📄 ReaderOptions.h (7.04 KB)
│ ├─ 📄 Result.h (239 B)
│ ├─ 📄 StructuredAppend.h (249 B)
│ ├─ 📄 TextUtfEncoding.h (566 B)
│ ├─ 📄 Version.h (334 B)
│ ├─ 📄 ZXAlgorithms.h (5.65 KB)
│ ├─ 📄 ZXingCpp.h (496 B)
│ └─ 📄 ZXVersion.h (211 B)
└─ 📂 lib
├─ 📂 cmake
│ └─ 📂 ZXing
│ ├─ 📄 ZXingConfig.cmake (1.21 KB)
│ ├─ 📄 ZXingConfigVersion.cmake (2.76 KB)
│ ├─ 📄 ZXingTargets.cmake (4.58 KB)
│ └─ 📄 ZXingTargets-release.cmake (850 B)
└─ 📄 ZXing.lib (15.86 MB)对应文件已在Github开源,可直接使用
在插件中建立目录结构
假设您的插件目录是 Plugins/MyCustomPlugin。请按以下结构放置文件:
MyProject/
└── Plugins/
└── MyCustomPlugin/
├── Source/
│ ├── MyCustomPlugin/
│ │ ├── MyCustomPlugin.Build.cs
│ │ └── ...
│ └── ThirdParty/ <-- 在插件Source下新建
│ └── ZXing/ <-- 新建 ZXing 文件夹
│ ├── Include/ <-- 将刚才 output/include 下的 "ZXing" 文件夹整个拷进来
│ │ └── ZXing/ <-- 结构应该是 Include/ZXing/ReadBarcode.h
│ └── Lib/
│ └── Win64/ <-- 将 output/lib/ZXing.lib 拷进来注意:最终的头文件路径应该是 .../ThirdParty/ZXing/Include/ZXing/ReadBarcode.h。这样我们在代码里就可以用标准的 #include "ZXing/ReadBarcode.h" 方式引用了。
配置插件的 Build.cs
在插件环境中,ModuleDirectory 指向的是 Plugins/MyCustomPlugin/Source/MyCustomPlugin。我们需要用它来定位 ThirdParty。
打开 Plugins/MyCustomPlugin/Source/MyCustomPlugin/MyCustomPlugin.Build.cs:
using UnrealBuildTool;
using System.IO; // 必加
public class MyCustomPlugin : ModuleRules
{
public MyCustomPlugin(ReadOnlyTargetRules Target) : base(Target)
{
PCHUsage = ModuleRules.PCHUsageMode.UseExplicitOrSharedPCHs;
// 开启 C++20 (ZXing 需要)
CppStandard = CppStandardVersion.Cpp20;
PublicDependencyModuleNames.AddRange(
new string[]
{
"Core",
"CoreUObject",
"Engine",
"Projects", // 插件开发常需要这个
// ... 其他依赖
}
);
// --- ZXing 集成 ---
// 1. 定位到 ThirdParty 目录
// ModuleDirectory 是当前 .Build.cs 所在目录
string ThirdPartyPath = Path.GetFullPath(Path.Combine(ModuleDirectory, "../ThirdParty"));
string ZXingIncludePath = Path.Combine(ThirdPartyPath, "ZXing", "Include");
string ZXingLibPath = Path.Combine(ThirdPartyPath, "ZXing", "Lib", "Win64", "ZXing.lib");
// 2. 检查文件是否存在 (良好的习惯,防止路径错误导致莫名其妙的链接失败)
if (!Directory.Exists(ZXingIncludePath))
{
throw new BuildException("ZXing Include path not found: " + ZXingIncludePath);
}
// 3. 添加头文件包含路径
// 这样在代码里就可以写 #include "ZXing/ReadBarcode.h"
PublicIncludePaths.Add(ZXingIncludePath);
// 4. 链接静态库
if (Target.Platform == UnrealTargetPlatform.Win64)
{
PublicAdditionalLibraries.Add(ZXingLibPath);
}
// --- 集成结束 ---
}
}此时就可以在代码中愉快的引用了
// 此时 Include 目录下有 ZXing 子目录,所以前缀是 ZXing/
#include "ZXing/ReadBarcode.h"
#include "ZXing/ImageView.h"简易代码
.h
#pragma once
// UE核心头文件(只包含一次)
#include "CoreMinimal.h"
#include "Kismet/BlueprintFunctionLibrary.h"// 自身的generated头文件(放在最后)
#include "CommonUtility.generated.h"
/**
*
*/
UCLASS()
class PROJECTPLUGINS_API UCommonUtility: public UBlueprintFunctionLibrary
{
GENERATED_BODY()
public:
/**
* 生成二维码纹理
* @param Content 二维码内容 (URL或文本)
* @param Width 生成的图片宽度 (像素)
* @param Height 生成的图片高度 (像素)
* @param Margin 二维码白边宽度 (通常设为0-4)
* @param OutTexture 生成的纹理对象
* @return 是否生成成功
*/
UFUNCTION(BlueprintCallable, Category = "ZXing|Generation")
static bool GenerateQRCode(FString Content, int32 Width, int32 Height, int32 Margin, UTexture2D*& OutTexture);
};
.cpp
// 防止 Windows 宏冲突
THIRD_PARTY_INCLUDES_START
#include "ZXing/MultiFormatWriter.h"
#include "ZXing/BitMatrix.h"
#include "ZXing/CharacterSet.h" // <--- 新增这一行
THIRD_PARTY_INCLUDES_END
#include "Engine/Texture2D.h"
#include "TextureResource.h"
bool UCommonUtility::GenerateQRCode(FString Content, int32 Width, int32 Height, int32 Margin, UTexture2D*& OutTexture)
{
OutTexture = nullptr;
if (Content.IsEmpty() || Width <= 0 || Height <= 0)
{
UE_LOG(LogTemp, Error, TEXT("GenerateQRCode: 内容为空或尺寸无效"));
return false;
}
try
{
// 1. 配置 Writer
ZXing::MultiFormatWriter Writer(ZXing::BarcodeFormat::QRCode);
// --- [关键修复] 设置编码格式为 UTF-8 ---
Writer.setEncoding(ZXing::CharacterSet::UTF8);
// -------------------------------------
Writer.setMargin(Margin);
// 2. 编码 (将 FString 转为 std::string UTF8)
// TCHAR_TO_UTF8 会将中文转为正确的 UTF-8 字节流
std::string TextStr = TCHAR_TO_UTF8(*Content);
// 生成位矩阵
auto Matrix = Writer.encode(TextStr, Width, Height);
// 获取实际生成的宽高 (zxing 可能会根据内容调整实际大小)
int32 RealWidth = Matrix.width();
int32 RealHeight = Matrix.height();
// 3. 创建 UE5 纹理
// PF_B8G8R8A8 是 UI 和材质常用的格式
UTexture2D* NewTexture = UTexture2D::CreateTransient(RealWidth, RealHeight, PF_B8G8R8A8);
if (!NewTexture) return false;
// 4. 锁定纹理内存以便写入
FTexture2DMipMap& Mip = NewTexture->GetPlatformData()->Mips[0];
void* Data = Mip.BulkData.Lock(LOCK_READ_WRITE);
// 转换为 FColor 指针方便操作像素
FColor* RawData = static_cast<FColor*>(Data);
// 5. 将 BitMatrix 转换为像素颜色
// ZXing Matrix 中 true 为黑(前景),false 为白(背景)
// 注意:RawData 是由上到下,由左到右排列的数组
for (int32 y = 0; y < RealHeight; y++)
{
for (int32 x = 0; x < RealWidth; x++)
{
bool bIsBlack = Matrix.get(x, y);
// 写入颜色:黑色或白色 (Alpha 设为 255)
// 数组索引 = y * 宽度 + x
RawData[y * RealWidth + x] = bIsBlack ? FColor::Black : FColor::White;
}
}
// 6. 解锁并更新资源
Mip.BulkData.Unlock();
// 配置纹理属性以获得清晰的像素化效果 (二维码不应该被模糊/抗锯齿)
NewTexture->Filter = TextureFilter::TF_Nearest;
NewTexture->SRGB = true; // 既然是 UI 显示,通常开启 sRGB
NewTexture->UpdateResource();
OutTexture = NewTexture;
return true;
}
catch (const std::exception& e)
{
// 捕获 ZXing 可能抛出的异常 (例如内容太长导致无法生成)
UE_LOG(LogTemp, Error, TEXT("ZXing Generation Error: %s"), UTF8_TO_TCHAR(e.what()));
return false;
}
}
评论