diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index 421307b..7e668d6 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -100,3 +100,50 @@ jobs: if: startsWith(github.ref, 'refs/tags/v') with: files: ${{ env.BUILD_DIR }}/photils-cli-${{ env.VERSION }}-osx.zip + build-and-test-windows: + runs-on: windows-latest + steps: + - uses: actions/checkout@v3 + - name: prepare + run: | + pip3 install conan + conan profile new default --detect + mkdir ${{ env.BUILD_DIR }} + # caching seems to produces erros after once the cache was build + # - name: get conan cache + # uses: actions/cache@v3 + # with: + # path: | + # ~/.conan/data + # key: conan-${{ runner.os }}-${{ hashFiles('./conanfile.txt') }} + - name: install dependencies + if: steps.cache.outputs.cache-hit != 'true' + run: conan install . --install-folder build --build=missing + - name: configure and build + working-directory: ${{ env.BUILD_DIR }} + run: | + cmake .. + cmake --build . --config Release + - name: run tests + run: ${{ env.BUILD_DIR }}/Release/bin/photils-cli_test + - run: | + echo VERSION=$(grep "PROJECT_VER " include/version.h | cut -d \" -f2) >> $GITHUB_ENV + shell: bash + - name: build windows zip + if: startsWith(github.ref, 'refs/tags/v') + run: | + cmake -DBUILD_TESTS=OFF .. + cmake --build . --config Release + cpack + working-directory: ${{ env.BUILD_DIR }} + - name: deploy + if: startsWith(github.ref, 'refs/tags/v') + uses: actions/upload-artifact@v3 + with: + name: photils-cli-${{ env.VERSION }}-win64 + path: ${{ env.BUILD_DIR }}/*.zip + - name: Release + uses: softprops/action-gh-release@v1 + if: startsWith(github.ref, 'refs/tags/v') + with: + files: ${{ env.BUILD_DIR }}/photils-cli-${{ env.VERSION }}-win64.zip diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 6997402..eced6ff 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -5,15 +5,3 @@ repos: - id: check-yaml - id: trailing-whitespace - id: end-of-file-fixer - - repo: https://github.com/PyCQA/isort - rev: 5.10.1 - hooks: - - id: isort - - repo: https://github.com/PyCQA/pylint - rev: v2.14.3 # Use the sha / tag you want to point at - hooks: - - id: pylint - - repo: https://github.com/psf/black - rev: 22.3.0 - hooks: - - id: black diff --git a/CMakeLists.txt b/CMakeLists.txt index ab5f02d..ed691c5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,18 +4,18 @@ include(FeatureSummary) set(CMAKE_BUILD_TYPE "Release" CACHE STRING "Choose the type of build.") project(photils-cli) -project(${PROJECT_NAME} VERSION "0.4.0") +project(${PROJECT_NAME} VERSION "0.4.1") OPTION(BUILD_TESTS "Build test" ON) include(${CMAKE_BINARY_DIR}/conanbuildinfo.cmake) conan_basic_setup(NO_OUTPUT_DIRS) -set(CMAKE_CXX_STANDARD 14) +set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED OFF) set(THREADS_PREFER_PTHREAD_FLAG ON) -set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/${CMAKE_BUILD_TYPE}/lib) -set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/${CMAKE_BUILD_TYPE}/bin) + +message("Runtime DIr: ${OUTPUT_REL}") if(APPLE) set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -stdlib=libc++ -lc++abi") @@ -24,16 +24,14 @@ if(APPLE) set_source_files_properties(${OSX_APP_ICON} PROPERTIES MACOSX_PACKAGE_LOCATION "Resources") endif() -include_directories(${PROJECT_SOURCE_DIR}/include) + +file(GLOB_RECURSE PHOTILS_SRC ${PROJECT_SOURCE_DIR}/src/*.cpp) find_package(Threads REQUIRED) list(APPEND CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake) configure_file(${PROJECT_SOURCE_DIR}/include/version.h.in ${PROJECT_SOURCE_DIR}/include/version.h) -get_filename_component(RESOURCE_FOLDER ${CMAKE_RUNTIME_OUTPUT_DIRECTORY} DIRECTORY) -file(GLOB_RECURSE PHOTILS_SRC ${PROJECT_SOURCE_DIR}/src/*.cpp) - if(APPLE) set(EXTRA_LIBS "") add_executable(${PROJECT_NAME} MACOSX_BUNDLE ${OSX_APP_ICON} ${PHOTILS_SRC}) @@ -42,13 +40,30 @@ else() add_executable(${PROJECT_NAME} ${PHOTILS_SRC}) endif() +target_include_directories(${PROJECT_NAME} PUBLIC ${PROJECT_SOURCE_DIR}/include) +set_target_properties( ${PROJECT_NAME} + PROPERTIES + ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/${CMAKE_BUILD_TYPE}/lib + LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/${CMAKE_BUILD_TYPE}/lib + RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/${CMAKE_BUILD_TYPE}/bin + RUNTIME_OUTPUT_DIRECTORY_DEBUG ${CMAKE_BINARY_DIR}/${CMAKE_BUILD_TYPE}/bin + RUNTIME_OUTPUT_DIRECTORY_RELEASE ${CMAKE_BINARY_DIR}/${CMAKE_BUILD_TYPE}/bin +) + +get_target_property( RESOURCE_FOLDER ${PROJECT_NAME} RUNTIME_OUTPUT_DIRECTORY) +get_filename_component(RESOURCE_FOLDER ${RESOURCE_FOLDER} DIRECTORY) + + + message("conan: ${CONAN_LIBS}") target_link_libraries(${PROJECT_NAME} ${CONAN_LIBS}) +message("COPY Target: ${RESOURCE_FOLDER}") + file(MAKE_DIRECTORY ${RESOURCE_FOLDER}/share/photils/) add_custom_command( TARGET ${PROJECT_NAME} POST_BUILD - COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_SOURCE_DIR}/res/* ${RESOURCE_FOLDER}/share/photils/ + COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR}/res ${RESOURCE_FOLDER}/share/photils ) include(Install) diff --git a/README.md b/README.md index e8942e4..5641a3a 100644 --- a/README.md +++ b/README.md @@ -1,32 +1,29 @@ # photils-cli -[![Build Status](https://travis-ci.org/scheckmedia/photils-cli.svg?branch=master)](https://travis-ci.org/scheckmedia/photils-cli) +![Build Status](https://github.com/scheckmedia/photils-cli/actions/workflows/build.yaml/badge.svg) Photils-cli is an application that passes an image through a neural network, classifies it, and extracts the suggested tags. Everything happens offline without the need that your data are sent over the internet. The reason for this application is mainly the integration into [darktable](https://www.darktable.org/) as [plugin](https://github.com/scheckmedia/photils-dt). ## Installation -## Conan -conan profile update settings.compiler.libcxx=libstdc++11 default + +[![](https://img.shields.io/badge/Releases%40latest-Download-blue)](https://github.com/scheckmedia/photils-cli/releases) ### Linux - [![](https://img.shields.io/badge/Linux%40latest-Download-blue)]( -https://github.com/scheckmedia/photils-cli/releases/latest/download/photils-cli-linux-x86_64.AppImage) -1. Download the latest release +1. Download the latest release `photils-cli-VERSION-linux.zip` 2. Copy the photils-cli.AppImage at some safe pleace 3. Make the AppImage executable: https://youtu.be/nzZ6Ikc7juw ### MacOS -[![](https://img.shields.io/badge/MacOS%40latest-Download-blue)]( -https://github.com/scheckmedia/photils-cli/releases/latest/download/photils-cli-osx.zip) -1. Download the latest release -2. Extract the zip and copy the photils-cli.app at some safe pleace +1. Download the latest release `photils-cli-VERSION-osx.zip` +2. Extract the zip and copy the photils-cli.app at some safe place ### Windows -*work in progress* +1. Download the latest release `photils-cli-VERSION-win64.zip` +2. Extract the zip and copy the content of the zip at some safe place ## Usage #### Linux: @@ -39,6 +36,11 @@ $ ./photils-cli.AppImage --image ~/Pictures/_DSC2437.jpg $ ./photils-cli.app/Contents/MacOS/photils-cli --image ~/Pictures/_DSC2437.jpg ``` +#### MacOS: +```bash +$ .\photils-cli.exe --image C:\Documents\somepic.jpg +``` + ### Args ```bash photils-cli [OPTION...] @@ -55,10 +57,11 @@ photils-cli [OPTION...] photils comes with a fixed list of ~3700 [available tags](https://github.com/scheckmedia/photils-cli/blob/master/res/labels.json). In some cases, the language or space-less tag style does not fit your workflow. For such cases, you have the option to override tags with your own style. For example, if you don't like the *blackbackground* tag and want *black background* instead, you can user the override file to fix this. You can also use it to translate the tags to the language of your choice. All what you need is to place a file named **override_labels.json** in the folder: -| OS | Path | -| ----- | -------------------------------------------------------------- | -| MacOS | $HOME/Library/Application Support/photils/override_labels.json | -| Linux | $HOME/.local/share/photils/override_labels.json | +| OS | Path | +| ------- | -------------------------------------------------------------- | +| MacOS | $HOME/Library/Application Support/photils/override_labels.json | +| Linux | $HOME/.local/share/photils/override_labels.json | +| Windwos | %userprofile%\\.local\share\photils\override_labels.json | with a structure like: ```json diff --git a/cmake/Install.cmake b/cmake/Install.cmake index da2127a..126745b 100644 --- a/cmake/Install.cmake +++ b/cmake/Install.cmake @@ -11,9 +11,13 @@ if(APPLE) include(BundleUtilities) fixup_bundle(\"${APPS}\" \"\" \"${DIRS}\") " COMPONENT Runtime) - -# set(CPACK_GENERATOR "DRAGNDROP") -# include(CPack) +elseif(WIN32) + # include(InstallRequiredSystemLibraries) + install(TARGETS ${PROJECT_NAME} DESTINATION bin) + install(DIRECTORY ${RESOURCE_FOLDER}/share/photils/ DESTINATION share/photils) + set(CPACK_GENERATOR "ZIP") + set(CPACK_INCLUDE_TOPLEVEL_DIRECTORY OFF) + include(CPack) else() install(TARGETS ${PROJECT_NAME} DESTINATION bin) install(FILES appimage_resources/photils-cli.desktop DESTINATION share/applications/) diff --git a/conanfile.txt b/conanfile.txt index df614f0..38279ab 100644 --- a/conanfile.txt +++ b/conanfile.txt @@ -6,6 +6,8 @@ ghc-filesystem/1.5.12 [options] opencv:with_ffmpeg=False +opencv:with_ade=False + [generators] cmake diff --git a/include/version.h b/include/version.h index 40ffd8e..162da9f 100644 --- a/include/version.h +++ b/include/version.h @@ -1,6 +1,6 @@ #pragma once #define PROJECT_NAME "photils-cli" -#define PROJECT_VER "0.4.0" +#define PROJECT_VER "0.4.1" #define PROJECT_VER_MAJOR "0" #define PROJECT_VER_MINOR "4" -#define PTOJECT_VER_PATCH "0" +#define PTOJECT_VER_PATCH "1" diff --git a/src/helper.cpp b/src/helper.cpp index 17e1ecb..10cef9f 100644 --- a/src/helper.cpp +++ b/src/helper.cpp @@ -1,7 +1,12 @@ +#define NOMINMAX #include "helper.h" #include +#include #include #include +#ifdef _WIN32 +#include +#endif using namespace photils; @@ -13,6 +18,10 @@ fs::path photils::getExecutionPath() { if (_NSGetExecutablePath(buff, &size) == 0) { app_path.assign(buff).remove_filename(); } +#elif _WIN32 + TCHAR path[MAX_PATH]; + GetModuleFileName(NULL, path, MAX_PATH); + app_path.assign(path).remove_filename(); #else app_path = fs::read_symlink("/proc/self/exe").remove_filename(); #endif @@ -25,6 +34,9 @@ fs::path photils::getDataHome() { #if __APPLE__ data_home = fs::path(std::getenv("HOME")) / "Library" / "Application Support" / "photils"; +#elif _WIN32 + data_home = + fs::path(std::getenv("USERPROFILE")) / ".local" / "share" / "photils"; #else data_home = fs::path(std::getenv("HOME")) / ".local" / "share" / "photils"; #endif diff --git a/src/inference.cpp b/src/inference.cpp index 665bcb6..119d319 100644 --- a/src/inference.cpp +++ b/src/inference.cpp @@ -1,3 +1,4 @@ +#define NOMINMAX #include "inference.h" #include #include diff --git a/src/main.cpp b/src/main.cpp index 9f78a58..75de511 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,4 +1,3 @@ -#include #include #include #include diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index ef29f7d..9522002 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -9,6 +9,7 @@ set(gtest_force_shared_crt ON CACHE BOOL "" FORCE) FetchContent_MakeAvailable(googletest) enable_testing() +set(CMAKE_CXX_STANDARD 14) file(GLOB_RECURSE TEST_SRC ${PROJECT_SOURCE_DIR}/tests/*.cpp) @@ -23,11 +24,20 @@ add_executable( ${TEST_SRC} ) +set_target_properties( ${PROJECT_NAME}_test + PROPERTIES + ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/${CMAKE_BUILD_TYPE}/lib + LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/${CMAKE_BUILD_TYPE}/lib + RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}${CMAKE_BUILD_TYPE}//bin + RUNTIME_OUTPUT_DIRECTORY_DEBUG ${CMAKE_BINARY_DIR}/${CMAKE_BUILD_TYPE}/bin + RUNTIME_OUTPUT_DIRECTORY_RELEASE ${CMAKE_BINARY_DIR}/${CMAKE_BUILD_TYPE}/bin +) + target_include_directories(${PROJECT_NAME}_test PUBLIC ${PROJECT_SOURCE_DIR}/include) target_link_libraries( ${PROJECT_NAME}_test - ${CONAN_LIBS} ${EXTRA_LIBS} + ${CONAN_LIBS} gtest_main gtest ) diff --git a/tests/test_helper.cpp b/tests/test_helper.cpp index 46b591d..dd65712 100644 --- a/tests/test_helper.cpp +++ b/tests/test_helper.cpp @@ -21,7 +21,7 @@ TEST(Helper, centerCrop) { .parent_path() .parent_path(); auto testImgPath = path / "tests" / "data" / "may-kiron105mm-0012.jpg"; - auto img = cv::imread(testImgPath); + auto img = cv::imread(testImgPath.string()); auto sourceImg = img.clone(); photils::centerCrop(img, {128, 128}); diff --git a/tests/test_inference.cpp b/tests/test_inference.cpp index 1607f55..78c9236 100644 --- a/tests/test_inference.cpp +++ b/tests/test_inference.cpp @@ -18,7 +18,7 @@ TEST(Inference, getTags) { auto tags = instance.getTags("no_file", false); ASSERT_EQ(tags.size(), 0); - tags = instance.getTags(testImgPath, false); + tags = instance.getTags(testImgPath.string(), false); ASSERT_TRUE(tags.size() > 0); auto cmp = [](photils::Prediction p) { @@ -29,7 +29,6 @@ TEST(Inference, getTags) { } TEST(Inference, getTagsFromNEF) { - auto overrideLoc = photils::getDataHome() / "override_labels.json"; auto path = photils::getExecutionPath() .parent_path() .parent_path() @@ -38,7 +37,7 @@ TEST(Inference, getTagsFromNEF) { auto testImgPath = path / "tests" / "data" / "_DSC2555.NEF"; auto& instance = photils::Inference::getInstance(); - auto tags = instance.getTags(testImgPath, false); + auto tags = instance.getTags(testImgPath.string(), false); ASSERT_TRUE(tags.size() > 0); auto cmp = [](photils::Prediction p) { @@ -50,7 +49,7 @@ TEST(Inference, getTagsFromNEF) { TEST(Inference, labelOverride) { auto overrideLoc = photils::getDataHome() / "override_labels.json"; - std::ofstream out(overrideLoc); + std::ofstream out(overrideLoc, std::ios::trunc); out << std::string("{\"flower\":\"wtf\"}"); out.close(); @@ -63,7 +62,7 @@ TEST(Inference, labelOverride) { auto testImgPath = path / "tests" / "data" / "_DSC2555.NEF"; auto& instance = photils::Inference::getInstance(); - auto tags = instance.getTags(testImgPath, false); + auto tags = instance.getTags(testImgPath.string(), false); ASSERT_TRUE(tags.size() > 0); auto cmp = [](photils::Prediction p) { @@ -73,6 +72,6 @@ TEST(Inference, labelOverride) { ASSERT_TRUE(hasOverrideLabel); if (fs::exists(overrideLoc)) { - std::remove(overrideLoc.c_str()); + std::remove(overrideLoc.string().c_str()); } }