From d20f856896740587e33a8aaefc5548792be71cc4 Mon Sep 17 00:00:00 2001 From: BurntRanch Date: Fri, 12 Jun 2026 17:33:31 +0300 Subject: [PATCH 01/13] cmake: install oshot.desktop --- CMakeLists.txt | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 0b63bd9..51f0c68 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -468,3 +468,9 @@ install( DESTINATION share/licenses/${PROJECT_NAME} COMPONENT documentation ) + +install( + FILES oshot.desktop + DESTINATION share/applications + COMPONENT documentation +) From c7ddb0dd09e242423d11aea3ea270236b6c5469f Mon Sep 17 00:00:00 2001 From: BurntRanch Date: Fri, 12 Jun 2026 17:37:49 +0300 Subject: [PATCH 02/13] config: use TESSDATA_PREFIX for ocr_path by default and remove the ocr-path from the config so that changes to the env var will take place --- include/config.hpp | 8 +++++--- src/config.cpp | 7 ++++++- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/include/config.hpp b/include/config.hpp index b605f91..529f2f3 100644 --- a/include/config.hpp +++ b/include/config.hpp @@ -1,6 +1,7 @@ #ifndef _CONFIG_HPP_ #define _CONFIG_HPP_ +#include #include #include #include @@ -46,7 +47,7 @@ class Config // just for out-of-box experience sake, let's use the relative // ./models directory for the OCR models. #ifdef __linux__ - std::string ocr_path = "/usr/share/tessdata/"; + std::string ocr_path = getenv("TESSDATA_PREFIX"); #else std::string ocr_path = "./models"; #endif @@ -289,8 +290,9 @@ void apply_imgui_theme(); // default config inline constexpr std::string_view AUTOCONFIG = R"#([default] -# Default Path to where we'll use all the '.traineddata' models. -ocr-path = "{}" +# Path to where we'll use all the '.traineddata' models. +# Takes from the TESSDATA_PREFIX environment variable by default, or `/usr/share/tessdata` on the lack thereof. +# ocr-path = "/usr/share/tessdata" # Default OCR model. ocr-model = "{}" diff --git a/src/config.cpp b/src/config.cpp index c2a7f40..1d62bfe 100644 --- a/src/config.cpp +++ b/src/config.cpp @@ -20,6 +20,12 @@ Config::Config(const fs::path& configFile, const fs::path& configDir) fs::create_directories(configDir / "models"); } +#ifdef __linux__ + // on Linux, if ocr_path isn't defined, set it to /usr/share/tessdata. + if (File.ocr_path.empty()) + File.ocr_path = "/usr/share/tessdata"; +#endif + if (!fs::exists(configFile)) { warn("Config file {} not found, generating new one", configFile.string()); @@ -156,7 +162,6 @@ void Config::GenerateConfig(const std::string& filename, const bool force) } f.print(AUTOCONFIG, - File.ocr_path, File.ocr_model, File.ocr_get_repo, File.delay, From c37320b713101ab4d08019b0695ce4b3a8cf1076 Mon Sep 17 00:00:00 2001 From: BurntRanch Date: Fri, 12 Jun 2026 17:39:11 +0300 Subject: [PATCH 03/13] feat: Nix flakes --- flake.lock | 27 +++++++++++++++++++++++++++ flake.nix | 30 ++++++++++++++++++++++++++++++ 2 files changed, 57 insertions(+) create mode 100644 flake.lock create mode 100644 flake.nix diff --git a/flake.lock b/flake.lock new file mode 100644 index 0000000..ed20e51 --- /dev/null +++ b/flake.lock @@ -0,0 +1,27 @@ +{ + "nodes": { + "nixpkgs": { + "locked": { + "lastModified": 1781074563, + "narHash": "sha256-md8WlXOlfnIeHeOScMTTHFyf2d6iaTwPl2apR5EQ3P4=", + "owner": "nixos", + "repo": "nixpkgs", + "rev": "9ae611a455b90cf061d8f332b977e387bda8e1ca", + "type": "github" + }, + "original": { + "owner": "nixos", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "root": { + "inputs": { + "nixpkgs": "nixpkgs" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/flake.nix b/flake.nix new file mode 100644 index 0000000..d3b8ad1 --- /dev/null +++ b/flake.nix @@ -0,0 +1,30 @@ +{ + description = "Nix flake for oshot; a simple and lightweight tool for extracting text from a screenshot/image (on the fly)"; + + inputs = { + nixpkgs.url = "github:nixos/nixpkgs?ref=nixos-unstable"; + }; + + outputs = { self, nixpkgs }: { + packages.x86_64-linux.oshot = + with import nixpkgs { system = "x86_64-linux"; }; + stdenv.mkDerivation { + name = "oshot"; + src = self; + nativeBuildInputs = [ cmake gnumake pkg-config git ]; + buildInputs = [ glfw3 zenity leptonica libx11.dev tesseract zbar.dev libappindicator-gtk3.dev dbus.dev systemd.dev libsysprof-capture pcre2.dev libxdmcp.dev libuuid.dev libselinux.dev libsepol.dev libthai.dev libdatrie.dev libdeflate lerc.dev xz.dev zstd.dev libwebp libxkbcommon.dev libepoxy.dev libxtst giflib ]; + configurePhase = '' + cmake -DCMAKE_BUILD_PREFIX=/usr -DDEBUG=0 -G "Unix Makefiles" -B build -S . + ''; + buildPhase = '' + cmake --build build -j$(nproc) + ''; + installPhase = '' + install -Dm755 build/oshot $out/bin/oshot + install -Dm644 oshot.desktop $out/share/applications/oshot.desktop + install -Dm644 LICENSE $out/share/licenses/oshot/LICENSE + ''; + }; + packages.x86_64-linux.default = self.packages.x86_64-linux.oshot; + }; +} From 9f93a4b9d48ef2290583aeee3dd7f07f961fcc31 Mon Sep 17 00:00:00 2001 From: BurntRanch Date: Fri, 12 Jun 2026 17:39:21 +0300 Subject: [PATCH 04/13] readme: include NixOS instructions --- README.md | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/README.md b/README.md index 91caea4..e0c2798 100644 --- a/README.md +++ b/README.md @@ -74,6 +74,31 @@ If when starting oshot, it starts to flick a screen black (or it won't launch), If still errors, please open an [Issue](https://github.com/Toni500github/oshot/issues) and take a screenshot/paste the text of the error appearing in the console when executing oshot +### NixOS +On NixOS, TESSDATA_PREFIX will need to be set for oshot to find the languages. +You have two ways to do this, depending on how you installed tesseract. + +If you installed tesseract in `environment.systemPackages`, set the following variable: +```nix +environment.sessionVariables = { + # Change tesseract to tesseract5 if that's the package you used. + "TESSDATA_PREFIX" = "${pkgs.tesseract}/share/tessdata"; +}; +``` + +If you installed tesseract in `users.users..packages`, you could use the above method, but it's better you use home-manager. +If you have home-manager, add this in your home.nix: +```nix +systemd.user.sessionVariables = { + # Change tesseract to tesseract5 if that's the package you used. + "TESSDATA_PREFIX" = "${pkgs.tesseract}/share/tessdata"; +}; +``` + +> **__Notice:__** If you're not using systemd, the home-manager solution won't work. We assume you'll be able to find a replacement yourself if you're not using systemd. + +If this doesn't work, while `echo $TESSDATA_PREFIX` returns a valid result, check your config file. + ## Usage https://github.com/user-attachments/assets/8367490a-f7b0-4320-86e9-8ef8764a56b5 From f1165bfe2859be097f9c37c248e809e3a8ca50aa Mon Sep 17 00:00:00 2001 From: BurntRanch Date: Fri, 12 Jun 2026 17:56:15 +0300 Subject: [PATCH 05/13] config: edit ocr-path comment --- include/config.hpp | 1 - 1 file changed, 1 deletion(-) diff --git a/include/config.hpp b/include/config.hpp index 529f2f3..1ed3795 100644 --- a/include/config.hpp +++ b/include/config.hpp @@ -291,7 +291,6 @@ void apply_imgui_theme(); // default config inline constexpr std::string_view AUTOCONFIG = R"#([default] # Path to where we'll use all the '.traineddata' models. -# Takes from the TESSDATA_PREFIX environment variable by default, or `/usr/share/tessdata` on the lack thereof. # ocr-path = "/usr/share/tessdata" # Default OCR model. From fdb82ef43e6a8fd407de895b1630e307b5b27473 Mon Sep 17 00:00:00 2001 From: BurntRanch Date: Fri, 12 Jun 2026 17:56:15 +0300 Subject: [PATCH 06/13] config: edit ocr-path comment --- include/config.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/config.hpp b/include/config.hpp index 1ed3795..24ec905 100644 --- a/include/config.hpp +++ b/include/config.hpp @@ -291,7 +291,7 @@ void apply_imgui_theme(); // default config inline constexpr std::string_view AUTOCONFIG = R"#([default] # Path to where we'll use all the '.traineddata' models. -# ocr-path = "/usr/share/tessdata" +# ocr-path = "~/.config/oshot/models" # Default OCR model. ocr-model = "{}" From f18e2ed5b8c0ee5d7db064914f6daf50226aeaca Mon Sep 17 00:00:00 2001 From: BurntRanch Date: Fri, 12 Jun 2026 19:43:58 +0300 Subject: [PATCH 07/13] config: change behavior of ocr-path $TESSDATA_PREFIX now supersedes ocr-path --- include/config.hpp | 3 ++- src/config.cpp | 13 +++++++------ 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/include/config.hpp b/include/config.hpp index 24ec905..667f7de 100644 --- a/include/config.hpp +++ b/include/config.hpp @@ -291,7 +291,8 @@ void apply_imgui_theme(); // default config inline constexpr std::string_view AUTOCONFIG = R"#([default] # Path to where we'll use all the '.traineddata' models. -# ocr-path = "~/.config/oshot/models" +# The TESSDATA_PREFIX environment variable supersedes this. +ocr-path = "~/.config/oshot/models" # Default OCR model. ocr-model = "{}" diff --git a/src/config.cpp b/src/config.cpp index 1d62bfe..05cd7a4 100644 --- a/src/config.cpp +++ b/src/config.cpp @@ -20,12 +20,6 @@ Config::Config(const fs::path& configFile, const fs::path& configDir) fs::create_directories(configDir / "models"); } -#ifdef __linux__ - // on Linux, if ocr_path isn't defined, set it to /usr/share/tessdata. - if (File.ocr_path.empty()) - File.ocr_path = "/usr/share/tessdata"; -#endif - if (!fs::exists(configFile)) { warn("Config file {} not found, generating new one", configFile.string()); @@ -67,6 +61,13 @@ void Config::LoadConfigFile(const std::string& filename) File.allow_out_edit = GetValue("default.allow-edit-ocr", false); // deprecated File.allow_out_edit = GetValue("default.allow-text-edit", File.allow_out_edit); + +#ifdef __linux__ + const char *tessdata_prefix; + if ((tessdata_prefix = getenv("TESSDATA_PREFIX"))) { + File.ocr_path = tessdata_prefix; + } +#endif } void Config::LoadThemeFile(const std::string& filename) From 6d5ef3dad8fbfeef8019fabd0b7532643e37fd85 Mon Sep 17 00:00:00 2001 From: BurntRanch Date: Fri, 12 Jun 2026 20:12:19 +0300 Subject: [PATCH 08/13] config: change default ocr-path --- include/config.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/config.hpp b/include/config.hpp index 667f7de..40e2394 100644 --- a/include/config.hpp +++ b/include/config.hpp @@ -292,7 +292,7 @@ void apply_imgui_theme(); inline constexpr std::string_view AUTOCONFIG = R"#([default] # Path to where we'll use all the '.traineddata' models. # The TESSDATA_PREFIX environment variable supersedes this. -ocr-path = "~/.config/oshot/models" +ocr-path = "/usr/share/tessdata" # Default OCR model. ocr-model = "{}" From 8ceae4fd0df8ddbba7dd3b9790455c0488bf3616 Mon Sep 17 00:00:00 2001 From: BurntRanch Date: Fri, 12 Jun 2026 20:12:38 +0300 Subject: [PATCH 09/13] config: remove linux guard for TESSDATA_PREFIX check --- src/config.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/config.cpp b/src/config.cpp index 05cd7a4..679a418 100644 --- a/src/config.cpp +++ b/src/config.cpp @@ -62,12 +62,10 @@ void Config::LoadConfigFile(const std::string& filename) File.allow_out_edit = GetValue("default.allow-edit-ocr", false); // deprecated File.allow_out_edit = GetValue("default.allow-text-edit", File.allow_out_edit); -#ifdef __linux__ const char *tessdata_prefix; if ((tessdata_prefix = getenv("TESSDATA_PREFIX"))) { File.ocr_path = tessdata_prefix; } -#endif } void Config::LoadThemeFile(const std::string& filename) From 24de869eb1b65cf381b28d91abfd8c595f07e7bd Mon Sep 17 00:00:00 2001 From: BurntRanch Date: Fri, 12 Jun 2026 20:25:04 +0300 Subject: [PATCH 10/13] config: remove getenv from config_file_t initialize --- include/config.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/config.hpp b/include/config.hpp index 40e2394..df9d519 100644 --- a/include/config.hpp +++ b/include/config.hpp @@ -47,7 +47,7 @@ class Config // just for out-of-box experience sake, let's use the relative // ./models directory for the OCR models. #ifdef __linux__ - std::string ocr_path = getenv("TESSDATA_PREFIX"); + std::string ocr_path = "/usr/share/tessdata"; #else std::string ocr_path = "./models"; #endif From 039e8d497fea8463c4a40b03cd39c674110a9102 Mon Sep 17 00:00:00 2001 From: BurntRanch Date: Fri, 12 Jun 2026 20:31:32 +0300 Subject: [PATCH 11/13] chore: clang-format --- include/config.hpp | 2 +- src/config.cpp | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/include/config.hpp b/include/config.hpp index df9d519..b293d6d 100644 --- a/include/config.hpp +++ b/include/config.hpp @@ -292,7 +292,7 @@ void apply_imgui_theme(); inline constexpr std::string_view AUTOCONFIG = R"#([default] # Path to where we'll use all the '.traineddata' models. # The TESSDATA_PREFIX environment variable supersedes this. -ocr-path = "/usr/share/tessdata" +ocr-path = {} # Default OCR model. ocr-model = "{}" diff --git a/src/config.cpp b/src/config.cpp index 679a418..85841db 100644 --- a/src/config.cpp +++ b/src/config.cpp @@ -62,8 +62,9 @@ void Config::LoadConfigFile(const std::string& filename) File.allow_out_edit = GetValue("default.allow-edit-ocr", false); // deprecated File.allow_out_edit = GetValue("default.allow-text-edit", File.allow_out_edit); - const char *tessdata_prefix; - if ((tessdata_prefix = getenv("TESSDATA_PREFIX"))) { + const char* tessdata_prefix; + if ((tessdata_prefix = getenv("TESSDATA_PREFIX"))) + { File.ocr_path = tessdata_prefix; } } @@ -161,6 +162,7 @@ void Config::GenerateConfig(const std::string& filename, const bool force) } f.print(AUTOCONFIG, + File.ocr_path, File.ocr_model, File.ocr_get_repo, File.delay, From 01c9e93affbf9d1929e3dd16d09d79701a7ab093 Mon Sep 17 00:00:00 2001 From: BurntRanch Date: Fri, 12 Jun 2026 20:34:44 +0300 Subject: [PATCH 12/13] revert: most changes in config.hpp --- include/config.hpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/include/config.hpp b/include/config.hpp index b293d6d..e270123 100644 --- a/include/config.hpp +++ b/include/config.hpp @@ -1,7 +1,6 @@ #ifndef _CONFIG_HPP_ #define _CONFIG_HPP_ -#include #include #include #include @@ -47,7 +46,7 @@ class Config // just for out-of-box experience sake, let's use the relative // ./models directory for the OCR models. #ifdef __linux__ - std::string ocr_path = "/usr/share/tessdata"; + std::string ocr_path = "/usr/share/tessdata/"; #else std::string ocr_path = "./models"; #endif @@ -290,9 +289,9 @@ void apply_imgui_theme(); // default config inline constexpr std::string_view AUTOCONFIG = R"#([default] -# Path to where we'll use all the '.traineddata' models. +# Default Path to where we'll use all the '.traineddata' models. # The TESSDATA_PREFIX environment variable supersedes this. -ocr-path = {} +ocr-path = "{}" # Default OCR model. ocr-model = "{}" From 623713ea26c4b5866d7ce8ba7c0f36ad772080e9 Mon Sep 17 00:00:00 2001 From: BurntRanch Date: Fri, 12 Jun 2026 20:39:03 +0300 Subject: [PATCH 13/13] flake: remove pointless zenity dependency --- flake.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/flake.nix b/flake.nix index d3b8ad1..55f9c65 100644 --- a/flake.nix +++ b/flake.nix @@ -12,7 +12,7 @@ name = "oshot"; src = self; nativeBuildInputs = [ cmake gnumake pkg-config git ]; - buildInputs = [ glfw3 zenity leptonica libx11.dev tesseract zbar.dev libappindicator-gtk3.dev dbus.dev systemd.dev libsysprof-capture pcre2.dev libxdmcp.dev libuuid.dev libselinux.dev libsepol.dev libthai.dev libdatrie.dev libdeflate lerc.dev xz.dev zstd.dev libwebp libxkbcommon.dev libepoxy.dev libxtst giflib ]; + buildInputs = [ glfw3 leptonica libx11.dev tesseract zbar.dev libappindicator-gtk3.dev dbus.dev systemd.dev libsysprof-capture pcre2.dev libxdmcp.dev libuuid.dev libselinux.dev libsepol.dev libthai.dev libdatrie.dev libdeflate lerc.dev xz.dev zstd.dev libwebp libxkbcommon.dev libepoxy.dev libxtst giflib ]; configurePhase = '' cmake -DCMAKE_BUILD_PREFIX=/usr -DDEBUG=0 -G "Unix Makefiles" -B build -S . '';