shushus

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

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