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