A screenshot capture-and-annotate app for Linux, built to work the same on GNOME, KDE Plasma, XFCE, MATE, Cinnamon and LXQt — on X11 and Wayland alike — and shipped as a single AppImage.
Take a shot, drop it on a gradient with padding and a soft shadow, point at things with arrows, scribble with the pen, blur out the parts nobody should see, grab the text straight out of the picture, and copy or save the result.
Two ways, depending on whether you would rather download one file or type one command. Both give you the same app, a menu entry and an icon.
First pipx itself, if you have not got it:
| Distribution | |
|---|---|
| Debian 12+, Ubuntu 23.04+, Mint, Zorin | sudo apt install pipx |
| Fedora | sudo dnf install pipx |
| Arch, Manjaro | sudo pacman -S python-pipx |
| openSUSE | sudo zypper install python3-pipx |
| older releases, or no root | python3 -m pip install --user pipx |
Then, once:
pipx ensurepathThat puts ~/.local/bin on your PATH, which is where both pipx and shotpad
end up — skip it and the install will look like it worked but leave
shotpad: command not found. Open a new terminal afterwards so the change
takes effect. Now Shotpad:
pipx install git+https://github.com/TuranIsmayilov/shotpad.git
shotpad --installshotpad --install adds the menu entry, icon and image-file associations;
shotpad --uninstall removes exactly those again.
Needs Python 3.10+. Qt (~100 MB) is downloaded on install. Use pipx rather than
pip — Debian 12+, Ubuntu 23.04+ and Fedora all refuse pip install into the
system Python, which is exactly the problem pipx exists to solve: it gives every
application its own virtualenv and links just the command into ~/.local/bin.
For machines without Python, or if you would rather not build anything. Download the latest from Releases, then:
chmod +x Shotpad-1.0.7-x86_64.AppImage
./Shotpad-1.0.7-x86_64.AppImage # run it
./Shotpad-1.0.7-x86_64.AppImage --install # menu entry and iconNothing else needed — it carries its own Python and Qt. It starts about 0.2 s slower than a pipx install, because the bundle has to mount itself first.
git clone https://github.com/TuranIsmayilov/shotpad.git
cd shotpad
python3 -m venv .venv && . .venv/bin/activate
pip install -e .
shotpadShotpad never checks for updates on its own and never phones home, so new
versions are something you pull when you want them. shotpad --version says
what you are on; Releases
says what is current.
Your preferences live in ~/.config/Shotpad/Shotpad.conf, outside the app, so
none of this touches them.
pipx upgrade shotpadThat re-pulls the git repository and rebuilds. If it reports nothing to do even though the release is newer — pip can decide a direct URL is already satisfied when the version number has not moved — force it:
pipx install --force git+https://github.com/TuranIsmayilov/shotpad.gitThe desktop entry points at pipx's stable ~/.local/bin/shotpad either way, so
there is nothing to re-register.
Download the new file from Releases, then:
chmod +x Shotpad-1.0.7-x86_64.AppImage
./Shotpad-1.0.7-x86_64.AppImage --install # re-point the menu entry
rm Shotpad-1.0.6-x86_64.AppImage # the old one, once you are happyRe-running --install matters here. The menu entry and any keyboard
shortcut hold the absolute path of the bundle you installed from, and the
version is in the filename — so a new download leaves them pointing at the old
file. --install rewrites them; a custom Print Screen binding you added
yourself has to be updated by hand.
To skip that dance entirely, keep the bundle at a fixed path and overwrite it:
mv ~/Downloads/Shotpad-1.1.0-x86_64.AppImage ~/.local/bin/shotpad.AppImageInstall once from there and every later update is just that one mv.
git pull
pip install -e . # only if the dependencies changedAn editable install already runs your working tree, so a git pull is usually
the whole update.
| Padding | 0–200 (default 12), scales with the image so it looks right at any resolution |
| Backgrounds | Linear / radial / conic gradients, solids, your own image, or fully transparent |
| Presets | 16 curated gradients and 16 solids, one click each |
| Corner radius | Rounded plate corners (default 9) |
| Shadow | Separate strength, softness and offset |
| Tilt | ±20° rotation, with the canvas growing to fit |
| Aspect ratio | Auto, 1:1, 4:3, 3:2, 16:9, 21:9, 9:16, 3:4 |
| Grain | Subtle film noise over the background |
| Inner border | A hairline between the screenshot and the background |
| Outer border | A mat around the screenshot — 8 presets led by a glass sheen that fades across the diagonal, sized as a share of the short edge |
| Tool | Key | Notes |
|---|---|---|
| Select / move | V |
Drag to move, grab a handle to resize, arrows to nudge |
| Pen | P |
Smoothed freehand |
| Highlighter | H |
Translucent, multiply-blended |
| Arrow | A |
Optional second arrowhead; Shift snaps to 15° |
| Line | L |
Solid or dashed |
| Rectangle | R |
Outline or filled, with its own corner radius |
| Ellipse | E |
Outline or filled |
| Text | T |
Any installed font, with a readable outline or a label plate |
| Numbered badge | N |
Auto-increments — for step-by-step guides |
| Redact | B |
Blur, pixelate or a solid block |
| Eraser | X |
Click an annotation to remove it, or drag a box to clear everything it covers |
| Crop | C |
Handles, rule-of-thirds guides, Enter to apply |
Plus rotate, flip, unlimited undo/redo, and export at 1×/1.5×/2×/3×.
Grab text (G) turns a screenshot back into text. Drag a box over an error
code, a licence key or a URL that only exists as pixels, and it is on your
clipboard.
| Languages | English, Turkish, Azerbaijani and Russian, bundled. The picker follows your system language rather than assuming English |
| More languages | Drop any .traineddata into ~/.local/share/shotpad/tessdata — no rebuild, no waiting for a release |
| Redactions hold | It reads the picture as it will be exported, so a blur or a black box is not quietly undone by the tool next to it in the rail |
| Small text | Enlarged before reading, by an amount measured from the image — without it, 1× interface text reads "Comer radius" for "Corner radius" |
| Offline | The recogniser is bundled and runs on your machine. Nothing is uploaded, and it works with no network at all |
Finding nothing leaves your clipboard alone; the status bar reports what was copied, and says so when the reading looks doubtful.
This is text recognition only — Shotpad's own interface is English.
The tool rail names every tool beside its icon. The ☰ button at the top of it collapses the rail to icons only, and it opens the way you last left it.
Preferences → General can make closing the window copy the finished image to the clipboard, for the common "grab it, mark it up, paste it into chat" loop. It is off by default: taking the clipboard is a side effect on something you own and did not ask about.
Annotations are stored in screenshot coordinates, so changing the padding, crop, aspect ratio or tilt never makes an arrow drift off the thing it points at. Redactions are baked into the screenshot pixels, not painted over the canvas — a blurred password stays blurred no matter how you re-frame the shot.
Shotpad probes the machine and walks an ordered list of backends until one produces pixels:
| Session | Order |
|---|---|
| Wayland | XDG portal → grim → the desktop's own tool → portal (interactive) |
| X11 | Qt's direct grab → the desktop's own tool → maim → scrot → import → portal |
spectacle (KDE), gnome-screenshot, xfce4-screenshooter and
mate-screenshot are each preferred on their own desktop when the earlier
options are unavailable. Menu → Capture diagnostics shows exactly what was
detected and what is being used.
Shotpad detects the desktop and reorders its backends to suit it. These are the ones it recognises by name:
| Desktop | Wayland | X11 | Status |
|---|---|---|---|
| GNOME | portal, then gnome-screenshot |
Qt grab, then gnome-screenshot |
tested |
| KDE Plasma | portal, then spectacle |
Qt grab, then spectacle |
tested |
| XFCE | portal | Qt grab, then xfce4-screenshooter |
tested |
| MATE | portal | Qt grab, then mate-screenshot |
tested |
| Cinnamon, LXQt | portal | Qt grab, then maim / scrot / import |
tested |
| Budgie, Deepin, Pantheon | portal | Qt grab, then maim / scrot / import |
recognised, untested |
| sway, Hyprland, i3, other wlroots | grim, then portal |
Qt grab, then maim / scrot / import |
recognised, untested |
"Recognised, untested" means Shotpad detects the desktop by name and picks the backend order shown, but that combination has not been run on real hardware — not that anything is known to be broken.
Recognition is not required either way. An unlisted desktop falls through the
same ordered list and works as long as one backend is present; on Wayland that
means a working xdg-desktop-portal, which every actively maintained compositor
ships.
Note that xfce4-screenshooter and mate-screenshot are X11-only paths: under
Wayland those desktops go through the portal, since neither tool can read the
framebuffer there.
Area selection is always Shotpad's own overlay, not the desktop's. Shotpad
grabs the whole screen first and lets you pick a region from that frozen copy,
so the selection experience — dimming, size readout, Shift to move, Ctrl
for a square, window snapping — is identical no matter which desktop you are
on. On X11 it also highlights whole windows as you move the pointer.
Shotpad draws its own title bar, with window controls in the Linux Mint Cinnamon (Mint-Y) style: monochrome symbolic glyphs, ordered minimise, maximise, close, with close in the top-right corner. A circular highlight follows the pointer and the close button tints red; the maximise glyph becomes a restore glyph while the window is maximised.
Drag the header to move the window, double-click it to maximise, and drag any edge to resize - all three go through the compositor, so they behave the same on X11 and Wayland. If your window manager handles frameless windows badly, Preferences → General can hand the title bar back to the desktop.
No Linux desktop lets an ordinary application steal the Print Screen key, so the supported route is to bind one yourself. Point the binding at:
shotpad --area
(or the full path to the AppImage). --install prints the exact command to
use, plus where to put it:
- GNOME — Settings → Keyboard → View and Customise Shortcuts → Custom Shortcuts
- KDE — System Settings → Shortcuts → Add → Command or Script
- XFCE — Settings → Keyboard → Application Shortcuts
- MATE — Control Center → Keyboard Shortcuts → Add
On GNOME 46 and earlier — which is what Ubuntu 24.04 LTS and Zorin 18 ship —
pressing the shortcut while no other window is open can leave the capture
without its selection overlay: the Shotpad window appears for a moment, vanishes,
and nothing further happens. The process is still running, so pkill -f shotpad
clears it.
With any window on screen it behaves normally, which is the case nearly all the time — a screenshot usually has something to capture.
Newer GNOME is unaffected: tested on Ubuntu 26.04 and current Fedora, where the same binding works on a completely empty desktop. GNOME 47 and 48 are untested.
shotpad open the editor
shotpad photo.png open an image
shotpad --area capture, then pick a region
shotpad --screen capture the whole desktop
shotpad --window capture, then pick a window
shotpad --clipboard start from the clipboard image
shotpad --desktop-ui use GNOME's / KDE's own picker instead
shotpad --area --delay 5 wait 5 seconds first
shotpad --area --no-edit save straight to the screenshots folder, no editor
shotpad --area --no-edit --raw --out shot.png no styling, exact path
shotpad --area --no-edit --copy also copy to the clipboard
shotpad --list-backends what capture methods this machine has
shotpad --install add a desktop entry for the current user
Ctrl+Shift+A / F / W |
Capture area / screen / window |
Ctrl+O Ctrl+V |
Open a file, paste from clipboard |
Ctrl+S Ctrl+Shift+S |
Save, Save as |
Ctrl+C |
Copy the finished image |
Ctrl+Z Ctrl+Shift+Z |
Undo, redo |
Ctrl+0 Ctrl± |
Fit, zoom |
Delete |
Delete the selected annotation |
Ctrl+Shift+Delete |
Clear all annotations |
Space-drag, middle-drag |
Pan |
Alt-drag |
Drag the finished image into another app |
V P H A L R E T N B X C |
Pick a tool |
Inside the region overlay: drag to select, click for the window or whole
screen, Shift to move the selection, Ctrl for a square, Enter for the
current monitor, Esc to cancel.
Copy-on-close is off by default — taking over the clipboard is a side effect on something you own and did not ask about. Turn it on in Preferences → General ("Copy the finished image to the clipboard when the window closes").
Copying an image is not as simple as it looks. On both X11 and Wayland the clipboard contents stay inside the application that copied them and are transferred lazily, at paste time. An application that copies and then exits therefore leaves an empty clipboard - unless a clipboard manager grabbed the data first, and stock GNOME ships none.
So "copy on close" cannot just call setImage() and quit. Shotpad does what
wl-copy does: it hands the image to a small background copy of itself that
keeps serving it. That helper replaces any previous one, so only ever one
exists, and it exits when another application takes the clipboard (detectable
on X11) or after fifteen minutes, whichever comes first. It costs about 90 MB
of RAM while resident.
If you have a clipboard manager running (KDE's Klipper, GPaste, CopyQ, …) the handover happens instantly and the helper is redundant.
Under Wayland, no application can read the screen directly — that is the security model, not a limitation of Shotpad. Capture goes through the XDG desktop portal, and GNOME and KDE ask for permission the first time. Allow it once and subsequent captures are silent.
If a capture seems to hang, look for a system dialog waiting for an answer. Shotpad gives up after 90 seconds and falls through to the next backend.
If your compositor supports the wlroots screencopy protocol, installing grim
lets Shotpad capture through it directly, with no prompt involved.
./packaging/build-appimage.sh # -> dist/Shotpad-1.0.7-x86_64.AppImage
./packaging/build-appimage.sh --arch aarch64
./packaging/build-appimage.sh --no-prune # keep all of Qt, for debugging
./packaging/build-appimage.sh --no-ocr # skip the text recogniserThe script downloads a relocatable CPython from
python-build-standalone
(built against an old glibc, so the result runs on older distributions too),
installs PySide6-Essentials into it, prunes the Qt modules Shotpad does not
use, verifies the bundle still imports, and packs it with appimagetool.
It also bundles the handful of libxcb-* libraries (notably libxcb-cursor,
a hard requirement of Qt 6.5+'s X11 plugin that Debian and Ubuntu leave out of
a default install) and verifies that both the xcb and wayland platform
plugins resolve every library they need - a missing one there would otherwise
only surface on a user's machine as "could not load the Qt platform plugin".
packaging/build-tesseract.sh compiles Tesseract into a single static binary,
cached in build/cache so it is built once. It needs cmake and a C++
compiler; without them the AppImage still builds, just without Grab text, and
the tool reports itself unavailable rather than failing.
It is built from source rather than taken from a distribution because Debian's
libtesseract lists libcurl and libarchive as hard DT_NEEDED entries, and
following that closure drags in OpenSSL, Kerberos and libxml2 — roughly 23 MB
and a standing CVE obligation, for URL and archive input a screenshot tool never
reaches. Configured without them, and with a Leptonica stripped of every
image-format backend, it has no dynamic dependencies at all. Leptonica keeps its
PNM reader and Qt writes PPM, which is how the two talk.
The static link is what protects the AppImage's reach: built dynamically on a
current distribution it demands GLIBC 2.38, where the bundled Qt asks only for
2.28 — which would quietly drop Debian 12, Ubuntu 22.04 and RHEL 9. The builder
refuses to emit a binary carrying any NEEDED entry, so a link that stops being
static fails the build instead of shipping.
Result: about 65 MB (55 MB with --no-ocr), with no dependency on anything
installed on the host.
pip install -e ".[dev]"
QT_QPA_PLATFORM=offscreen python -m pytest tests -q
python -m pyflakes shotpadshotpad/
model.py document, framing and background settings, undo
annotations.py annotation objects (geometry, hit-testing, drawing)
render.py the one renderer used by both the preview and the export
util.py blur, pixelate, rounded paths
icons.py the built-in vector icon set
theme.py palette and stylesheet
settings.py preferences
capture/
backends.py desktop detection and the backend chain
portal.py XDG desktop portal over QtDBus
windows.py X11 window enumeration for window snapping
ui/
window.py main window, capture flow, export
canvas.py the editing canvas
selector.py the fullscreen region overlay
sidebar.py the inspector
home.py start screen
widgets.py shared controls
The preview and the exported file go through the same render_document(), so
what you see really is what you get; the editor just calls it at a smaller
scale.
A GTK4/libadwaita app looks right on GNOME and out of place everywhere else. Shotpad has to look and behave the same on four desktops, so it uses Qt with the Fusion style, its own palette and its own icon set, and it does not read the system theme beyond light/dark. That avoids a Qt app inheriting Breeze on KDE, some GTK bridge on XFCE and nothing coherent on MATE. It also keeps the AppImage self-contained: bundling GTK4 plus libadwaita plus GObject introspection portably is considerably harder than bundling Qt.
GPL-3.0-or-later — see LICENSE. Copyright © 2026 Turan Ismayilov.
You may use, study, share and modify Shotpad. If you distribute a modified version, you must publish your source under the same licence, so Shotpad and everything built from it stay free software. It comes with no warranty.
The GPL covers the code. It does not give away the name "Shotpad" or the Shotpad icon, which remain the property of Turan Ismayilov and are not licensed for reuse.
You are welcome to fork, modify and redistribute the code — but a modified or repackaged build must not be called "Shotpad" and must not use the Shotpad icon. Please rename it. This is the same approach Firefox and VLC take, and it exists so that anything carrying the Shotpad name is something I actually released.
Shotpad uses Qt through PySide6, which is licensed under the LGPL-3.0, and a CPython interpreter from python-build-standalone.
The AppImage bundles both. The full licence text of everything inside it is at
usr/share/licenses/ within the bundle — read it without installing anything:
./Shotpad-1.0.7-x86_64.AppImage --appimage-extract 'usr/share/licenses/*'Qt is bundled unmodified and dynamically linked, so you can replace it with
your own build of the same version; usr/share/licenses/README.txt explains
how. Qt's source is available from
the Qt project.
