ImgEdtr: как я пишу нативный редактор скриншотов на Rust для GNOME
Мне нужен был простой редактор: нажать горячую клавишу, выбрать область экрана, добавить стрелку или текст, обрезать лишнее и сразу скопировать картинку. Так появился ImgEdtr — нативный редактор скриншотов на Rust, GTK4 и libadwaita. Он уже открывает PNG, JPEG и WebP, рисует аннотации и копирует результат в буфер; сохранение в файл я ещё доделываю.

По возможностям мне нравится Gradia. Она написана на Python и у меня иногда запускается медленнее, чем хотелось бы. Поэтому я решил сделать похожий инструмент на Rust: нажал горячую клавишу — и окно появилось без заметной паузы.
Rust я выбрал именно ради этого эксперимента. Мне хотелось собрать самостоятельный нативный инструмент под GNOME и заодно проверить, насколько быстро будет открываться обычное настольное приложение с холстом, текстом, буфером обмена, D-Bus и работой с файлами. Когда будет готова первая нормальная версия, я запущу ImgEdtr и Gradia на одной машине и сравню время. Пока таких замеров нет.
1. Сначала я выкинул всё лишнее
У редактора изображений очень легко появляется бесконечный список функций: слои, фильтры, OCR, облако, плагины и собственный формат проекта. Через неделю небольшой инструмент уже мысленно конкурирует с GIMP, хотя всё ещё не умеет нормально сохранить один скриншот. Поэтому для первой версии я оставил один документ на окно, три формата — PNG, JPEG и WebP — и редактируемые аннотации только в пределах текущего сеанса.
Пока я делаю его под свою систему: Ubuntu 26.04.1 LTS, GNOME 50 и Wayland. Хочу обычный .deb, который поставил и забыл, без фонового сервиса. Для начала мне достаточно одного: снять -> добавить стрелку и текст -> обрезать -> скопировать или сохранить.
2. Проект разделён на три части
Я сразу разделил Cargo workspace на три части. Так проще следить, чтобы стрелка не съезжала в сторону, когда одна и та же картинка показывается на холсте, копируется в буфер и сохраняется в PNG.
| Часть | За что отвечает |
|---|---|
core |
Документ, геометрия, аннотации, преобразования и Undo/Redo без зависимости от GTK |
render |
Декодирование и единый рендер для холста, буфера и будущего экспорта |
app |
GTK4/libadwaita, ввод, окна, файлы, D-Bus и интеграция с GNOME |
Исходный растр хранится отдельно и не копируется целиком при каждом движении стрелки. История запоминает команды и изменения объектов, ограничена 100 шагами, а одно перетаскивание считается одной командой. Поэтому движение на десять пикселей не превращается в десять отдельных нажатий Undo.
3. Прототип уже открывает изображения четырьмя способами
PNG, JPEG и WebP можно открыть через диалог, из командной строки, перетаскиванием в окно или вставкой из буфера. Картинка загружается в фоне, чтобы окно не зависало. JPEG сразу поворачивается по EXIF, прозрачность не теряется, а встроенные RGB- и Gray-профили приводятся к sRGB.
На холсте уже работают текст, стрелка, линия, прямоугольник, эллипс, карандаш, маркер, нумерация шагов, пикселизация и непрозрачное закрытие области. Объекты можно выделять, перемещать, менять их размер и стиль; многострочный текст — открывать для повторного редактирования. Есть Fit, масштаб 100%, произвольное масштабирование, перемещение холста, обрезка, поворот на 90 градусов, отражение, изменение размера в пикселях и Undo/Redo для аннотаций и преобразований.


На первом скриншоте ещё почти пустое окно. На втором уже открыта картинка, работает масштаб и можно двигать аннотации поверх изображения.
Самая неприятная часть скрывается под привычной кнопкой поворота. Обрезка, изменение размера и поворот меняют не только растр, но и координаты всех аннотаций. Если стрелка указывала на кнопку до поворота, после него она должна продолжить указывать на ту же кнопку — во всех четырёх системах координат: исходника, документа, холста и итогового рендера.
4. Захват экрана работает через системный Screenshot portal
ImgEdtr не рисует собственную рамку поверх рабочего стола и не требует расширения GNOME Shell. Кнопка камеры и команда img-edtr --screenshot обращаются через D-Bus к системному Screenshot portal. GNOME показывает привычный выбор области, окна или экрана, а полученный файл открывается в новом документе.
img-edtr --screenshot
У Screenshot portal несколько версий: интерактивный выбор появился во второй, а параметр target — в третьей. ImgEdtr сначала спрашивает версию портала и не посылает ему незнакомые парметры. Мне так ещё и не приходится самому рисовать рамку захвата и воевать с Wayland.
Команду можно вручную повесить на любую свободную горячую клавишу GNOME. В настройки пользователя ImgEdtr не лезет.
5. .deb уже собирается, но отдавать его кому-то рано
В пакете уже есть иконка, .desktop-файл и ассоциации для PNG, JPEG и WebP. После установки ImgEdtr должен появиться в меню и в Open With, но не будет назначать себя редактором по умолчанию.
В буфер уже копируется готовая картинка со всеми аннотациями. А вот кнопки «Сохранить» пока нет.
Ещё надо проверить захват экрана, несколько мониторов, дробный масштаб и что происходит с буфером после закрытия программы. Поэтому 0.1.0 пока просто номер в Cargo.toml, а не версия, которую я готов кому-то отдать.
6. Тесты не дают вайбкодингу сломать уже работающие вещи
Когда приложение быстро растёт вместе с ИИ-агентом, новая функция легко ломает то, что ещё вчера работало. Поэтому в ImgEdtr есть автотесты для Undo/Redo, обрезки, поворота и преобразования координат. Они ловят не кривую кнопку, а неприятные поломки: пропавшее состояние, уехавшую после поворота стрелку или рамку выделения, которая вдруг попала в готовую картинку.
С тестами я могу смелее просить агента переделать геометрию или историю Undo: если что-то старое развалилось, это сразу видно. Но портал, буфер обмена, несколько экранов и дробный масштаб всё равно придётся проверять руками в GNOME.
7. Теперь надо доделать сохранение и пройти весь путь руками
Сейчас я доделываю сохранение файлов. PNG должен сохранять прозрачность, JPEG — подставлять белый фон. И всё это не должно подвесить окно или оставить после ошибки битый файл.
горячая клавиша
-> системный захват
-> стрелка и текст
-> обрезка
-> сохранение
-> копирование в другое приложение
Когда сохранение заработает, я пройду весь путь от горячей клавиши до готовой картинки. Потом уже сравню скорость запуска и память с Gradia на одной машине.
Если эта версия не развалится в реальной работе, потом добавлю яркость, контраст, насыщенность, гистограмму и RGB-кривые. Главное, чтобы эти настройки не перекрашивали стрелки и текст.
Мне не нужен второй GIMP
Мне не нужны слои, плагины и ещё сотня функций. Мне нужно быстро снять картинку, обвести кнопку, добавить стрелку и отправить результат. Поэтому я взял системный захват экрана и отложил цветокоррекцию, пока не заработает весь этот короткий путь.
Меня особенно радует, что с Codex или Claude Code за пару вечеров можно собрать именно ту программу, которой мне не хватало. Раньше я бы искал ближайшую готовую программу и привыкал к её особенностям. Теперь проще объяснить агенту, что мне нужно, и собрать своё. Агенты пишут скучную обвязку, роются в API и помогают с тестами. А я решаю, что вообще должно получиться, и проверяю результат.
Мне нравятся такие маленькие программы. Меня раздражало, что ради одной стрелки нужно открывать большой редактор, вот я и делаю для этого свою кнопку. Код ImgEdtr пока лежит в приватном репозитории. Сначала я доделаю сохранение и пользуюсь им сам, а потом уже открою репозиторий.