Compare commits

...

4 Commits

Author SHA1 Message Date
1572044ade also cd
Some checks failed
ContinuousDelivery / linux-ubuntu (push) Has been cancelled
ContinuousDelivery / android (map[ndk_abi:arm64-v8a vcpkg_toolkit:arm64-android-23]) (push) Has been cancelled
ContinuousDelivery / android (map[ndk_abi:armeabi-v7a vcpkg_toolkit:arm-neon-android-23]) (push) Has been cancelled
ContinuousDelivery / android (map[ndk_abi:x86_64 vcpkg_toolkit:x64-android-23]) (push) Has been cancelled
ContinuousDelivery / windows (push) Has been cancelled
ContinuousDelivery / windows-asan (push) Has been cancelled
ContinuousDelivery / dumpsyms (push) Has been cancelled
ContinuousDelivery / release (push) Has been cancelled
ContinuousIntegration / linux (push) Has been cancelled
ContinuousIntegration / android (map[ndk_abi:arm64-v8a vcpkg_toolkit:arm64-android-23]) (push) Has been cancelled
ContinuousIntegration / android (map[ndk_abi:armeabi-v7a vcpkg_toolkit:arm-neon-android-23]) (push) Has been cancelled
ContinuousIntegration / android (map[ndk_abi:x86_64 vcpkg_toolkit:x64-android-23]) (push) Has been cancelled
ContinuousIntegration / macos (push) Has been cancelled
ContinuousIntegration / windows (push) Has been cancelled
2025-05-07 19:59:23 +02:00
9d2f2a0344 new vcpkg caching action for ci 2025-05-07 19:37:29 +02:00
3b5874739b qoi_pipe style animation encoding 2025-05-07 15:43:34 +02:00
12893ac743 qoi_pipe decoding support 2025-05-07 15:30:05 +02:00
4 changed files with 175 additions and 63 deletions

View File

@ -62,6 +62,11 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
permissions:
# vcpkg caching action
actions: read
contents: read
strategy: strategy:
matrix: matrix:
platform: platform:
@ -97,17 +102,17 @@ jobs:
- name: Install Dependencies (host) - name: Install Dependencies (host)
run: sudo apt update && sudo apt -y install cmake pkg-config nasm run: sudo apt update && sudo apt -y install cmake pkg-config nasm
- name: Export GitHub Actions cache environment variables - name: Restore vcpkg cache
uses: actions/github-script@v7 id: vcpkg-cache
uses: TAServers/vcpkg-cache@v3
with: with:
script: | token: ${{secrets.GITHUB_TOKEN}}
core.exportVariable('ACTIONS_CACHE_URL', process.env.ACTIONS_CACHE_URL || '');
core.exportVariable('ACTIONS_RUNTIME_TOKEN', process.env.ACTIONS_RUNTIME_TOKEN || '');
- name: Install Dependencies (target) - name: Install Dependencies (target)
env: env:
ANDROID_NDK_HOME: ${{steps.setup_ndk.outputs.ndk-path}} ANDROID_NDK_HOME: ${{steps.setup_ndk.outputs.ndk-path}}
VCPKG_BINARY_SOURCES: "clear;x-gha,readwrite" VCPKG_FEATURE_FLAGS: "binarycaching"
VCPKG_BINARY_SOURCES: "clear;files,${{steps.vcpkg-cache.outputs.path}},readwrite"
run: vcpkg install --overlay-triplets=vcpkg_android_triplets --triplet ${{matrix.platform.vcpkg_toolkit}} libsodium opus libvpx libpng libjpeg-turbo freetype run: vcpkg install --overlay-triplets=vcpkg_android_triplets --triplet ${{matrix.platform.vcpkg_toolkit}} libsodium opus libvpx libpng libjpeg-turbo freetype
# vcpkg scripts root /usr/local/share/vcpkg/scripts # vcpkg scripts root /usr/local/share/vcpkg/scripts
@ -154,22 +159,27 @@ jobs:
runs-on: windows-2019 runs-on: windows-2019
permissions:
# vcpkg caching action
actions: read
contents: read
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
with: with:
submodules: recursive submodules: recursive
fetch-depth: 0 fetch-depth: 0
- name: Export GitHub Actions cache environment variables - name: Restore vcpkg cache
uses: actions/github-script@v7 id: vcpkg-cache
uses: TAServers/vcpkg-cache@v3
with: with:
script: | token: ${{secrets.GITHUB_TOKEN}}
core.exportVariable('ACTIONS_CACHE_URL', process.env.ACTIONS_CACHE_URL || '');
core.exportVariable('ACTIONS_RUNTIME_TOKEN', process.env.ACTIONS_RUNTIME_TOKEN || '');
- name: Install Dependencies - name: Install Dependencies
env: env:
VCPKG_BINARY_SOURCES: "clear;x-gha,readwrite" VCPKG_FEATURE_FLAGS: "binarycaching"
VCPKG_BINARY_SOURCES: "clear;files,${{steps.vcpkg-cache.outputs.path}},readwrite"
run: vcpkg install pkgconf:x64-windows libsodium:x64-windows-static pthreads:x64-windows-static opus:x64-windows-static libvpx:x64-windows-static zstd:x64-windows-static libwebp:x64-windows-static libpng:x64-windows-static libjpeg-turbo:x64-windows-static freetype:x64-windows-static run: vcpkg install pkgconf:x64-windows libsodium:x64-windows-static pthreads:x64-windows-static opus:x64-windows-static libvpx:x64-windows-static zstd:x64-windows-static libwebp:x64-windows-static libpng:x64-windows-static libjpeg-turbo:x64-windows-static freetype:x64-windows-static
# setup vs env # setup vs env
@ -223,22 +233,27 @@ jobs:
runs-on: windows-2019 runs-on: windows-2019
permissions:
# vcpkg caching action
actions: read
contents: read
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
with: with:
submodules: recursive submodules: recursive
fetch-depth: 0 fetch-depth: 0
- name: Export GitHub Actions cache environment variables - name: Restore vcpkg cache
uses: actions/github-script@v7 id: vcpkg-cache
uses: TAServers/vcpkg-cache@v3
with: with:
script: | token: ${{secrets.GITHUB_TOKEN}}
core.exportVariable('ACTIONS_CACHE_URL', process.env.ACTIONS_CACHE_URL || '');
core.exportVariable('ACTIONS_RUNTIME_TOKEN', process.env.ACTIONS_RUNTIME_TOKEN || '');
- name: Install Dependencies - name: Install Dependencies
env: env:
VCPKG_BINARY_SOURCES: "clear;x-gha,readwrite" VCPKG_FEATURE_FLAGS: "binarycaching"
VCPKG_BINARY_SOURCES: "clear;files,${{steps.vcpkg-cache.outputs.path}},readwrite"
run: vcpkg install pkgconf:x64-windows libsodium:x64-windows-static pthreads:x64-windows-static opus:x64-windows-static libvpx:x64-windows-static zstd:x64-windows-static libwebp:x64-windows-static libpng:x64-windows-static libjpeg-turbo:x64-windows-static freetype:x64-windows-static run: vcpkg install pkgconf:x64-windows libsodium:x64-windows-static pthreads:x64-windows-static opus:x64-windows-static libvpx:x64-windows-static zstd:x64-windows-static libwebp:x64-windows-static libpng:x64-windows-static libjpeg-turbo:x64-windows-static freetype:x64-windows-static

View File

@ -40,6 +40,11 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
permissions:
# vcpkg caching action
actions: read
contents: read
strategy: strategy:
matrix: matrix:
platform: platform:
@ -74,17 +79,17 @@ jobs:
- name: Install Dependencies (host) - name: Install Dependencies (host)
run: sudo apt update && sudo apt -y install cmake pkg-config nasm run: sudo apt update && sudo apt -y install cmake pkg-config nasm
- name: Export GitHub Actions cache environment variables - name: Restore vcpkg cache
uses: actions/github-script@v7 id: vcpkg-cache
uses: TAServers/vcpkg-cache@v3
with: with:
script: | token: ${{secrets.GITHUB_TOKEN}}
core.exportVariable('ACTIONS_CACHE_URL', process.env.ACTIONS_CACHE_URL || '');
core.exportVariable('ACTIONS_RUNTIME_TOKEN', process.env.ACTIONS_RUNTIME_TOKEN || '');
- name: Install Dependencies (target) - name: Install Dependencies (target)
env: env:
ANDROID_NDK_HOME: ${{steps.setup_ndk.outputs.ndk-path}} ANDROID_NDK_HOME: ${{steps.setup_ndk.outputs.ndk-path}}
VCPKG_BINARY_SOURCES: "clear;x-gha,readwrite" VCPKG_FEATURE_FLAGS: "binarycaching"
VCPKG_BINARY_SOURCES: "clear;files,${{steps.vcpkg-cache.outputs.path}},readwrite"
run: vcpkg install --overlay-triplets=vcpkg_android_triplets --triplet ${{matrix.platform.vcpkg_toolkit}} libsodium opus libvpx libpng libjpeg-turbo freetype run: vcpkg install --overlay-triplets=vcpkg_android_triplets --triplet ${{matrix.platform.vcpkg_toolkit}} libsodium opus libvpx libpng libjpeg-turbo freetype
# vcpkg scripts root /usr/local/share/vcpkg/scripts # vcpkg scripts root /usr/local/share/vcpkg/scripts
@ -138,21 +143,26 @@ jobs:
runs-on: windows-latest runs-on: windows-latest
permissions:
# vcpkg caching action
actions: read
contents: read
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
with: with:
submodules: recursive submodules: recursive
- name: Export GitHub Actions cache environment variables - name: Restore vcpkg cache
uses: actions/github-script@v7 id: vcpkg-cache
uses: TAServers/vcpkg-cache@v3
with: with:
script: | token: ${{secrets.GITHUB_TOKEN}}
core.exportVariable('ACTIONS_CACHE_URL', process.env.ACTIONS_CACHE_URL || '');
core.exportVariable('ACTIONS_RUNTIME_TOKEN', process.env.ACTIONS_RUNTIME_TOKEN || '');
- name: Install Dependencies - name: Install Dependencies
env: env:
VCPKG_BINARY_SOURCES: "clear;x-gha,readwrite" VCPKG_FEATURE_FLAGS: "binarycaching"
VCPKG_BINARY_SOURCES: "clear;files,${{steps.vcpkg-cache.outputs.path}},readwrite"
run: vcpkg install pkgconf:x64-windows libsodium:x64-windows-static pthreads:x64-windows-static opus:x64-windows-static libvpx:x64-windows-static zstd:x64-windows-static libwebp:x64-windows-static libpng:x64-windows-static libjpeg-turbo:x64-windows-static freetype:x64-windows-static run: vcpkg install pkgconf:x64-windows libsodium:x64-windows-static pthreads:x64-windows-static opus:x64-windows-static libvpx:x64-windows-static zstd:x64-windows-static libwebp:x64-windows-static libpng:x64-windows-static libjpeg-turbo:x64-windows-static freetype:x64-windows-static
# setup vs env # setup vs env

View File

@ -1,10 +1,72 @@
#include "./image_loader_qoi.hpp" #include "./image_loader_qoi.hpp"
#include <cstdint>
#include <qoi/qoi.h> #include <qoi/qoi.h>
#include <cstdint>
#include <cassert>
#include <iostream> #include <iostream>
#define QOI_HEADER_SIZE 14
// true if data looks like qoi
static bool probe_qoi(const uint8_t* data, int64_t data_size) {
// smallest possible qoi
// magic
// dims (w h)
// chan
// col
if (data_size < QOI_HEADER_SIZE+8) {
return false;
}
if (
data[0] != 'q' ||
data[1] != 'o' ||
data[2] != 'i' ||
data[3] != 'f'
) {
return false;
}
return true;
}
// every qoi ends with 0,0,0,0,0,0,0,1
// returns the index for the first byte after padding (aka the size of the qoi)
static int64_t probe_qoi_padding(const uint8_t* data, int64_t data_size) {
assert(data);
assert(data_size >= 8);
// loop checks if 0x00 or 0x01, otherwise skips 2
// we start at the last possible first position
for (int64_t pos = 7; pos < data_size;) {
if (data[pos] == 0x00) {
pos += 1; // not last char in padding, but we might be in the padding
} else if (data[pos] == 0x01) {
// last char from padding
if (
data[pos-7] == 0x00 &&
data[pos-6] == 0x00 &&
data[pos-5] == 0x00 &&
data[pos-4] == 0x00 &&
data[pos-3] == 0x00 &&
data[pos-2] == 0x00 &&
data[pos-1] == 0x00
) {
//return pos - 7; // first byte of padding
return pos+1;
} else {
pos += 8; // cant be last byte for another 7
}
} else {
pos += 2;
}
}
return -1; // not found
}
ImageLoaderQOI::ImageInfo ImageLoaderQOI::loadInfoFromMemory(const uint8_t* data, uint64_t data_size) { ImageLoaderQOI::ImageInfo ImageLoaderQOI::loadInfoFromMemory(const uint8_t* data, uint64_t data_size) {
ImageInfo res; ImageInfo res;
@ -26,24 +88,46 @@ ImageLoaderQOI::ImageInfo ImageLoaderQOI::loadInfoFromMemory(const uint8_t* data
ImageLoaderQOI::ImageResult ImageLoaderQOI::loadFromMemoryRGBA(const uint8_t* data, uint64_t data_size) { ImageLoaderQOI::ImageResult ImageLoaderQOI::loadFromMemoryRGBA(const uint8_t* data, uint64_t data_size) {
ImageResult res; ImageResult res;
qoi_desc desc; if (!probe_qoi(data, data_size)) {
uint8_t* img_data = static_cast<uint8_t*>(
qoi_decode(data, data_size, &desc, 4)
);
if (img_data == nullptr) {
// not readable
return res; return res;
} }
res.width = desc.width; for (size_t data_pos = 0; data_pos < data_size;) {
res.height = desc.height; const auto qoi_size = probe_qoi_padding(data+data_pos, data_size-data_pos);
if (qoi_size < QOI_HEADER_SIZE+8) {
// too small
break;
}
auto& new_frame = res.frames.emplace_back(); qoi_desc desc;
new_frame.ms = 0;
new_frame.data = {img_data, img_data+(desc.width*desc.height*4)}; uint8_t* img_data = static_cast<uint8_t*>(
qoi_decode(data + data_pos, qoi_size, &desc, 4)
);
if (img_data == nullptr) {
// not readable
return res;
}
if (res.width == 0 || res.height == 0) {
res.width = desc.width;
res.height = desc.height;
}
if (res.width == desc.width && res.height == desc.height) {
auto& new_frame = res.frames.emplace_back();
new_frame.ms = 25; // ffmpeg default
new_frame.data = {img_data, img_data+(desc.width*desc.height*4)};
} else {
// dim mismatch, what do we do? abort, continue?
data_pos = data_size; // force exit loop
}
free(img_data);
data_pos += qoi_size;
}
free(img_data);
return res; return res;
} }
@ -53,11 +137,6 @@ std::vector<uint8_t> ImageEncoderQOI::encodeToMemoryRGBA(const ImageResult& inpu
return {}; return {};
} }
if (input_image.frames.size() > 1) {
std::cerr << "IEQOI warning: image with animation, only first frame will be encoded!\n";
return {};
}
// TODO: look into RDO (eg https://github.com/richgel999/rdopng) // TODO: look into RDO (eg https://github.com/richgel999/rdopng)
//int png_compression_level = 8; //int png_compression_level = 8;
//if (extra_options.count("png_compression_level")) { //if (extra_options.count("png_compression_level")) {
@ -70,22 +149,30 @@ std::vector<uint8_t> ImageEncoderQOI::encodeToMemoryRGBA(const ImageResult& inpu
desc.channels = 4; desc.channels = 4;
desc.colorspace = QOI_SRGB; // TODO: decide desc.colorspace = QOI_SRGB; // TODO: decide
int out_len {0}; std::vector<uint8_t> new_data;
uint8_t* enc_data = static_cast<uint8_t*>(qoi_encode( for (const auto& frame : input_image.frames) {
input_image.frames.front().data.data(), int out_len {0};
&desc, uint8_t* enc_data = static_cast<uint8_t*>(qoi_encode(
&out_len frame.data.data(),
)); &desc,
&out_len
));
if (enc_data == nullptr) { if (enc_data == nullptr) {
std::cerr << "IEQOI error: qoi_encode failed!\n"; std::cerr << "IEQOI error: qoi_encode failed!\n";
return {}; break;
}
// qoi_pipe like animation support. simple concatination of images
if (new_data.empty()) {
new_data = std::vector<uint8_t>(enc_data, enc_data+out_len);
} else {
new_data.insert(new_data.cend(), enc_data, enc_data+out_len);
}
free(enc_data); // TODO: a streaming encoder would be better
} }
std::vector<uint8_t> new_data(enc_data, enc_data+out_len);
free(enc_data); // TODO: a streaming encoder would be better
return new_data; return new_data;
} }