From 07d931126f6969532cc5080477c9b82a302db41b Mon Sep 17 00:00:00 2001 From: Stephen Seo Date: Wed, 1 Dec 2021 17:31:51 +0900 Subject: [PATCH] Add arg parsing --- CMakeLists.txt | 1 + src/arg_parse.cc | 69 ++++++++++++++++++++++++++++++++++++++++++++++++ src/arg_parse.h | 22 +++++++++++++++ src/image.cc | 6 ++++- src/main.cc | 67 +++++++++++++++++++++++++++++++++++++++++----- src/video.cc | 7 ++--- src/video.h | 4 +-- 7 files changed, 163 insertions(+), 13 deletions(-) create mode 100644 src/arg_parse.cc create mode 100644 src/arg_parse.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 368bc1a..6939390 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3,6 +3,7 @@ project(EN605.617.81.FA21_StephenSeo_DitheringProject) set(Project_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/src/main.cc + ${CMAKE_CURRENT_SOURCE_DIR}/src/arg_parse.cc ${CMAKE_CURRENT_SOURCE_DIR}/src/image.cc ${CMAKE_CURRENT_SOURCE_DIR}/src/video.cc ${CMAKE_CURRENT_SOURCE_DIR}/src/opencl_handle.cc diff --git a/src/arg_parse.cc b/src/arg_parse.cc new file mode 100644 index 0000000..b61c9fa --- /dev/null +++ b/src/arg_parse.cc @@ -0,0 +1,69 @@ +#include "arg_parse.h" + +#include +#include + +Args::Args() + : do_dither_image_(true), + do_dither_grayscaled_(false), + do_overwrite_(false), + input_filename(), + output_filename() {} + +void Args::PrintUsage() { + std::cout + << "Usage: [-h | --help] [-i | --input ] [-o " + " | --output ] [-b | --blue " + "] [-g | --gray] [--image] [--video] [--overwrite]\n" + " -h | --help\t\t\t\tPrint this usage text\n" + " -i | --input \tSet input filename\n" + " -o | --output \tSet output filename\n" + " -b | --blue \tSet input blue_noise filename\n" + " -g | --gray\t\t\t\tDither output in grayscale\n" + " --image\t\t\t\tDither a single image\n" + " --video\t\t\t\tDither frames in a video\n" + " --overwrite\t\t\t\tAllow overwriting existing files\n" + << std::endl; +} + +bool Args::ParseArgs(int argc, char **argv) { + --argc; + ++argv; + while (argc > 0) { + if (std::strcmp(argv[0], "-h") == 0 || + std::strcmp(argv[0], "--help") == 0) { + PrintUsage(); + return true; + } else if (argc > 1 && (std::strcmp(argv[0], "-i") == 0 || + std::strcmp(argv[0], "--input") == 0)) { + input_filename = std::string(argv[1]); + --argc; + ++argv; + } else if (argc > 1 && (std::strcmp(argv[0], "-o") == 0 || + std::strcmp(argv[0], "--output") == 0)) { + output_filename = std::string(argv[1]); + --argc; + ++argv; + } else if (argc > 1 && (std::strcmp(argv[0], "-b") == 0 || + std::strcmp(argv[0], "--blue") == 0)) { + blue_noise_filename = std::string(argv[1]); + --argc; + ++argv; + } else if (std::strcmp(argv[0], "-g") == 0 || + std::strcmp(argv[0], "--gray") == 0) { + do_dither_grayscaled_ = true; + } else if (std::strcmp(argv[0], "--image") == 0) { + do_dither_image_ = true; + } else if (std::strcmp(argv[0], "--video") == 0) { + do_dither_image_ = false; + } else if (std::strcmp(argv[0], "--overwrite") == 0) { + do_overwrite_ = true; + } else { + std::cout << "WARNING: Ignoring invalid input \"" << argv[0] << '"' + << std::endl; + } + --argc; + ++argv; + } + return false; +} diff --git a/src/arg_parse.h b/src/arg_parse.h new file mode 100644 index 0000000..5f62494 --- /dev/null +++ b/src/arg_parse.h @@ -0,0 +1,22 @@ +#ifndef IGPUP_DITHERING_PROJECT_ARG_PARSE_ +#define IGPUP_DITHERING_PROJECT_ARG_PARSE_ + +#include + +struct Args { + Args(); + + static void PrintUsage(); + + /// Returns true if help was printed + bool ParseArgs(int argc, char **argv); + + bool do_dither_image_; + bool do_dither_grayscaled_; + bool do_overwrite_; + std::string input_filename; + std::string output_filename; + std::string blue_noise_filename; +}; + +#endif diff --git a/src/image.cc b/src/image.cc index 90712d2..284abf0 100644 --- a/src/image.cc +++ b/src/image.cc @@ -64,7 +64,11 @@ Image::Image(const std::string &filename) is_dithered_grayscale_(false), is_dithered_color_(false), is_preserving_blue_noise_offsets_(true) { - if (filename.compare(filename.size() - 4, filename.size(), ".png") == 0) { + if (filename.empty()) { + std::cout << "ERROR: Image got empty filename string" << std::endl; + return; + } else if (filename.compare(filename.size() - 4, filename.size(), ".png") == + 0) { // filename expected to be .png std::cout << "INFO: PNG filename extension detected, decoding..." << std::endl; diff --git a/src/main.cc b/src/main.cc index 9309377..e6c1720 100644 --- a/src/main.cc +++ b/src/main.cc @@ -1,18 +1,71 @@ #include +#include "arg_parse.h" #include "image.h" #include "video.h" int main(int argc, char **argv) { - Image blue_noise("bluenoise.png"); - if (!blue_noise.IsValid()) { - std::cout << "ERROR: Invalid bluenoise.png" << std::endl; + Args args{}; + if (args.ParseArgs(argc, argv)) { + return 0; + } + + Image blue_noise(args.blue_noise_filename); + if (!blue_noise.IsValid() || !blue_noise.IsGrayscale()) { + std::cout << "ERROR: Invalid blue noise file \"" << args.blue_noise_filename + << '"' << std::endl; + Args::PrintUsage(); return 1; } - Video video("input.mp4"); - if (!video.DitherVideo("output.mp4", &blue_noise, false)) { - std::cout << "ERROR: Failed to dither video" << std::endl; - return 1; + + if (args.do_dither_image_) { + Image input_image(args.input_filename); + if (!input_image.IsValid()) { + std::cout << "ERROR: Invalid input image file \"" << args.input_filename + << '"' << std::endl; + Args::PrintUsage(); + return 2; + } + + if (args.do_dither_grayscaled_) { + auto output_image = + input_image.ToGrayscaleDitheredWithBlueNoise(&blue_noise); + if (!output_image) { + std::cout << "ERROR: Failed to dither input image \"" + << args.input_filename << '"' << std::endl; + Args::PrintUsage(); + return 3; + } + if (!output_image->SaveAsPNG(args.output_filename, args.do_overwrite_)) { + std::cout << "ERROR: Failed to saved dithered image from input \"" + << args.input_filename << '"' << std::endl; + Args::PrintUsage(); + return 4; + } + } else { + auto output_image = input_image.ToColorDitheredWithBlueNoise(&blue_noise); + if (!output_image) { + std::cout << "ERROR: Failed to dither input image \"" + << args.input_filename << '"' << std::endl; + Args::PrintUsage(); + return 5; + } + if (!output_image->SaveAsPNG(args.output_filename, args.do_overwrite_)) { + std::cout << "ERROR: Failed to saved dithered image from input \"" + << args.input_filename << '"' << std::endl; + Args::PrintUsage(); + return 6; + } + } + } else { + Video video(args.input_filename); + if (!video.DitherVideo(args.output_filename, &blue_noise, + args.do_dither_grayscaled_, args.do_overwrite_)) { + std::cout << "ERROR: Failed to dither frames from input video \"" + << args.input_filename << '"' << std::endl; + Args::PrintUsage(); + return 7; + } } return 0; diff --git a/src/video.cc b/src/video.cc index bcf8795..a06722e 100644 --- a/src/video.cc +++ b/src/video.cc @@ -25,12 +25,13 @@ Video::~Video() { } bool Video::DitherVideo(const char *output_filename, Image *blue_noise, - bool grayscale) { - return DitherVideo(std::string(output_filename), blue_noise, grayscale); + bool grayscale, bool overwrite) { + return DitherVideo(std::string(output_filename), blue_noise, grayscale, + overwrite); } bool Video::DitherVideo(const std::string &output_filename, Image *blue_noise, - bool grayscale) { + bool grayscale, bool overwrite) { // Get AVFormatContext for input file AVFormatContext *avf_context = nullptr; std::string url = std::string("file:") + input_filename_; diff --git a/src/video.h b/src/video.h index e42e36e..7d9c675 100644 --- a/src/video.h +++ b/src/video.h @@ -27,7 +27,7 @@ class Video { /// Same as DitherVideo(const std::string&, Image*, bool) bool DitherVideo(const char *output_filename, Image *blue_noise, - bool grayscale = false); + bool grayscale = false, bool overwrite = false); /*! * \brief Dithers the frames in the input video. @@ -39,7 +39,7 @@ class Video { * \return True on success. */ bool DitherVideo(const std::string &output_filename, Image *blue_noise, - bool grayscale = false); + bool grayscale = false, bool overwrite = false); private: Image image_;