add qr generator

This commit is contained in:
2020-11-30 15:33:21 +05:00
parent a907d8bbeb
commit 2b8916de8c
43 changed files with 3726 additions and 1 deletions
@@ -0,0 +1,355 @@
// Fill out your copyright notice in the Description page of Project Settings.
#include "QRCodeBlueprintFunctionLibrary.h"
#include "qrencode.h"
#include <string>
#include <fstream>
#include "IImageWrapper.h"
//#include "ModuleManager.h"
#include "ImageWrapper/Public/IImageWrapper.h"
#include "IImageWrapperModule.h"
//#include "FileManagerGeneric.h"
#include "HAL/FileManagerGeneric.h"
using namespace std;
#define BI_RGB 0
//#pragma pack(push, 2)必须要加。bfType是2个字节,对应“BM”,后4个字节是文件大小,又对应4字节。
//如果不设定对齐方式,而按默认的8字节或4字节对应,这些属性就错位了,而别人又是按标准来读取的,
//对齐方式不同,自然出错。一般情况下的编程之所以不考虑这些问题,是因为读取和保存都是你个人完成的,
//对齐方式是一样的,自然不出错。而这里你生成的图片可能还要供别人使用,自然要严格遵守标准。
#pragma pack(push, 2)//必须得写,否则sizeof得不到正确的结果
typedef unsigned char BYTE;
typedef unsigned short WORD;
typedef unsigned long DWORD;
typedef long LONG;
typedef struct {
WORD bfType;//位图文件的类型,必须为BM(1-2字节)
DWORD bfSize;//位图文件的大小,以字节为单位(3-6字节,低位在前)
WORD bfReserved1;//位图文件保留字,必须为0(7-8字节)
WORD bfReserved2;//位图文件保留字,必须为0(9-10字节)
DWORD bfOffBits;//位图数据的起始位置,以相对于位图(11-14字节,低位在前)
} BITMAPFILEHEADER;
typedef struct {
DWORD biSize;//本结构所占用字节数(15-18字节)
LONG biWidth;//位图的宽度,以像素为单位(19-22字节)
LONG biHeight;//位图的高度,以像素为单位(23-26字节)
WORD biPlanes;//目标设备的级别,必须为1(27-28字节)
WORD biBitCount;//每个像素所需的位数,必须是1(双色),4(16色),8(256色)16(高彩色)或24(真彩色)之一,(29-30字节)
DWORD biCompression;//位图压缩类型,必须是0(不压缩),1(BI_RLE8压缩类型)或2(BI_RLE4压缩类型)之一,31-34字节)
DWORD biSizeImage;//位图的大小(其中包含了为了补齐行数是4的倍数而添加的空字节),以字节为单位(35-38字节)
LONG biXPelsPerMeter;//位图水平分辨率,每米像素数(39-42字节)
LONG biYPelsPerMeter;//位图垂直分辨率,每米像素数(43-46字节)
DWORD biClrUsed;//位图实际使用的颜色表中的颜色数(47-50字节)
DWORD biClrImportant;//位图显示过程中重要的颜色数(51-54字节)
} BITMAPINFOHEADER;
#pragma pack(pop)
void UQRCodeBlueprintFunctionLibrary::GenerateQRCodeBitmap(const int32& Width, const int32& Height, const FString& Name, const FString& Outfile, int32 Margin /* = 0 */)
{
std::string StdName(TCHAR_TO_UTF8(*Name));
const char* QRCodeStr = StdName.c_str();
QRcode* QRCodePtr = nullptr;
QRCodePtr = QRcode_encodeString(QRCodeStr, 1, QR_ECLEVEL_L, QR_MODE_8, 1);
if (QRCodePtr)
{
uint32 QRWidth, QRWidthAdjustedX, QRHeightAdjustedY, QRDataBytes;
QRWidth = QRCodePtr->width;//矩阵的维数
uint32 ScaleX = (Width - 2 * Margin) / QRWidth;
uint32 ScaleY = (Height - 2 * Margin) / QRWidth;
QRWidthAdjustedX = QRWidth * ScaleX;//水平维度占的像素个数(ScaleX)
QRHeightAdjustedY = QRWidth * ScaleY;//垂直维度占的像素个数(ScaleY)
QRDataBytes = QRWidthAdjustedX * QRHeightAdjustedY * 3;//每一个像素3个字节(BGR)
//create data
uint8* RGBDataPtr = (uint8 *)malloc(QRDataBytes);
if (!RGBDataPtr)
{
printf("out of memory!!");
return;
}
uint8* QRCodeSourceDatas = QRCodePtr->data;
uint8* QRCodeDestData;
memset(RGBDataPtr, 0xFF, QRDataBytes); //分配内存,并且填充为白色
//由于Windows规定一个扫描行所占的字节数必须是4的倍数,这里必须是4的整数倍
int32 WidthAdjusted = Width % 4 ? (Width / 4 + 1) * 4 : Width;
uint32 ImageBytes = WidthAdjusted * Height * 3;
//create bitmap file header
BITMAPFILEHEADER FileHeader;
FileHeader.bfType = 0x4D42; //"BM"
FileHeader.bfReserved1 = 0;
FileHeader.bfReserved2 = 0;
FileHeader.bfSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + ImageBytes;
FileHeader.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
//create bitmap info header
BITMAPINFOHEADER InfoHeader = {0};//所有值默认为0
InfoHeader.biSize = sizeof(BITMAPINFOHEADER);
InfoHeader.biWidth = WidthAdjusted;
//说明图象的高度,以象素为单位。注:这个值除了用于描述图像的高度之外,它还有另一个用处,
//就是指明该图像是倒向的位图,还是正向的位图。如果该值是一个正数,说明图像是倒向的,
//如果该值是一个负数,则说明图像是正向的。大多数的BMP文件都是倒向的位图,也就是时,
//高度值是一个正数。(注:当高度值是一个负数时(正向图像),图像将不能被压缩
//(也就是说biCompression成员将不能是BI_RLE8或BI_RLE4)。
InfoHeader.biHeight = -(int32)Height;
InfoHeader.biPlanes = 1;
InfoHeader.biBitCount = 24;
InfoHeader.biCompression = BI_RGB;
InfoHeader.biSizeImage = ImageBytes;
for (uint32 y = 0; y < QRWidth; y++)
{
QRCodeDestData = RGBDataPtr + ScaleY * y * QRWidthAdjustedX * 3;
for (uint32 x = 0; x < QRWidth; x++)
{
if (*QRCodeSourceDatas & 0x01)
{
for (uint32 rectY = 0; rectY < ScaleY; rectY++)
{
for (uint32 rectX = 0; rectX < ScaleX; rectX++)
{
*(QRCodeDestData + rectY * QRWidthAdjustedX * 3 + rectX * 3) = 0;//Blue
*(QRCodeDestData + rectY * QRWidthAdjustedX * 3 + rectX * 3 + 1) = 0;//Green
*(QRCodeDestData + rectY * QRWidthAdjustedX * 3 + rectX * 3 + 2) = 0;//Red
}
}
}
QRCodeDestData += ScaleX * 3;
QRCodeSourceDatas += 1;
}
}
uint8* ImageDataPtr = (uint8 *)malloc(ImageBytes);
memset(ImageDataPtr, 0xFF, ImageBytes); //分配内存,并且填充为白色
for (uint32 y = Margin; y < QRHeightAdjustedY + Margin; y++)
{
for (uint32 x = Margin; x < QRWidthAdjustedX + Margin; x++)
{
for (int32 PixelByte = 0; PixelByte < 3; PixelByte++)
{
uint32 ImageIndex = (y * WidthAdjusted + x) * 3 + PixelByte;
uint32 RGBDataIndex = ((y - Margin) * QRWidthAdjustedX + (x - Margin)) * 3 + PixelByte;
ImageDataPtr[ImageIndex] = RGBDataPtr[RGBDataIndex];
}
}
}
if (!FFileManagerGeneric::Get().DirectoryExists(*Outfile))
{
FFileManagerGeneric::Get().MakeDirectory(*FPaths::GetPath(Outfile), true);
}
FILE* BitmapFile;
if (!(fopen_s(&BitmapFile, TCHAR_TO_UTF8(*Outfile), "wb")))
{
fwrite(&FileHeader, sizeof(BITMAPFILEHEADER), 1, BitmapFile);
fwrite(&InfoHeader, sizeof(BITMAPINFOHEADER), 1, BitmapFile);
fwrite(ImageDataPtr, sizeof(uint8), ImageBytes, BitmapFile);
fclose(BitmapFile);
}
else
{
printf("create file failed!!");
}
QRcode_free(QRCodePtr);
free(RGBDataPtr);
if (Margin > 0)
{
free(ImageDataPtr);
}
}
}
UTexture2D* UQRCodeBlueprintFunctionLibrary::GenerateQRCodeTexture(const int32& Width, const int32& Height, const FString& Name, int32 Margin /* = 0 */)
{
std::string StdName(TCHAR_TO_UTF8(*Name));
const char* QRCodeStr = StdName.c_str();
QRcode* QRCodePtr = nullptr;
QRCodePtr = QRcode_encodeString(QRCodeStr, 1, QR_ECLEVEL_L, QR_MODE_8, 1);
UTexture2D* Texture = nullptr;
if (QRCodePtr)
{
uint32 QRWidth, QRWidthAdjustedX, QRHeightAdjustedY, QRDataBytes;
QRWidth = QRCodePtr->width;//矩阵的维数
uint32 ScaleX = (Width - 2 * Margin) / QRWidth;
uint32 ScaleY = (Height - 2 * Margin) / QRWidth;
QRWidthAdjustedX = QRWidth * ScaleX;//水平维度占的像素个数(ScaleX)
QRHeightAdjustedY = QRWidth * ScaleY;//垂直维度占的像素个数(ScaleY)
QRDataBytes = QRWidthAdjustedX * QRHeightAdjustedY * 3;//每一个像素3个字节(BGR)
uint8* RGBDataPtr = (uint8 *)malloc(QRDataBytes);
if (!RGBDataPtr)
{
printf("out of memory!!");
return Texture;
}
uint8* QRCodeSourceDatas = QRCodePtr->data;
uint8* QRCodeDestData;
memset(RGBDataPtr, 0xFF, QRDataBytes); //分配内存,并且填充为白色
for (uint32 y = 0; y < QRWidth; y++)
{
QRCodeDestData = RGBDataPtr + ScaleY * y * QRWidthAdjustedX * 3;
for (uint32 x = 0; x < QRWidth; x++)
{
if (*QRCodeSourceDatas & 0x01)
{
for (uint32 rectY = 0; rectY < ScaleY; rectY++)
{
for (uint32 rectX = 0; rectX < ScaleX; rectX++)
{
*(QRCodeDestData + rectY * QRWidthAdjustedX * 3 + rectX * 3) = 0;//Blue
*(QRCodeDestData + rectY * QRWidthAdjustedX * 3 + rectX * 3 + 1) = 0;//Green
*(QRCodeDestData + rectY * QRWidthAdjustedX * 3 + rectX * 3 + 2) = 0;//Red
}
}
}
QRCodeDestData += ScaleX * 3;
QRCodeSourceDatas += 1;
}
}
QRcode_free(QRCodePtr);
TArray<uint8> ImageBGRAData;
//for (uint32 i = 0; i < QRDataBytes; i++)
//{
// ImageBGRAData.Add(RGBDataPtr[i]);
// if ((i + 1) % 3 == 0)
// {
// ImageBGRAData.Add(0xFF);//填充Alpha通道为不透明
// }
//}
for (uint32 i = 0; i < (uint32)Width * (uint32)Height * 4; i++)
{
ImageBGRAData.Add(0xFF);
}
for (uint32 y = Margin; y < QRHeightAdjustedY + Margin; y++)
{
for (uint32 x = Margin; x < QRWidthAdjustedX + Margin; x++)
{
for (int32 PixelByte = 0; PixelByte < 3; PixelByte++)
{
uint32 ImageIndex = ( y * Width + x ) * 4 + PixelByte;
uint32 RGBDataIndex = ((y - Margin) * QRWidthAdjustedX + (x - Margin)) * 3 + PixelByte;
ImageBGRAData[ImageIndex] = RGBDataPtr[RGBDataIndex];
}
}
}
free(RGBDataPtr);
IImageWrapperModule& ImageWrapperModule = FModuleManager::LoadModuleChecked<IImageWrapperModule>(FName("ImageWrapper"));
TSharedPtr<IImageWrapper> TargetImageWrapper = ImageWrapperModule.CreateImageWrapper(EImageFormat::BMP);
if (TargetImageWrapper.IsValid())
{
Texture = UTexture2D::CreateTransient(Width, Height, PF_B8G8R8A8);
if (Texture != nullptr)
{
FTexture2DMipMap& Mip = Texture->PlatformData->Mips[0];
void* TextureData = Mip.BulkData.Lock(LOCK_READ_WRITE);
FMemory::Memcpy(TextureData, ImageBGRAData.GetData(), ImageBGRAData.Num());
Mip.BulkData.Unlock();
Texture->UpdateResource();
}
}
}
return Texture;
}
bool UQRCodeBlueprintFunctionLibrary::GenerateQRCodeImageByType(const int32& Width, const int32& Height, const FString& Name, const FString& Outfile, QR_IMAGE_FORMAT ImageFormat, int32 Margin /*= 0*/)
{
std::string StdName(TCHAR_TO_UTF8(*Name));
const char* QRCodeStr = StdName.c_str();
QRcode* QRCodePtr = nullptr;
QRCodePtr = QRcode_encodeString(QRCodeStr, 1, QR_ECLEVEL_L, QR_MODE_8, 1);
UTexture2D* Texture = nullptr;
if (QRCodePtr)
{
uint32 QRWidth, QRWidthAdjustedX, QRHeightAdjustedY, QRDataBytes;
QRWidth = QRCodePtr->width;//矩阵的维数
uint32 ScaleX = (Width - 2 * Margin) / QRWidth;
uint32 ScaleY = (Height - 2 * Margin) / QRWidth;
QRWidthAdjustedX = QRWidth * ScaleX;//水平维度占的像素个数(ScaleX)
QRHeightAdjustedY = QRWidth * ScaleY;//垂直维度占的像素个数(ScaleY)
QRDataBytes = QRWidthAdjustedX * QRHeightAdjustedY * 3;//每一个像素3个字节(BGR)
uint8* RGBDataPtr = (uint8 *)malloc(QRDataBytes);
if (!RGBDataPtr)
{
printf("out of memory!!");
return false;
}
uint8* QRCodeSourceDatas = QRCodePtr->data;
uint8* QRCodeDestData;
memset(RGBDataPtr, 0xFF, QRDataBytes); //分配内存,并且填充为白色
for (uint32 y = 0; y < QRWidth; y++)
{
QRCodeDestData = RGBDataPtr + ScaleY * y * QRWidthAdjustedX * 3;
for (uint32 x = 0; x < QRWidth; x++)
{
if (*QRCodeSourceDatas & 0x01)
{
for (uint32 rectY = 0; rectY < ScaleY; rectY++)
{
for (uint32 rectX = 0; rectX < ScaleX; rectX++)
{
*(QRCodeDestData + rectY * QRWidthAdjustedX * 3 + rectX * 3) = 0;//Blue
*(QRCodeDestData + rectY * QRWidthAdjustedX * 3 + rectX * 3 + 1) = 0;//Green
*(QRCodeDestData + rectY * QRWidthAdjustedX * 3 + rectX * 3 + 2) = 0;//Red
}
}
}
QRCodeDestData += ScaleX * 3;
QRCodeSourceDatas += 1;
}
}
QRcode_free(QRCodePtr);
TArray<uint8> ImageBGRAData;
for (uint32 i = 0; i < (uint32)Width * (uint32)Height * 4; i++)
{
ImageBGRAData.Add(0xFF);
}
for (uint32 y = Margin; y < QRHeightAdjustedY + Margin; y++)
{
for (uint32 x = Margin; x < QRWidthAdjustedX + Margin; x++)
{
for (int32 PixelByte = 0; PixelByte < 3; PixelByte++)
{
uint32 ImageIndex = (y * Width + x) * 4 + PixelByte;
uint32 RGBDataIndex = ((y - Margin) * QRWidthAdjustedX + (x - Margin)) * 3 + PixelByte;
ImageBGRAData[ImageIndex] = RGBDataPtr[RGBDataIndex];
}
}
}
free(RGBDataPtr);
IImageWrapperModule& ImageWrapperModule = FModuleManager::LoadModuleChecked<IImageWrapperModule>(FName("ImageWrapper"));
TSharedPtr<IImageWrapper> TargetImageWrapper = ImageWrapperModule.CreateImageWrapper(EImageFormat(ImageFormat));
if (TargetImageWrapper.IsValid())
{
if (TargetImageWrapper->SetRaw(ImageBGRAData.GetData(), ImageBGRAData.Num(), Width, Height, ERGBFormat::BGRA, 8))
{
const TArray<uint8, FDefaultAllocator64> TagetImageData = TargetImageWrapper->GetCompressed();
if (!FFileManagerGeneric::Get().DirectoryExists(*Outfile))
{
FFileManagerGeneric::Get().MakeDirectory(*FPaths::GetPath(Outfile), true);
}
return FFileHelper::SaveArrayToFile(TagetImageData, *Outfile);
}
}
}
return false;
}
@@ -0,0 +1,20 @@
// Copyright 1998-2018 Epic Games, Inc. All Rights Reserved.
#include "QRcode.h"
#define LOCTEXT_NAMESPACE "FQRcodeModule"
void FQRcodeModule::StartupModule()
{
// This code will execute after your module is loaded into memory; the exact timing is specified in the .uplugin file per-module
}
void FQRcodeModule::ShutdownModule()
{
// This function may be called during shutdown to clean up your module. For modules that support dynamic reloading,
// we call this function before unloading the module.
}
#undef LOCTEXT_NAMESPACE
IMPLEMENT_MODULE(FQRcodeModule, QRcode)
@@ -0,0 +1,40 @@
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "Kismet/BlueprintFunctionLibrary.h"
#include "QRCodeBlueprintFunctionLibrary.generated.h"
UENUM()
enum class QR_IMAGE_FORMAT : uint8
{
/** Portable Network Graphics. */
PNG = 0,
/** Joint Photographic Experts Group. */
JPEG = 1,
};
/**
*
*/
UCLASS()
class QRCODE_API UQRCodeBlueprintFunctionLibrary : public UBlueprintFunctionLibrary
{
GENERATED_BODY()
public:
UFUNCTION(BlueprintCallable, Category = "UQRCodeBlueprintFunctionLibrary|GenerateQRCodeBitmap")
static void GenerateQRCodeBitmap(const int32& Width, const int32& Height, const FString& Name, const FString& Outfile, int32 Margin = 0);
UFUNCTION(BlueprintCallable, Category = "UQRCodeBlueprintFunctionLibrary|GenerateQRCodeTexture")
static UTexture2D* GenerateQRCodeTexture(const int32& Width, const int32& Height, const FString& Name, int32 Margin = 0);
UFUNCTION(BlueprintCallable, Category = "UQRCodeBlueprintFunctionLibrary|GenerateQRCodeBitmap")
static bool GenerateQRCodeImageByType(const int32& Width, const int32& Height, const FString& Name, const FString& Outfile, QR_IMAGE_FORMAT ImageFormat, int32 Margin = 0);
};
@@ -0,0 +1,15 @@
// Copyright 1998-2018 Epic Games, Inc. All Rights Reserved.
#pragma once
#include "CoreMinimal.h"
#include "Modules/ModuleManager.h"
class FQRcodeModule : public IModuleInterface
{
public:
/** IModuleInterface implementation */
virtual void StartupModule() override;
virtual void ShutdownModule() override;
};
@@ -0,0 +1,92 @@
// Copyright 1998-2018 Epic Games, Inc. All Rights Reserved.
using UnrealBuildTool;
using System.IO;
public class QRcode : ModuleRules
{
private string ModulePath
{
get { return ModuleDirectory; }
}
private string ThirdPartyPath
{
get { return Path.GetFullPath(Path.Combine(ModulePath, "../../ThirdParty/")); }
}
private string BinariesPath
{
get { return Path.GetFullPath(Path.Combine(ModulePath, "../../Binaries/")); }
}
private string QREncodeLibraryPath
{
get { return Path.GetFullPath(Path.Combine(ThirdPartyPath, "QREncode", "lib")); }
}
public QRcode(ReadOnlyTargetRules Target) : base(Target)
{
PCHUsage = ModuleRules.PCHUsageMode.UseExplicitOrSharedPCHs;
PublicIncludePaths.AddRange(
new string[] {
Path.Combine(ThirdPartyPath, "QREncode", "include"),
// ... add public include paths required here ...
}
);
PrivateIncludePaths.AddRange(
new string[] {
// ... add other private include paths required here ...
}
);
PublicDependencyModuleNames.AddRange(
new string[]
{
"Core",
// ... add other public dependencies that you statically link with here ...
}
);
PrivateDependencyModuleNames.AddRange(
new string[]
{
"CoreUObject",
"Engine",
"Slate",
"SlateCore",
// ... add private dependencies that you statically link with here ...
}
);
DynamicallyLoadedModuleNames.AddRange(
new string[]
{
// ... add any modules that your module loads dynamically here ...
}
);
LoadQREncodeLib(Target);
}
public bool LoadQREncodeLib(ReadOnlyTargetRules Target)
{
bool isLibrarySupported = false;
if ((Target.Platform == UnrealTargetPlatform.Win64) || (Target.Platform == UnrealTargetPlatform.Win32))
{
isLibrarySupported = true;
string PlatformString = (Target.Platform == UnrealTargetPlatform.Win64) ? "Win64" : "Win32";
PublicAdditionalLibraries.Add(Path.Combine(QREncodeLibraryPath, PlatformString, "QRCode.lib"));
}
return isLibrarySupported;
}
}