A bunch of random code samples
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 

147 lines
4.2 KiB

/*
cmake_minimum_required(VERSION 3.27)
project(cordiceps)
set(CMAKE_CXX_STANDARD 23)
include(FetchContent)
FetchContent_Declare(
raylib
GIT_REPOSITORY https://github.com/raysan5/raylib.git
GIT_TAG 5.0
)
FetchContent_MakeAvailable(raylib)
add_executable(cordiceps cordiceps.cpp)
target_link_libraries(cordiceps PUBLIC raylib_static)
*/
#include <ranges>
#include <iostream>
#include <fstream>
#include <sstream>
#include <vector>
#include <cassert>
#include <cstdint>
#include <bit>
#include <bitset>
#include "raylib.h"
std::string slurp(const char* filename) {
std::ifstream file{filename, std::ios_base::binary};
std::stringstream data;
file >> data.rdbuf();
return data.str();
}
std::vector<bool> to_bits(std::string str) {
std::vector<bool> d;
for(char c : str) {
d.push_back(c & 0b10000000);
d.push_back(c & 0b1000000);
d.push_back(c & 0b100000);
d.push_back(c & 0b10000);
d.push_back(c & 0b1000);
d.push_back(c & 0b100);
d.push_back(c & 0b10);
d.push_back(c & 0b1);
}
return d;
}
std::string from_bits(std::vector<bool> data) {
std::string d;
std::bitset<32> size_bits;
for(int idx = 0; idx < 32; ++idx) size_bits[idx] = data[idx];
uint32_t size = size_bits.to_ulong();
if(std::endian::native == std::endian::little) size = std::byteswap(size);
std::cerr << "Decoded expected " << size << " bytes" << std::endl;
for(auto composite : data | std::views::drop(32) | std::views::chunk(8)) {
char c = 0;
for(auto b : composite) {
c *= 2;
c += b;
}
d.push_back(c);
size--;
if(size == 0) return d;
}
return d;
}
void encode(const char* pic, const char* data_source) {
auto image = LoadImage(pic);
auto raw_data = slurp(data_source);
uint32_t size = raw_data.size();
std::cerr << "Writing expected " << size << " bytes" << std::endl;
if(std::endian::native == std::endian::little) size = std::byteswap(size);
std::bitset<32> size_bits;
size_bits = size;
std::vector<bool> raw_bits = to_bits(raw_data);
assert(raw_bits.size() % 8 == 0);
assert(raw_bits.size() / 8 == raw_data.size());
std::vector<bool> data;
for(int idx = 0; idx < 32; ++idx) data.push_back(size_bits[idx]);
data.insert(data.end(), raw_bits.begin(), raw_bits.end());
size_t idx = 0;
for(auto j : std::ranges::iota_view(0, image.height)) {
for(auto i : std::ranges::iota_view(0, image.width)) {
auto c = GetImageColor(image, i, j);
c.r ^= c.r & 1;
c.g ^= c.g & 1;
c.b ^= c.b & 1;
c.r += idx < data.size() ? data[idx] : 0; idx++;
c.g += idx < data.size() ? data[idx] : 0; idx++;
c.b += idx < data.size() ? data[idx] : 0; idx++;
ImageDrawPixel(&image, i, j, c);
}
}
ExportImage(image, pic);
UnloadImage(image);
if(raw_bits.size() > idx) {
std::cout << "\x1b[1;31mWritten bits: " << data.size() << "/" << idx << std::endl;
} else {
std::cout << "\x1b[1;32mWritten bits: " << data.size() << "/" << idx << std::endl;
}
}
void decode(const char* pic) {
auto image = LoadImage(pic);
std::vector<bool> raw_bits;
size_t idx = 0;
for(auto j : std::ranges::iota_view(0, image.height)) {
for(auto i : std::ranges::iota_view(0, image.width)) {
auto c = GetImageColor(image, i, j);
raw_bits.push_back(c.r & 1);
raw_bits.push_back(c.g & 1);
raw_bits.push_back(c.b & 1);
}
}
UnloadImage(image);
auto data = from_bits(raw_bits);
std::cerr << "Printing expected " << data.size() << " bytes" << std::endl;
std::ofstream{"cordiceps.out", std::ios_base::binary} << data;
}
void CustomLog(int msgType, const char *text, va_list args)
{
fprintf(stderr, text, args);
}
int main(int argc, char** argv) {
SetTraceLogLevel(LOG_ERROR);
SetTraceLogCallback(CustomLog);
if(argc <= 1) {
perror("arguments missing, expected: picture then datafile for coding, picture for decoding");
}
if(argc == 3) {
encode(argv[1], argv[2]);
} else if(argc == 2) {
decode(argv[1]);
}
return 0;
}