2018-05-11 12:42:35 +02:00

221 lines
5.0 KiB
C++

#include <assert.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#define EXTENSION_NAME QRCode
#define LIB_NAME "QRCode"
#define MODULE_NAME "qrcode"
// Defold SDK
#define DLIB_LOG_DOMAIN LIB_NAME
#include <dmsdk/sdk.h>
#include "quirc/quirc.h"
#define JC_QRENCODE_IMPLEMENTATION
#include "jc_qrencode.h"
// GENERATE
// https://github.com/nayuki/QR-Code-generator
struct QRCodeContext
{
int width;
int height;
};
QRCodeContext g_QRContext;
static int Scan(lua_State* L)
{
DM_LUA_STACK_CHECK(L, 1);
dmScript::LuaHBuffer* buffer = dmScript::CheckBuffer(L, 1);
int width = luaL_checkint(L, 2);
int height = luaL_checkint(L, 3);
int flip_x = luaL_checkint(L, 4);
struct quirc* qr;
qr = quirc_new();
if (!qr) {
return luaL_error(L, "qrcode.scan: Failed to allocate memory");
}
if (quirc_resize(qr, width, height) < 0) {
return luaL_error(L, "qrcode.scan: Failed to allocate video memory");
}
uint8_t* image = quirc_begin(qr, &width, &height);
uint8_t* data;
uint32_t datasize;
dmBuffer::GetBytes(buffer->m_Buffer, (void**)&data, &datasize);
// Make it grey scale
for( int y = 0; y < height; ++y )
{
for( int x = 0; x < width; ++x )
{
float r = (float)data[y * width * 3 + x * 3 + 0] / 255.0f;
float g = (float)data[y * width * 3 + x * 3 + 1] / 255.0f;
float b = (float)data[y * width * 3 + x * 3 + 2] / 255.0f;
float value = (r+g+b)/3.0f;
value = value*value;
value += 0.1f;
if(value>1.0f)
{
value = 1.0f;
}
if( flip_x == 0 )
image[y * width + x] = (uint8_t)(value * 255.0f);
else
image[y * width + (width - x - 1)] = (uint8_t)(value * 255.0f);
}
}
quirc_end(qr);
int num_codes = quirc_count(qr);
for( int i = 0; i < num_codes; i++)
{
struct quirc_code code;
struct quirc_data data;
quirc_extract(qr, i, &code);
quirc_decode_error_t err = quirc_decode(&code, &data);
if (err)
{
num_codes = 0;
}
else
{
lua_pushstring(L, (const char*)data.payload);
}
break;
}
quirc_destroy(qr);
if( num_codes == 0 )
{
lua_pushnil(L);
}
return 1;
}
static dmBuffer::HBuffer GenerateImage(JCQRCode* qr, uint32_t* outsize)
{
int32_t size = qr->size;
int32_t border = 2;
int32_t scale = 8;
int32_t newsize = scale*(size + 2 * border);
dmBuffer::StreamDeclaration streams_decl[] = {
{dmHashString64("data"), dmBuffer::VALUE_TYPE_UINT8, 1}
};
dmBuffer::HBuffer buffer = 0;
dmBuffer::Result result = dmBuffer::Create(newsize * newsize, streams_decl, 1, &buffer);
if (result != dmBuffer::RESULT_OK )
{
return 0;
}
uint8_t* data;
uint32_t datasize;
dmBuffer::GetBytes(buffer, (void**)&data, &datasize);
memset(data, 255, newsize*newsize);
for( int y = 0; y < size*scale; ++y )
{
for( int x = 0; x < size*scale; ++x )
{
int flip_y = size*scale - y - 1; // flip it so we can easily pass it as a texture later on
uint8_t module = qr->data[(flip_y/scale)*256 + (x/scale)];
data[(y + scale*border) * newsize + x + scale*border] = module;
}
}
if (outsize)
*outsize = newsize;
return buffer;
}
static int Generate(lua_State* L)
{
DM_LUA_STACK_CHECK(L, 2);
const char* text = luaL_checkstring(L, 1);
JCQRCode* qr = jc_qrencode((const uint8_t*)text, (uint32_t)strlen(text));
if( !qr )
{
return DM_LUA_ERROR("Failed to encode text: '%s'\n", text);
}
uint32_t outsize = 0;
dmBuffer::HBuffer buffer = GenerateImage(qr, &outsize);
free(qr); // free the qr code
// Transfer ownership to Lua
dmScript::LuaHBuffer luabuffer = {buffer, true};
dmScript::PushBuffer(L, luabuffer);
lua_pushinteger(L, outsize);
return 2;
}
static const luaL_reg Module_methods[] =
{
{"scan", Scan},
{"generate", Generate},
{0, 0}
};
static void LuaInit(lua_State* L)
{
int top = lua_gettop(L);
luaL_register(L, MODULE_NAME, Module_methods);
#define SETCONSTANT(name) \
lua_pushnumber(L, (lua_Number) name); \
lua_setfield(L, -2, #name);\
#undef SETCONSTANT
lua_pop(L, 1);
assert(top == lua_gettop(L));
}
dmExtension::Result AppInitializeQRCode(dmExtension::AppParams* params)
{
return dmExtension::RESULT_OK;
}
dmExtension::Result InitializeQRCode(dmExtension::Params* params)
{
LuaInit(params->m_L);
return dmExtension::RESULT_OK;
}
dmExtension::Result AppFinalizeQRCode(dmExtension::AppParams* params)
{
return dmExtension::RESULT_OK;
}
dmExtension::Result FinalizeQRCode(dmExtension::Params* params)
{
return dmExtension::RESULT_OK;
}
DM_DECLARE_EXTENSION(EXTENSION_NAME, LIB_NAME, AppInitializeQRCode, AppFinalizeQRCode, InitializeQRCode, 0, 0, FinalizeQRCode)