/* cmake_minimum_required(VERSION 3.28) project(codiceps) 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(codiceps codiceps.cpp) target_link_libraries(codiceps PUBLIC raylib_static) */ #include #include #include #include #include #include #include "raylib.h" std::string slurp(const char* filename) { std::ifstream file{filename}; std::stringstream data; file >> data.rdbuf(); return data.str(); } std::vector to_bits(std::string str) { std::vector 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 data) { std::string d; for(auto composite : data | std::views::chunk(8)) { char c = 0; for(auto b : composite) { c *= 2; c += b; } d.push_back(c); } return d; } void encode(const char* pic, const char* data_source) { auto image = LoadImage(pic); auto raw_data = slurp(data_source); std::vector raw_bits = to_bits(raw_data); assert(raw_bits.size() % 8 == 0); assert(raw_bits.size() / 8 == raw_data.size()); 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 < raw_bits.size() ? raw_bits[idx] : 0; idx++; c.g += idx < raw_bits.size() ? raw_bits[idx] : 0; idx++; c.b += idx < raw_bits.size() ? raw_bits[idx] : 0; idx++; ImageDrawPixel(&image, i, j, c); } } ExportImage(image, pic); UnloadImage(image); if(raw_bits.size() > idx) { std::cout << "\x1b[1;31mWritten bits: " << raw_bits.size() << "/" << idx << std::endl; } else { std::cout << "\x1b[1;32mWritten bits: " << raw_bits.size() << "/" << idx << std::endl; } } void decode(const char* pic) { auto image = LoadImage(pic); std::vector 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); std::cout << from_bits(raw_bits).c_str() << std::endl; } int main(int argc, char** argv) { 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; }