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.

118 lines
3.1 KiB

  1. /*
  2. cmake_minimum_required(VERSION 3.28)
  3. project(codiceps)
  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(codiceps codiceps.cpp)
  13. target_link_libraries(codiceps PUBLIC raylib_static)
  14. */
  15. #include <ranges>
  16. #include <iostream>
  17. #include <fstream>
  18. #include <sstream>
  19. #include <vector>
  20. #include <cassert>
  21. #include "raylib.h"
  22. std::string slurp(const char* filename) {
  23. std::ifstream file{filename};
  24. std::stringstream data;
  25. file >> data.rdbuf();
  26. return data.str();
  27. }
  28. std::vector<bool> to_bits(std::string str) {
  29. std::vector<bool> d;
  30. for(char c : str) {
  31. d.push_back(c & 0b10000000);
  32. d.push_back(c & 0b1000000);
  33. d.push_back(c & 0b100000);
  34. d.push_back(c & 0b10000);
  35. d.push_back(c & 0b1000);
  36. d.push_back(c & 0b100);
  37. d.push_back(c & 0b10);
  38. d.push_back(c & 0b1);
  39. }
  40. return d;
  41. }
  42. std::string from_bits(std::vector<bool> data) {
  43. std::string d;
  44. for(auto composite : data | std::views::chunk(8)) {
  45. char c = 0;
  46. for(auto b : composite) {
  47. c *= 2;
  48. c += b;
  49. }
  50. d.push_back(c);
  51. }
  52. return d;
  53. }
  54. void encode(const char* pic, const char* data_source) {
  55. auto image = LoadImage(pic);
  56. auto raw_data = slurp(data_source);
  57. std::vector<bool> raw_bits = to_bits(raw_data);
  58. assert(raw_bits.size() % 8 == 0);
  59. assert(raw_bits.size() / 8 == raw_data.size());
  60. size_t idx = 0;
  61. for(auto j : std::ranges::iota_view(0, image.height)) {
  62. for(auto i : std::ranges::iota_view(0, image.width)) {
  63. auto c = GetImageColor(image, i, j);
  64. c.r ^= c.r & 1;
  65. c.g ^= c.g & 1;
  66. c.b ^= c.b & 1;
  67. c.r += idx < raw_bits.size() ? raw_bits[idx] : 0; idx++;
  68. c.g += idx < raw_bits.size() ? raw_bits[idx] : 0; idx++;
  69. c.b += idx < raw_bits.size() ? raw_bits[idx] : 0; idx++;
  70. ImageDrawPixel(&image, i, j, c);
  71. }
  72. }
  73. ExportImage(image, pic);
  74. UnloadImage(image);
  75. if(raw_bits.size() > idx) {
  76. std::cout << "\x1b[1;31mWritten bits: " << raw_bits.size() << "/" << idx << std::endl;
  77. } else {
  78. std::cout << "\x1b[1;32mWritten bits: " << raw_bits.size() << "/" << idx << std::endl;
  79. }
  80. }
  81. void decode(const char* pic) {
  82. auto image = LoadImage(pic);
  83. std::vector<bool> raw_bits;
  84. size_t idx = 0;
  85. for(auto j : std::ranges::iota_view(0, image.height)) {
  86. for(auto i : std::ranges::iota_view(0, image.width)) {
  87. auto c = GetImageColor(image, i, j);
  88. raw_bits.push_back(c.r & 1);
  89. raw_bits.push_back(c.g & 1);
  90. raw_bits.push_back(c.b & 1);
  91. }
  92. }
  93. UnloadImage(image);
  94. std::cout << from_bits(raw_bits).c_str() << std::endl;
  95. }
  96. int main(int argc, char** argv) {
  97. if(argc < 1) {
  98. perror("arguments missing, expected: picture then datafile for coding, picture for decoding");
  99. }
  100. if(argc == 3) {
  101. encode(argv[1], argv[2]);
  102. } else if(argc == 2) {
  103. decode(argv[1]);
  104. }
  105. return 0;
  106. }