shushus

Спринт 15. Археологические раскопки: подключаем LibJPEG. Задание 1.

May 31st, 2023
737
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 11.25 KB | None | 0 0
  1.  
  2. *** PACKAGE ImgConverter ***
  3.  
  4. -----------------------------------------------------------------------
  5. CMakeLists.txt
  6. -----------------------------------------------------------------------
  7. cmake_minimum_required(VERSION 3.11)
  8.  
  9. project(Negate CXX)
  10. set(CMAKE_CXX_STANDARD 17)
  11.  
  12. add_subdirectory(../ImgLib ImgLibBuildDir)
  13.  
  14. if (CMAKE_SYSTEM_NAME MATCHES "^MINGW")
  15.     set(SYSTEM_LIBS -lstdc++)
  16. else()
  17.     set(SYSTEM_LIBS)
  18. endif()
  19.  
  20. add_executable(imgconv main.cpp)
  21.  
  22. target_include_directories(imgconv PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/../ImgLib")
  23.  
  24. target_link_libraries(imgconv ImgLib ${SYSTEM_LIBS})
  25. -----------------------------------------------------------------------
  26. main.cpp
  27. -----------------------------------------------------------------------
  28. #include <img_lib.h>
  29. #include <jpeg_image.h>
  30. #include <ppm_image.h>
  31.  
  32. #include <filesystem>
  33. #include <string_view>
  34. #include <iostream>
  35.  
  36. using namespace std;
  37.  
  38. int main(int argc, const char** argv) {
  39.    
  40.     if (argc != 3) {
  41.         cerr << "Usage: "sv << argv[0] << " <in_file> <out_file>"sv << endl;
  42.         return 1;
  43.     }
  44.  
  45.     img_lib::Path in_path = argv[1];
  46.     img_lib::Path out_path = argv[2];
  47.  
  48.     img_lib::Image image = img_lib::LoadPPM(in_path);
  49.    
  50.     if (!image) {
  51.         cerr << "Loading failed"sv << endl;
  52.         return 4;
  53.     }
  54.  
  55.     if (!img_lib::SaveJPEG(out_path, image)) {
  56.         cerr << "Saving failed"sv << endl;
  57.         return 5;
  58.     }
  59.  
  60.     cout << "Successfully converted"sv << endl;
  61. }
  62.  
  63. *** PACKAGE ImgConverter END ***
  64.  
  65. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  66.  
  67. *** PACKAGE ImgLib ***
  68.  
  69. -----------------------------------------------------------------------
  70. CMakeLists.txt
  71. -----------------------------------------------------------------------
  72. cmake_minimum_required(VERSION 3.11)
  73.  
  74. project(ImgLib CXX)
  75. set(CMAKE_CXX_STANDARD 17)
  76.  
  77. set(LIBJPEG_DIR CACHE STRING "LibJPEG static library directory")
  78.  
  79. if(NOT LIBJPEG_DIR)
  80.     message(FATAL_ERROR "Please, specify LibJPEG directory via -DLIBJPEG_DIR=<dir>")
  81. endif()
  82.     message(STATUS "LibJPEG dir is ${LIBJPEG_DIR}, change via -DLIBJPEG_DIR=<dir>")
  83.  
  84. set(IMGLIB_MAIN_FILES img_lib.h img_lib.cpp)
  85.  
  86. set(IMGLIB_FORMAT_FILES ppm_image.h ppm_image.cpp
  87.                         jpeg_image.h jpeg_image.cpp)
  88.  
  89. add_library(ImgLib STATIC ${IMGLIB_MAIN_FILES}
  90.                           ${IMGLIB_FORMAT_FILES})
  91.  
  92. target_include_directories(ImgLib PUBLIC "${LIBJPEG_DIR}/include")
  93.  
  94. target_link_directories(ImgLib INTERFACE "${LIBJPEG_DIR}/lib/$<IF:$<CONFIG:Debug>,Debug,Release>")
  95.  
  96. target_link_libraries(ImgLib INTERFACE jpeg)
  97. -----------------------------------------------------------------------
  98. jpeg_image.h
  99. -----------------------------------------------------------------------
  100. #pragma once
  101. #include "img_lib.h"
  102.  
  103. #include <filesystem>
  104.  
  105. namespace img_lib {
  106.    
  107. using Path = std::filesystem::path;
  108.  
  109. bool SaveJPEG(const Path& file, const Image& image);
  110. Image LoadJPEG(const Path& file);
  111.  
  112. }//end namespace img_lib
  113. -----------------------------------------------------------------------
  114. jpeg_image.cpp
  115. -----------------------------------------------------------------------
  116. #include "ppm_image.h"
  117.  
  118. #include <array>
  119. #include <fstream>
  120. #include <stdio.h>
  121. #include <setjmp.h>
  122. #include <vector>
  123.  
  124. #include <jpeglib.h>
  125.  
  126. using namespace std;
  127.  
  128. namespace img_lib {
  129.  
  130. struct my_error_mgr {
  131.     struct jpeg_error_mgr pub;
  132.     jmp_buf setjmp_buffer;
  133. };
  134.  
  135. typedef struct my_error_mgr* my_error_ptr;
  136.  
  137. METHODDEF(void)
  138. my_error_exit (j_common_ptr cinfo) {
  139.     my_error_ptr myerr = (my_error_ptr) cinfo->err;
  140.     (*cinfo->err->output_message) (cinfo);
  141.     longjmp(myerr->setjmp_buffer, 1);
  142. }
  143.  
  144. bool SaveJPEG(const Path& file, const Image& image) {
  145.  
  146.     jpeg_compress_struct cinfo;
  147.     jpeg_error_mgr jerr;
  148.  
  149.     FILE* outfile;              
  150.     JSAMPROW row_pointer[1];    
  151.     int row_stride;                
  152.  
  153.     cinfo.err = jpeg_std_error(&jerr);
  154.     jpeg_create_compress(&cinfo);
  155.  
  156. #ifdef _MSC_VER
  157.     if ((outfile = _wfopen(file.wstring().c_str(), "wb")) == NULL) {
  158. #else
  159.     if ((outfile = fopen(file.string().c_str(), "wb")) == NULL) {
  160. #endif
  161.     return false;}
  162.    
  163.     jpeg_stdio_dest(&cinfo, outfile);
  164.  
  165.     cinfo.image_width = image.GetWidth();
  166.     cinfo.image_height = image.GetHeight();
  167.     cinfo.input_components = 3;      
  168.     cinfo.in_color_space = JCS_RGB;  
  169.  
  170.     jpeg_set_defaults(&cinfo);
  171.     jpeg_start_compress(&cinfo, TRUE);
  172.     row_stride = image.GetWidth() * 3;
  173.  
  174.     while (cinfo.next_scanline < cinfo.image_height) {      
  175.         std::vector<JSAMPLE> jsample(row_stride);
  176.        
  177.         for (int i = 0; i < image.GetWidth(); ++i) {
  178.            
  179.             jsample[3 * i] = JSAMPLE(image.GetLine(cinfo.next_scanline)[i].r);
  180.             jsample[1 + 3 * i] = JSAMPLE(image.GetLine(cinfo.next_scanline)[i].g);
  181.             jsample[2 + 3 * i] = JSAMPLE(image.GetLine(cinfo.next_scanline)[i].b);
  182.         }
  183.        
  184.         row_pointer[0] = &jsample[0];
  185.         (void)jpeg_write_scanlines(&cinfo, row_pointer, 1);
  186.     }
  187.  
  188.     jpeg_finish_compress(&cinfo);
  189.     fclose(outfile);
  190.  
  191.     jpeg_destroy_compress(&cinfo);
  192.    
  193.     return true;
  194. }
  195.  
  196. void SaveScanlineToImage(const JSAMPLE* row, int y, Image& out_image) {
  197.    
  198.     Color* line = out_image.GetLine(y);
  199.    
  200.     for (int x = 0; x < out_image.GetWidth(); ++x) {
  201.        
  202.         const JSAMPLE* pixel = row + x * 3;
  203.         line[x] = Color{byte{pixel[0]}, byte{pixel[1]}, byte{pixel[2]}, byte{255}};
  204.     }
  205. }
  206.  
  207. Image LoadJPEG(const Path& file) {
  208.     jpeg_decompress_struct cinfo;
  209.     my_error_mgr jerr;
  210.    
  211.     FILE* infile;
  212.     JSAMPARRAY buffer;
  213.     int row_stride;
  214.  
  215. #ifdef _MSC_VER
  216.     if ((infile = _wfopen(file.wstring().c_str(), "rb")) == NULL) {
  217. #else
  218.     if ((infile = fopen(file.string().c_str(), "rb")) == NULL) {
  219. #endif
  220.         return {};
  221.     }
  222.  
  223.     cinfo.err = jpeg_std_error(&jerr.pub);
  224.     jerr.pub.error_exit = my_error_exit;
  225.  
  226.     if (setjmp(jerr.setjmp_buffer)) {
  227.         jpeg_destroy_decompress(&cinfo);
  228.         fclose(infile);
  229.         return {};
  230.     }
  231.  
  232.     jpeg_create_decompress(&cinfo);
  233.     jpeg_stdio_src(&cinfo, infile);
  234.     (void) jpeg_read_header(&cinfo, TRUE);
  235.     cinfo.out_color_space = JCS_RGB;
  236.     cinfo.output_components = 3;
  237.     (void) jpeg_start_decompress(&cinfo);
  238.    
  239.     row_stride = cinfo.output_width * cinfo.output_components;    
  240.     buffer = (*cinfo.mem->alloc_sarray) ((j_common_ptr) &cinfo, JPOOL_IMAGE, row_stride, 1);
  241.  
  242.     Image result(cinfo.output_width, cinfo.output_height, Color::Black());
  243.  
  244.     while (cinfo.output_scanline < cinfo.output_height) {
  245.         int y = cinfo.output_scanline;
  246.         (void) jpeg_read_scanlines(&cinfo, buffer, 1);
  247.  
  248.         SaveScanlineToImage(buffer[0], y, result);
  249.     }
  250.  
  251.     (void) jpeg_finish_decompress(&cinfo);
  252.  
  253.     jpeg_destroy_decompress(&cinfo);
  254.     fclose(infile);
  255.  
  256.     return result;
  257. }
  258.  
  259. }//end namespace img_lib
  260. -----------------------------------------------------------------------
  261. img_lib.h
  262. -----------------------------------------------------------------------
  263. #pragma once
  264.  
  265. #include <array>
  266. #include <cassert>
  267. #include <cstddef>
  268. #include <vector>
  269.  
  270. namespace img_lib {
  271.  
  272. struct Size {
  273.     int width;
  274.     int height;
  275. };
  276.  
  277. struct Color {
  278.    
  279.     static Color Black() {
  280.        
  281.         return {std::byte{0},
  282.                 std::byte{0},
  283.                 std::byte{0},
  284.                 std::byte{255}};
  285.     }
  286.  
  287.     std::byte r, g, b, a;
  288. };
  289.  
  290. class Image {
  291. public:
  292.  
  293.     Image() = default;
  294.  
  295.     Image(int w, int h, Color fill);
  296.  
  297.     Color GetPixel(int x, int y) const {return const_cast<Image*>(this)->GetPixel(x, y);}
  298.    
  299.     Color& GetPixel(int x, int y) {
  300.         assert(x < GetWidth() && y < GetHeight() && x >= 0 && y >= 0);
  301.         return GetLine(y)[x];
  302.     }
  303.  
  304.     Color* GetLine(int y);
  305.     const Color* GetLine(int y) const;
  306.  
  307.     int GetWidth() const;
  308.     int GetHeight() const;
  309.  
  310.     int GetStep() const;
  311.  
  312.     explicit operator bool() const {return GetWidth() > 0 && GetHeight() > 0;}
  313.     bool operator!() const {return !operator bool();}
  314.  
  315. private:
  316.     int width_ = 0;
  317.     int height_ = 0;
  318.     int step_;
  319.  
  320.     std::vector<Color> pixels_;
  321. };
  322.  
  323. }//end namespace img_lib
  324. -----------------------------------------------------------------------
  325. img_lib.cpp
  326. -----------------------------------------------------------------------
  327. #include "img_lib.h"
  328.  
  329. namespace img_lib {
  330.  
  331. Image::Image(int w, int h, Color fill) : width_(w)
  332.                                        , height_(h)
  333.                                        , step_(w)
  334.                                        , pixels_(step_ * height_, fill) {}
  335.  
  336. Color* Image::GetLine(int y) {
  337.     assert(y >= 0 && y < height_);
  338.     return pixels_.data() + step_ * y;
  339. }
  340.  
  341. const Color* Image::GetLine(int y) const {return const_cast<Image*>(this)->GetLine(y);}
  342. int Image::GetWidth() const {return width_;}
  343. int Image::GetHeight() const {return height_;}
  344. int Image::GetStep() const {return step_;}
  345.  
  346. }//end namespace img_lib
  347. -----------------------------------------------------------------------
  348. ppm_image.h
  349. -----------------------------------------------------------------------
  350. #pragma once
  351. #include "img_lib.h"
  352.  
  353. #include <filesystem>
  354.  
  355. namespace img_lib {
  356.    
  357. using Path = std::filesystem::path;
  358.  
  359. bool SavePPM(const Path& file, const Image& image);
  360. Image LoadPPM(const Path& file);
  361.  
  362. }//end namespace img_lib
  363. -----------------------------------------------------------------------
  364. ppm_image.cpp
  365. -----------------------------------------------------------------------
  366. #include "ppm_image.h"
  367.  
  368. #include <array>
  369. #include <fstream>
  370. #include <string_view>
  371.  
  372. using namespace std;
  373.  
  374. namespace img_lib {
  375.  
  376. static const string_view PPM_SIG = "P6"sv;
  377. static const int PPM_MAX = 255;
  378.  
  379. bool SavePPM(const Path& file, const Image& image) {
  380.     ofstream out(file, ios::binary);
  381.  
  382.     out << PPM_SIG << '\n' << image.GetWidth() << ' ' << image.GetHeight() << '\n' << PPM_MAX << '\n';
  383.  
  384.     const int w = image.GetWidth();
  385.     const int h = image.GetHeight();
  386.     std::vector<char> buff(w * 3);
  387.  
  388.     for (int y = 0; y < h; ++y) {
  389.        
  390.         const Color* line = image.GetLine(y);
  391.        
  392.         for (int x = 0; x < w; ++x) {
  393.             buff[x * 3 + 0] = static_cast<char>(line[x].r);
  394.             buff[x * 3 + 1] = static_cast<char>(line[x].g);
  395.             buff[x * 3 + 2] = static_cast<char>(line[x].b);
  396.         }
  397.        
  398.         out.write(buff.data(), w * 3);
  399.     }
  400.  
  401.     return out.good();
  402. }
  403.  
  404. Image LoadPPM(const Path& file) {
  405.     ifstream ifs(file, ios::binary);
  406.     std::string sign;
  407.     int w, h, color_max;
  408.  
  409.     ifs >> sign >> w >> h >> color_max;
  410.  
  411.     if (sign != PPM_SIG || color_max != PPM_MAX) {return {};}
  412.  
  413.     const char next = ifs.get();
  414.     if (next != '\n') {return {};}
  415.  
  416.     Image result(w, h, Color::Black());
  417.     std::vector<char> buff(w * 3);
  418.  
  419.     for (int y = 0; y < h; ++y) {
  420.        
  421.         Color* line = result.GetLine(y);
  422.         ifs.read(buff.data(), w * 3);
  423.  
  424.         for (int x = 0; x < w; ++x) {
  425.             line[x].r = static_cast<byte>(buff[x * 3 + 0]);
  426.             line[x].g = static_cast<byte>(buff[x * 3 + 1]);
  427.             line[x].b = static_cast<byte>(buff[x * 3 + 2]);
  428.         }
  429.     }
  430.  
  431.     return result;
  432. }
  433.  
  434. }//end namespace img_lib
  435.  
  436. *** PACKAGE ImgLib END ***
Advertisement
Add Comment
Please, Sign In to add comment