diff --git a/bindings/python/openshot.i b/bindings/python/openshot.i index 2f406c7f0..2bca526a7 100644 --- a/bindings/python/openshot.i +++ b/bindings/python/openshot.i @@ -41,6 +41,11 @@ %shared_ptr(juce::AudioBuffer) %shared_ptr(openshot::Frame) +/* Rename operators to avoid wrapping name collisions */ +%rename(__eq__) operator==; +%rename(__lt__) operator<; +%rename(__gt__) operator>; + /* Instantiate the required template specializations */ %template() std::map; %template() std::pair; @@ -249,6 +254,18 @@ %} } +%extend openshot::Profile { + bool __eq__(const openshot::Profile& other) const { + return (*self == other); + } + bool __lt__(const openshot::Profile& other) const { + return (*self < other); + } + bool __gt__(const openshot::Profile& other) const { + return (*self > other); + } +} + %extend openshot::OpenShotVersion { // Give the struct a string representation const std::string __str__() { diff --git a/src/Profiles.cpp b/src/Profiles.cpp index 4ea4e412c..c462ffc87 100644 --- a/src/Profiles.cpp +++ b/src/Profiles.cpp @@ -197,6 +197,28 @@ std::string Profile::LongNameWithDesc() { return output.str(); } +// Save profile to file system +void Profile::Save(const std::string& file_path) const { + std::ofstream file(file_path); + if (!file.is_open()) { + throw std::ios_base::failure("Failed to save profile."); + } + + file << "description=" << info.description << "\n"; + file << "frame_rate_num=" << info.fps.num << "\n"; + file << "frame_rate_den=" << info.fps.den << "\n"; + file << "width=" << info.width << "\n"; + file << "height=" << info.height << "\n"; + file << "progressive=" << !info.interlaced_frame << "\n"; // Correct the boolean value for progressive/interlaced + file << "sample_aspect_num=" << info.pixel_ratio.num << "\n"; + file << "sample_aspect_den=" << info.pixel_ratio.den << "\n"; + file << "display_aspect_num=" << info.display_ratio.num << "\n"; + file << "display_aspect_den=" << info.display_ratio.den << "\n"; + file << "pixel_format=" << info.pixel_format; + + file.close(); +} + // Generate JSON string of this object std::string Profile::Json() const { @@ -209,6 +231,7 @@ Json::Value Profile::JsonValue() const { // Create root json object Json::Value root; + root["description"] = info.description; root["height"] = info.height; root["width"] = info.width; root["pixel_format"] = info.pixel_format; @@ -221,7 +244,7 @@ Json::Value Profile::JsonValue() const { root["display_ratio"] = Json::Value(Json::objectValue); root["display_ratio"]["num"] = info.display_ratio.num; root["display_ratio"]["den"] = info.display_ratio.den; - root["interlaced_frame"] = info.interlaced_frame; + root["progressive"] = !info.interlaced_frame; // return JsonValue return root; @@ -247,6 +270,8 @@ void Profile::SetJson(const std::string value) { // Load Json::Value into this object void Profile::SetJsonValue(const Json::Value root) { + if (!root["description"].isNull()) + info.description = root["description"].asString(); if (!root["height"].isNull()) info.height = root["height"].asInt(); if (!root["width"].isNull()) @@ -260,12 +285,14 @@ void Profile::SetJsonValue(const Json::Value root) { if (!root["pixel_ratio"].isNull()) { info.pixel_ratio.num = root["pixel_ratio"]["num"].asInt(); info.pixel_ratio.den = root["pixel_ratio"]["den"].asInt(); + info.pixel_ratio.Reduce(); } if (!root["display_ratio"].isNull()) { info.display_ratio.num = root["display_ratio"]["num"].asInt(); info.display_ratio.den = root["display_ratio"]["den"].asInt(); + info.display_ratio.Reduce(); } - if (!root["interlaced_frame"].isNull()) - info.interlaced_frame = root["interlaced_frame"].asBool(); + if (!root["progressive"].isNull()) + info.interlaced_frame = !root["progressive"].asBool(); } diff --git a/src/Profiles.h b/src/Profiles.h index c10372a8a..1181431dc 100644 --- a/src/Profiles.h +++ b/src/Profiles.h @@ -139,9 +139,13 @@ namespace openshot Profile(); /// @brief Constructor for Profile. - /// @param path The folder path / location of a profile file + /// @param path The file path / location of a profile file Profile(std::string path); + /// @brief Save profile to a text file (label=value, one per line format) + /// @param file_path The file path / location of a profile file + void Save(const std::string& file_path) const; + std::string Key(); ///< Return a unique key of this profile with padding (01920x1080i2997_16:09) std::string ShortName(); ///< Return the name of this profile (1920x1080p29.97) std::string LongName(); ///< Return a longer format name (1920x1080p @ 29.97 fps (16:9)) diff --git a/tests/Profiles.cpp b/tests/Profiles.cpp index 05268dd13..b9f41a4a9 100644 --- a/tests/Profiles.cpp +++ b/tests/Profiles.cpp @@ -20,6 +20,7 @@ TEST_CASE( "empty constructor", "[libopenshot][profile]" ) openshot::Profile p1; // Default values + CHECK(p1.info.description.empty()); CHECK(p1.info.width == 0); CHECK(p1.info.height == 0); CHECK(p1.info.fps.num == 0); @@ -40,6 +41,7 @@ TEST_CASE( "constructor with example profiles", "[libopenshot][profile]" ) openshot::Profile p1(profile1.str()); // Default values + CHECK(p1.info.description == "HD 720p 24 fps"); CHECK(p1.info.width == 1280); CHECK(p1.info.height == 720); CHECK(p1.info.fps.num == 24); @@ -50,12 +52,28 @@ TEST_CASE( "constructor with example profiles", "[libopenshot][profile]" ) CHECK(p1.info.pixel_ratio.den == 1); CHECK(p1.info.interlaced_frame == false); + // Export to JSON + openshot::Profile p1_json = openshot::Profile(); + p1_json.SetJson(p1.Json()); + + CHECK(p1_json.info.description == "HD 720p 24 fps"); + CHECK(p1_json.info.width == 1280); + CHECK(p1_json.info.height == 720); + CHECK(p1_json.info.fps.num == 24); + CHECK(p1_json.info.fps.den == 1); + CHECK(p1_json.info.display_ratio.num == 16); + CHECK(p1_json.info.display_ratio.den == 9); + CHECK(p1_json.info.pixel_ratio.num == 1); + CHECK(p1_json.info.pixel_ratio.den == 1); + CHECK(p1_json.info.interlaced_frame == false); + std::stringstream profile2; profile2 << TEST_MEDIA_PATH << "example_profile2"; openshot::Profile p2(profile2.str()); // Default values + CHECK(p2.info.description == "HD 1080i 29.97 fps"); CHECK(p2.info.width == 1920); CHECK(p2.info.height == 1080); CHECK(p2.info.fps.num == 30000); @@ -134,3 +152,32 @@ TEST_CASE( "compare profiles", "[libopenshot][profile]" ) CHECK(p3 < p1); CHECK_FALSE(p1 == p3); } + +TEST_CASE( "save profiles", "[libopenshot][profile]" ) +{ + // Load profile + std::stringstream profile1; + profile1 << TEST_MEDIA_PATH << "example_profile1"; + openshot::Profile p1(profile1.str()); + + // Save copy + std::stringstream profile1_copy; + profile1_copy << TEST_MEDIA_PATH << "example_profile1_copy"; + std::cout << profile1_copy.str() << std::endl; + p1.Save(profile1_copy.str()); + + // Load saved copy + openshot::Profile p1_load_copy(profile1_copy.str()); + + // Default values + CHECK(p1_load_copy.info.description == "HD 720p 24 fps"); + CHECK(p1_load_copy.info.width == 1280); + CHECK(p1_load_copy.info.height == 720); + CHECK(p1_load_copy.info.fps.num == 24); + CHECK(p1_load_copy.info.fps.den == 1); + CHECK(p1_load_copy.info.display_ratio.num == 16); + CHECK(p1_load_copy.info.display_ratio.den == 9); + CHECK(p1_load_copy.info.pixel_ratio.num == 1); + CHECK(p1_load_copy.info.pixel_ratio.den == 1); + CHECK(p1_load_copy.info.interlaced_frame == false); +} \ No newline at end of file