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.

146 lines
4.2 KiB

  1. /*
  2. cmake_minimum_required(VERSION 3.27)
  3. project(cordiceps)
  4. set(CMAKE_CXX_STANDARD 23)
  5. include(FetchContent)
  6. FetchContent_Declare(
  7. raylib
  8. GIT_REPOSITORY https://github.com/raysan5/raylib.git
  9. GIT_TAG 5.0
  10. )
  11. FetchContent_MakeAvailable(raylib)
  12. add_executable(cordiceps cordiceps.cpp)
  13. target_link_libraries(cordiceps PUBLIC raylib_static)
  14. */
  15. #include <ranges>
  16. #include <iostream>
  17. #include <fstream>
  18. #include <sstream>
  19. #include <vector>
  20. #include <cassert>
  21. #include <cstdint>
  22. #include <bit>
  23. #include <bitset>
  24. #include "raylib.h"
  25. std::string slurp(const char* filename) {
  26. std::ifstream file{filename, std::ios_base::binary};
  27. std::stringstream data;
  28. file >> data.rdbuf();
  29. return data.str();
  30. }
  31. std::vector<bool> to_bits(std::string str) {
  32. std::vector<bool> d;
  33. for(char c : str) {
  34. d.push_back(c & 0b10000000);
  35. d.push_back(c & 0b1000000);
  36. d.push_back(c & 0b100000);
  37. d.push_back(c & 0b10000);
  38. d.push_back(c & 0b1000);
  39. d.push_back(c & 0b100);
  40. d.push_back(c & 0b10);
  41. d.push_back(c & 0b1);
  42. }
  43. return d;
  44. }
  45. std::string from_bits(std::vector<bool> data) {
  46. std::string d;
  47. std::bitset<32> size_bits;
  48. for(int idx = 0; idx < 32; ++idx) size_bits[idx] = data[idx];
  49. uint32_t size = size_bits.to_ulong();
  50. if(std::endian::native == std::endian::little) size = std::byteswap(size);
  51. std::cerr << "Decoded expected " << size << " bytes" << std::endl;
  52. for(auto composite : data | std::views::drop(32) | std::views::chunk(8)) {
  53. char c = 0;
  54. for(auto b : composite) {
  55. c *= 2;
  56. c += b;
  57. }
  58. d.push_back(c);
  59. size--;
  60. if(size == 0) return d;
  61. }
  62. return d;
  63. }
  64. void encode(const char* pic, const char* data_source) {
  65. auto image = LoadImage(pic);
  66. auto raw_data = slurp(data_source);
  67. uint32_t size = raw_data.size();
  68. std::cerr << "Writing expected " << size << " bytes" << std::endl;
  69. if(std::endian::native == std::endian::little) size = std::byteswap(size);
  70. std::bitset<32> size_bits;
  71. size_bits = size;
  72. std::vector<bool> raw_bits = to_bits(raw_data);
  73. assert(raw_bits.size() % 8 == 0);
  74. assert(raw_bits.size() / 8 == raw_data.size());
  75. std::vector<bool> data;
  76. for(int idx = 0; idx < 32; ++idx) data.push_back(size_bits[idx]);
  77. data.insert(data.end(), raw_bits.begin(), raw_bits.end());
  78. size_t idx = 0;
  79. for(auto j : std::ranges::iota_view(0, image.height)) {
  80. for(auto i : std::ranges::iota_view(0, image.width)) {
  81. auto c = GetImageColor(image, i, j);
  82. c.r ^= c.r & 1;
  83. c.g ^= c.g & 1;
  84. c.b ^= c.b & 1;
  85. c.r += idx < data.size() ? data[idx] : 0; idx++;
  86. c.g += idx < data.size() ? data[idx] : 0; idx++;
  87. c.b += idx < data.size() ? data[idx] : 0; idx++;
  88. ImageDrawPixel(&image, i, j, c);
  89. }
  90. }
  91. ExportImage(image, pic);
  92. UnloadImage(image);
  93. if(raw_bits.size() > idx) {
  94. std::cout << "\x1b[1;31mWritten bits: " << data.size() << "/" << idx << std::endl;
  95. } else {
  96. std::cout << "\x1b[1;32mWritten bits: " << data.size() << "/" << idx << std::endl;
  97. }
  98. }
  99. void decode(const char* pic) {
  100. auto image = LoadImage(pic);
  101. std::vector<bool> raw_bits;
  102. size_t idx = 0;
  103. for(auto j : std::ranges::iota_view(0, image.height)) {
  104. for(auto i : std::ranges::iota_view(0, image.width)) {
  105. auto c = GetImageColor(image, i, j);
  106. raw_bits.push_back(c.r & 1);
  107. raw_bits.push_back(c.g & 1);
  108. raw_bits.push_back(c.b & 1);
  109. }
  110. }
  111. UnloadImage(image);
  112. auto data = from_bits(raw_bits);
  113. std::cerr << "Printing expected " << data.size() << " bytes" << std::endl;
  114. std::ofstream{"cordiceps.out", std::ios_base::binary} << data;
  115. }
  116. void CustomLog(int msgType, const char *text, va_list args)
  117. {
  118. fprintf(stderr, text, args);
  119. }
  120. int main(int argc, char** argv) {
  121. SetTraceLogLevel(LOG_ERROR);
  122. SetTraceLogCallback(CustomLog);
  123. if(argc <= 1) {
  124. perror("arguments missing, expected: picture then datafile for coding, picture for decoding");
  125. }
  126. if(argc == 3) {
  127. encode(argv[1], argv[2]);
  128. } else if(argc == 2) {
  129. decode(argv[1]);
  130. }
  131. return 0;
  132. }