|
|
- /*
- 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;
- }
|