Added support for Streamdeck Pedal and updated UI to better fit the Packed UI style

This commit is contained in:
2026-02-27 22:47:08 +01:00
committed by erik
parent 5a70f775f1
commit 93faae5cc8
1463 changed files with 306917 additions and 0 deletions

32
node_modules/@julusian/jpeg-turbo/src/buffersize.cc generated vendored Normal file
View File

@@ -0,0 +1,32 @@
#include "buffersize.h"
Napi::Value BufferSize(const Napi::CallbackInfo &info)
{
Napi::Env env = info.Env();
if (info.Length() < 1)
{
Napi::TypeError::New(env, "Not enough arguments")
.ThrowAsJavaScriptException();
return env.Null();
}
if (!info[0].IsObject())
{
Napi::TypeError::New(env, "Invalid options").ThrowAsJavaScriptException();
return env.Null();
}
Napi::Object options = info[0].As<Napi::Object>();
BufferSizeOptions parsedOptions = ParseBufferSizeOptions(env, options);
if (!parsedOptions.valid)
{
return env.Null();
}
// Finally, calculate the buffer size
uint32_t dstLength = tjBufSize(parsedOptions.width, parsedOptions.height, parsedOptions.subsampling);
Napi::Number result = Napi::Number::New(env, dstLength);
return result;
}

8
node_modules/@julusian/jpeg-turbo/src/buffersize.h generated vendored Normal file
View File

@@ -0,0 +1,8 @@
#ifndef NODE_JPEGTURBO_BUFFERSIZE_H
#define NODE_JPEGTURBO_BUFFERSIZE_H
#include "util.h"
Napi::Value BufferSize(const Napi::CallbackInfo &info);
#endif

283
node_modules/@julusian/jpeg-turbo/src/compress.cc generated vendored Normal file
View File

@@ -0,0 +1,283 @@
#include "compress.h"
struct CompressProps
{
unsigned char *srcData;
uint32_t format;
uint32_t width;
uint32_t stride;
uint32_t height;
uint32_t subsampling;
int quality;
int bpp;
int flags;
unsigned long resSize;
unsigned char *resData;
};
std::string DoCompress(CompressProps &props)
{
tjhandle handle = tjInitCompress();
if (handle == nullptr)
{
return tjGetErrorStr();
}
int err = tjCompress2(handle,
props.srcData,
props.width,
props.stride * props.bpp,
props.height,
props.format,
&props.resData,
&props.resSize,
props.subsampling,
props.quality,
props.flags);
if (err != 0)
{
tjDestroy(handle);
return tjGetErrorStr();
}
err = tjDestroy(handle);
if (err != 0)
{
return tjGetErrorStr();
}
if (props.resData == nullptr)
{
return "No output data";
}
return "";
}
Napi::Object CompressResult(const Napi::Env &env, const Napi::Buffer<unsigned char> dstBuffer, const CompressProps &props)
{
Napi::Object res = Napi::Object::New(env);
res.Set("data", dstBuffer);
res.Set("size", props.resSize);
return res;
}
class CompressWorker : public Napi::AsyncWorker
{
public:
CompressWorker(
Napi::Env &env,
Napi::Buffer<unsigned char> &srcBuffer,
Napi::Buffer<unsigned char> &dstBuffer,
CompressProps &props)
: AsyncWorker(env),
deferred(Napi::Promise::Deferred::New(env)),
srcBuffer(Napi::Reference<Napi::Buffer<unsigned char>>::New(srcBuffer, 1)),
dstBuffer(Napi::Reference<Napi::Buffer<unsigned char>>::New(dstBuffer, 1)),
props(props)
{
}
~CompressWorker()
{
this->srcBuffer.Reset();
this->dstBuffer.Reset();
}
void Execute()
{
std::string err = DoCompress(this->props);
if (!err.empty())
{
SetError(err);
}
}
void OnOK()
{
deferred.Resolve(CompressResult(Env(), this->dstBuffer.Value(), this->props));
}
void OnError(Napi::Error const &error)
{
deferred.Reject(error.Value());
}
Napi::Promise GetPromise() const
{
return deferred.Promise();
}
private:
Napi::Promise::Deferred deferred;
Napi::Reference<Napi::Buffer<unsigned char>> srcBuffer;
Napi::Reference<Napi::Buffer<unsigned char>> dstBuffer;
CompressProps props;
};
Napi::Value CompressInner(const Napi::CallbackInfo &info, bool async)
{
Napi::Env env = info.Env();
if (info.Length() < 2)
{
Napi::TypeError::New(env, "Not enough arguments")
.ThrowAsJavaScriptException();
return env.Null();
}
if (!info[0].IsBuffer())
{
Napi::TypeError::New(env, "Invalid source buffer")
.ThrowAsJavaScriptException();
return env.Null();
}
Napi::Buffer<unsigned char> srcBuffer = info[0].As<Napi::Buffer<unsigned char>>();
unsigned int offset = 0;
Napi::Buffer<unsigned char> dstBuffer;
if (info[1].IsBuffer())
{
dstBuffer = info[1].As<Napi::Buffer<unsigned char>>();
offset++;
if (dstBuffer.Length() == 0)
{
Napi::TypeError::New(env, "Invalid destination buffer")
.ThrowAsJavaScriptException();
return env.Null();
}
}
if (info.Length() < offset + 2 || !info[offset + 1].IsObject())
{
Napi::TypeError::New(env, "Invalid options").ThrowAsJavaScriptException();
return env.Null();
}
Napi::Object options = info[offset + 1].As<Napi::Object>();
BufferSizeOptions parsedOptions = ParseBufferSizeOptions(env, options);
if (!parsedOptions.valid)
{
return env.Null();
}
CompressProps props = {};
props.srcData = srcBuffer.Data();
props.width = parsedOptions.width;
props.height = parsedOptions.height;
props.subsampling = parsedOptions.subsampling;
Napi::Value tmpFormat = options.Get("format");
if (!tmpFormat.IsNumber())
{
Napi::TypeError::New(env, "Invalid format").ThrowAsJavaScriptException();
return env.Null();
}
props.format = tmpFormat.As<Napi::Number>().Uint32Value();
// Figure out bpp from format (needed to calculate output buffer size)
props.bpp = 0;
switch (props.format)
{
case TJPF_GRAY:
props.bpp = 1;
break;
case TJPF_RGB:
case TJPF_BGR:
props.bpp = 3;
break;
case TJPF_RGBX:
case TJPF_BGRX:
case TJPF_XRGB:
case TJPF_XBGR:
case TJPF_RGBA:
case TJPF_BGRA:
case TJPF_ABGR:
case TJPF_ARGB:
props.bpp = 4;
break;
default:
Napi::TypeError::New(env, "Invalid input format").ThrowAsJavaScriptException();
return env.Null();
}
props.stride = parsedOptions.width;
Napi::Value tmpStride = options.Get("stride");
if (!tmpStride.IsUndefined())
{
if (!tmpStride.IsNumber())
{
Napi::TypeError::New(env, "Invalid stride").ThrowAsJavaScriptException();
return env.Null();
}
props.stride = tmpStride.As<Napi::Number>().Uint32Value();
}
props.quality = NJT_DEFAULT_QUALITY;
Napi::Value tmpQuality = options.Get("quality");
if (!tmpQuality.IsUndefined())
{
if (!tmpQuality.IsNumber())
{
Napi::TypeError::New(env, "Invalid quality").ThrowAsJavaScriptException();
return env.Null();
}
props.quality = tmpQuality.As<Napi::Number>().Uint32Value();
}
if (props.quality <= 0 || props.quality > 100)
{
Napi::TypeError::New(env, "Invalid quality").ThrowAsJavaScriptException();
return env.Null();
}
if (srcBuffer.Length() < static_cast<size_t>(props.stride) * props.height * props.bpp)
{
Napi::TypeError::New(env, "Source data is not long enough").ThrowAsJavaScriptException();
return env.Null();
}
uint32_t dstLength = tjBufSize(props.width, props.height, props.subsampling);
if (dstBuffer.IsEmpty())
{
dstBuffer = Napi::Buffer<unsigned char>::New(env, dstLength);
}
if (dstLength > dstBuffer.Length())
{
Napi::TypeError::New(env, "Insufficient output buffer").ThrowAsJavaScriptException();
return env.Null();
}
props.flags = TJFLAG_FASTDCT | TJFLAG_NOREALLOC;
props.resSize = dstBuffer.Length();
props.resData = dstBuffer.Data();
if (async)
{
CompressWorker *wk = new CompressWorker(env, srcBuffer, dstBuffer, props);
wk->Queue();
return wk->GetPromise();
}
else
{
std::string errStr = DoCompress(props);
if (!errStr.empty())
{
Napi::TypeError::New(env, errStr).ThrowAsJavaScriptException();
return env.Null();
}
return CompressResult(env, dstBuffer, props);
}
}
Napi::Value CompressAsync(const Napi::CallbackInfo &info)
{
return CompressInner(info, true);
}
Napi::Value CompressSync(const Napi::CallbackInfo &info)
{
return CompressInner(info, false);
}

9
node_modules/@julusian/jpeg-turbo/src/compress.h generated vendored Normal file
View File

@@ -0,0 +1,9 @@
#ifndef NODE_JPEGTURBO_COMPRESS_H
#define NODE_JPEGTURBO_COMPRESS_H
#include "util.h"
Napi::Value CompressAsync(const Napi::CallbackInfo &info);
Napi::Value CompressSync(const Napi::CallbackInfo &info);
#endif

8
node_modules/@julusian/jpeg-turbo/src/consts.h generated vendored Normal file
View File

@@ -0,0 +1,8 @@
#ifndef NODE_JPEGTURBO_CONSTS_H
#define NODE_JPEGTURBO_CONSTS_H
static int NJT_DEFAULT_QUALITY = 80;
static int NJT_DEFAULT_SUBSAMPLING = TJSAMP_420;
static int NJT_DEFAULT_FORMAT = TJPF_RGBA;
#endif

244
node_modules/@julusian/jpeg-turbo/src/decompress.cc generated vendored Normal file
View File

@@ -0,0 +1,244 @@
#include "compress.h"
struct DecompressProps
{
tjhandle handle;
unsigned char *srcData;
uint32_t srcLength;
uint32_t format;
int bpp;
int resWidth;
int resHeight;
unsigned long resSize;
unsigned char *resData;
};
std::string DoDecompress(DecompressProps &props)
{
int err = tjDecompress2(props.handle, props.srcData, props.srcLength, props.resData, props.resWidth, 0, props.resHeight, props.format, TJFLAG_FASTDCT);
if (err != 0)
{
tjDestroy(props.handle);
return tjGetErrorStr();
}
err = tjDestroy(props.handle);
if (err != 0)
{
return tjGetErrorStr();
}
return "";
}
Napi::Object DecompressResult(const Napi::Env &env, const Napi::Buffer<unsigned char> dstBuffer, const DecompressProps &props)
{
Napi::Object res = Napi::Object::New(env);
res.Set("data", dstBuffer);
res.Set("size", props.resSize);
res.Set("width", props.resWidth);
res.Set("height", props.resHeight);
res.Set("format", props.format);
return res;
}
class DecompressWorker : public Napi::AsyncWorker
{
public:
DecompressWorker(
Napi::Env &env,
Napi::Buffer<unsigned char> &srcBuffer,
Napi::Buffer<unsigned char> &dstBuffer,
DecompressProps &props)
: AsyncWorker(env),
deferred(Napi::Promise::Deferred::New(env)),
srcBuffer(Napi::Reference<Napi::Buffer<unsigned char>>::New(srcBuffer, 1)),
dstBuffer(Napi::Reference<Napi::Buffer<unsigned char>>::New(dstBuffer, 1)),
props(props)
{
}
~DecompressWorker()
{
this->srcBuffer.Reset();
this->dstBuffer.Reset();
}
void Execute()
{
std::string err = DoDecompress(this->props);
if (!err.empty())
{
SetError(err);
}
}
void OnOK()
{
deferred.Resolve(DecompressResult(Env(), this->dstBuffer.Value(), this->props));
}
void OnError(Napi::Error const &error)
{
deferred.Reject(error.Value());
}
Napi::Promise GetPromise() const
{
return deferred.Promise();
}
private:
Napi::Promise::Deferred deferred;
Napi::Reference<Napi::Buffer<unsigned char>> srcBuffer;
Napi::Reference<Napi::Buffer<unsigned char>> dstBuffer;
DecompressProps props;
};
Napi::Value DecompressInner(const Napi::CallbackInfo &info, bool async)
{
Napi::Env env = info.Env();
if (info.Length() < 1)
{
Napi::TypeError::New(env, "Not enough arguments")
.ThrowAsJavaScriptException();
return env.Null();
}
if (!info[0].IsBuffer())
{
Napi::TypeError::New(env, "Invalid source buffer")
.ThrowAsJavaScriptException();
return env.Null();
}
Napi::Buffer<unsigned char> srcBuffer = info[0].As<Napi::Buffer<unsigned char>>();
unsigned int offset = 0;
Napi::Buffer<unsigned char> dstBuffer;
if (info[1].IsBuffer())
{
dstBuffer = info[1].As<Napi::Buffer<unsigned char>>();
offset++;
if (dstBuffer.Length() == 0)
{
Napi::TypeError::New(env, "Invalid destination buffer")
.ThrowAsJavaScriptException();
return env.Null();
}
}
DecompressProps props = {};
props.srcData = srcBuffer.Data();
props.srcLength = srcBuffer.Length();
if (info.Length() >= offset + 2)
{
if (!info[offset + 1].IsObject())
{
Napi::TypeError::New(env, "Invalid options").ThrowAsJavaScriptException();
return env.Null();
}
Napi::Object options = info[offset + 1].As<Napi::Object>();
Napi::Value tmpFormat = options.Get("format");
if (!tmpFormat.IsNumber())
{
Napi::TypeError::New(env, "Invalid format").ThrowAsJavaScriptException();
return env.Null();
}
props.format = tmpFormat.As<Napi::Number>().Uint32Value();
}
// Figure out bpp from format (needed to calculate output buffer size)
props.bpp = 0;
switch (props.format)
{
case TJPF_GRAY:
props.bpp = 1;
break;
case TJPF_RGB:
case TJPF_BGR:
props.bpp = 3;
break;
case TJPF_RGBX:
case TJPF_BGRX:
case TJPF_XRGB:
case TJPF_XBGR:
case TJPF_RGBA:
case TJPF_BGRA:
case TJPF_ABGR:
case TJPF_ARGB:
props.bpp = 4;
break;
default:
Napi::TypeError::New(env, "Invalid output format").ThrowAsJavaScriptException();
return env.Null();
}
tjhandle handle = tjInitDecompress();
if (handle == nullptr)
{
Napi::TypeError::New(env, tjGetErrorStr()).ThrowAsJavaScriptException();
return env.Null();
}
props.handle = handle;
int err = tjDecompressHeader(handle, props.srcData, props.srcLength, &props.resWidth, &props.resHeight);
if (err != 0)
{
tjDestroy(handle);
Napi::TypeError::New(env, tjGetErrorStr()).ThrowAsJavaScriptException();
return env.Null();
}
auto targetSize = static_cast<size_t>(props.resWidth) * props.resHeight * props.bpp;
if (dstBuffer.IsEmpty())
{
dstBuffer = Napi::Buffer<unsigned char>::New(env, targetSize);
}
props.resSize = targetSize;
props.resData = dstBuffer.Data();
if (targetSize > dstBuffer.Length())
{
tjDestroy(handle);
Napi::TypeError::New(env, "Insufficient output buffer").ThrowAsJavaScriptException();
return env.Null();
}
if (async)
{
DecompressWorker *wk = new DecompressWorker(env, srcBuffer, dstBuffer, props);
wk->Queue();
return wk->GetPromise();
}
else
{
std::string errStr = DoDecompress(props);
if (!errStr.empty())
{
Napi::TypeError::New(env, errStr).ThrowAsJavaScriptException();
return env.Null();
}
return DecompressResult(env, dstBuffer, props);
}
return env.Null();
}
Napi::Value DecompressAsync(const Napi::CallbackInfo &info)
{
return DecompressInner(info, true);
}
Napi::Value DecompressSync(const Napi::CallbackInfo &info)
{
return DecompressInner(info, false);
}

9
node_modules/@julusian/jpeg-turbo/src/decompress.h generated vendored Normal file
View File

@@ -0,0 +1,9 @@
#ifndef NODE_JPEGTURBO_DECOMPRESS_H
#define NODE_JPEGTURBO_DECOMPRESS_H
#include "util.h"
Napi::Value DecompressAsync(const Napi::CallbackInfo &info);
Napi::Value DecompressSync(const Napi::CallbackInfo &info);
#endif

22
node_modules/@julusian/jpeg-turbo/src/enums.cc generated vendored Normal file
View File

@@ -0,0 +1,22 @@
#include "enums.h"
void InitializeEnums(const Napi::Env &env, Napi::Object &exports)
{
exports.Set("FORMAT_RGB", static_cast<unsigned long>(TJPF_RGB));
exports.Set("FORMAT_BGR", static_cast<unsigned long>(TJPF_BGR));
exports.Set("FORMAT_RGBX", static_cast<unsigned long>(TJPF_RGBX));
exports.Set("FORMAT_BGRX", static_cast<unsigned long>(TJPF_BGRX));
exports.Set("FORMAT_XRGB", static_cast<unsigned long>(TJPF_XRGB));
exports.Set("FORMAT_XBGR", static_cast<unsigned long>(TJPF_XBGR));
exports.Set("FORMAT_GRAY", static_cast<unsigned long>(TJPF_GRAY));
exports.Set("FORMAT_RGBA", static_cast<unsigned long>(TJPF_RGBA));
exports.Set("FORMAT_BGRA", static_cast<unsigned long>(TJPF_BGRA));
exports.Set("FORMAT_ABGR", static_cast<unsigned long>(TJPF_ABGR));
exports.Set("FORMAT_ARGB", static_cast<unsigned long>(TJPF_ARGB));
exports.Set("SAMP_444", static_cast<unsigned long>(TJSAMP_444));
exports.Set("SAMP_422", static_cast<unsigned long>(TJSAMP_422));
exports.Set("SAMP_420", static_cast<unsigned long>(TJSAMP_420));
exports.Set("SAMP_GRAY", static_cast<unsigned long>(TJSAMP_GRAY));
exports.Set("SAMP_440", static_cast<unsigned long>(TJSAMP_440));
}

8
node_modules/@julusian/jpeg-turbo/src/enums.h generated vendored Normal file
View File

@@ -0,0 +1,8 @@
#ifndef NODE_JPEGTURBO_ENUMS_H
#define NODE_JPEGTURBO_ENUMS_H
#include "util.h"
void InitializeEnums(const Napi::Env &env, Napi::Object &exports);
#endif

25
node_modules/@julusian/jpeg-turbo/src/exports.cc generated vendored Normal file
View File

@@ -0,0 +1,25 @@
#include "util.h"
#include "enums.h"
#include "buffersize.h"
#include "compress.h"
#include "decompress.h"
Napi::Object Init(Napi::Env env, Napi::Object exports)
{
// FT_Init_FreeType(&library);
// sprintf(version, "%i.%i.%i", FREETYPE_MAJOR, FREETYPE_MINOR, FREETYPE_PATCH);
// exports.Set("FreeTypeVersion", version);
exports.Set("bufferSize", Napi::Function::New(env, BufferSize));
exports.Set("compress", Napi::Function::New(env, CompressAsync));
exports.Set("compressSync", Napi::Function::New(env, CompressSync));
exports.Set("decompress", Napi::Function::New(env, DecompressAsync));
exports.Set("decompressSync", Napi::Function::New(env, DecompressSync));
InitializeEnums(env, exports);
return exports;
}
NODE_API_MODULE(jpegturbo, Init)

51
node_modules/@julusian/jpeg-turbo/src/util.cc generated vendored Normal file
View File

@@ -0,0 +1,51 @@
#include "util.h"
// Napi::Value getProperty(const Napi::Object &obj, const char *name)
// {
// }
BufferSizeOptions ParseBufferSizeOptions(const Napi::Env &env, const Napi::Object &options)
{
Napi::Value tmpWidth = options.Get("width");
if (!tmpWidth.IsNumber())
{
Napi::TypeError::New(env, "Invalid width").ThrowAsJavaScriptException();
return BufferSizeOptions{false};
}
uint32_t width = tmpWidth.As<Napi::Number>().Uint32Value();
Napi::Value tmpHeight = options.Get("height");
if (!tmpHeight.IsNumber())
{
Napi::TypeError::New(env, "Invalid height").ThrowAsJavaScriptException();
return BufferSizeOptions{false};
}
uint32_t height = tmpHeight.As<Napi::Number>().Uint32Value();
uint32_t subsampling = NJT_DEFAULT_SUBSAMPLING;
Napi::Value tmpSubsampling = options.Get("subsampling");
if (!tmpSubsampling.IsUndefined())
{
if (!tmpSubsampling.IsNumber())
{
Napi::TypeError::New(env, "Invalid subsampling").ThrowAsJavaScriptException();
return BufferSizeOptions{false};
}
subsampling = tmpSubsampling.As<Napi::Number>().Uint32Value();
}
switch (subsampling)
{
case TJSAMP_444:
case TJSAMP_422:
case TJSAMP_420:
case TJSAMP_GRAY:
case TJSAMP_440:
break;
default:
Napi::TypeError::New(env, "Invalid subsampling").ThrowAsJavaScriptException();
return BufferSizeOptions{false};
}
return BufferSizeOptions{true, width, height, subsampling};
}

22
node_modules/@julusian/jpeg-turbo/src/util.h generated vendored Normal file
View File

@@ -0,0 +1,22 @@
#ifndef NODE_JPEGTURBO_UTIL_H
#define NODE_JPEGTURBO_UTIL_H
#include <napi.h>
#include <turbojpeg.h>
#include "consts.h"
// Napi::Value getProperty(const Napi::Object &obj, const char *name);
struct BufferSizeOptions
{
bool valid;
uint32_t width;
uint32_t height;
uint32_t subsampling;
};
BufferSizeOptions ParseBufferSizeOptions(const Napi::Env &env, const Napi::Object &obj);
#endif