Skip to content

Commit ecec43d

Browse files
committed
various: define builtin options and key bindings for images
This makes mpv usable as an image viewer out of the box, as it is currently hard to setup. Using mpv as an image viewer has several advantages, the biggest one is that it's the best program at browsing directories of mixed videos and images. This adds a builtin-image profile that users can extend in mpv.conf. It doesn't restore and reapply the options on each image change, because that is slow for certain options (e.g. --d3d11-flip=no restarts the VO), and causes visible flicker when options like gamma are unapplied before changing image and reapplied on the next image. But it still restores the previous options after switching to a video or audio file. Default image key bindings are defined in the image input section which gets enabled with the profile. sxiv is their main inspiration. Closes #7983, closes #12496.
1 parent fe26680 commit ecec43d

File tree

10 files changed

+276
-6
lines changed

10 files changed

+276
-6
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
add `--apply-image-profile` option

DOCS/man/mpv.rst

+148
Original file line numberDiff line numberDiff line change
@@ -399,6 +399,83 @@ To use this feature, you need to fill the ``menu-data`` property with menu
399399
definition data, and add a keybinding to run the ``context-menu`` command,
400400
which can be done with a user script.
401401

402+
Image Bindings
403+
--------------
404+
405+
When viewing images, the following key bindings optimized for image viewing are
406+
added. Key bindings not listed here, or those configured by the user in
407+
``input.conf``, keep behaving like with non-image files.
408+
409+
LEFT, RIGHT, UP, DOWN, h, j, k, l
410+
Pan the image when it is larger than the window.
411+
412+
Shift+LEFT, Shift+RIGHT, Shift+UP, Shift+DOWN, H, J, K, L
413+
Slowly pan the image when it is larger than the window.
414+
415+
Ctrl+LEFT, Ctrl+RIGHT, Ctrl+UP, Ctrl+DOWN, Ctrl+h, Ctrl+j, Ctrl+k, Ctrl+l
416+
Align the image to one of the boundaries of the window when it is larger
417+
than the window.
418+
419+
= and -
420+
Change the zoom.
421+
422+
+ and _
423+
Change the zoom slowly.
424+
425+
0
426+
Reset zoom and panscan.
427+
428+
u
429+
Toggle between showing the image unscaled in its original dimensions and
430+
fitting it to the window.
431+
432+
o
433+
Fill the window with the image. This makes the image scaled to the window,
434+
resets zoom and sets ``--panscan`` to 1. See ``-panscan`` for more info.
435+
436+
r
437+
Rotate counterclockwise.
438+
439+
R and t
440+
Rotate clockwise.
441+
442+
v
443+
Rotate by 180 degrees.
444+
445+
SPACE
446+
Toggle between showing images for 5 seconds in a slideshow and keeping them
447+
open forever.
448+
449+
[ and ]
450+
Decrease/increase the image display duration by 1.
451+
452+
{ and }
453+
Halve/double the image display duration.
454+
455+
n
456+
Go to the next playlist entry.
457+
458+
p
459+
Go to the previous playlist entry.
460+
461+
N
462+
Go to the next sub-playlist (e.g. directory or archive).
463+
464+
P
465+
Go to the previous sub-playlist.
466+
467+
HOME and g-g
468+
Go to the first playlist entry.
469+
470+
END and G
471+
Go to the last playlist entry.
472+
473+
Wheel up/down
474+
Change the zoom while keeping the part of the image hovered by the cursor
475+
under it.
476+
477+
See `Image profile`_ for image viewing tips.
478+
402479
USAGE
403480
=====
404481

@@ -1057,6 +1134,77 @@ example, ``math`` is defined and gives access to the Lua standard math library.
10571134
This feature is subject to change indefinitely. You might be forced to
10581135
adjust your profiles on mpv updates.
10591136

1137+
Image profile
1138+
-------------
1139+
1140+
mpv has a builtin profile called ``builtin-image`` that is automatically applied
1141+
to images and restored when switching to a video or audio file. It enables
1142+
options optimal for image viewing, such as a smaller OSC layout optimized for
1143+
images. Its full contents can be listed with ``mpv
1144+
--show-profile=builtin-image``. It can be disabled with
1145+
``--apply-image-profile=no``.
1146+
1147+
It can be extended in mpv.conf without overwriting it completely:
1148+
1149+
.. admonition:: Example to loop image playlists
1150+
1151+
::
1152+
1153+
[builtin-image]
1154+
loop-playlist
1155+
1156+
``--apply-image-profile`` also enables the image specific key bindings listed in
1157+
`Keyboard Control`_. Additional image key bindings can be specified in the
1158+
``image`` section in ``input.conf``, for example:
1159+
1160+
SPACE {image} repeatable playlist-next force
1161+
1162+
See the `INPUT.CONF`_ section for more information on how to define key
1163+
bindings.
1164+
1165+
To reset zoom, alignment and rotation between images, it is recommended to place
1166+
``reset-on-next-file=video-zoom,panscan,video-unscaled,video-align-x,video-align-y,video-rotate``
1167+
in the top level of mpv.conf, as enabling it in the conditional profile makes it
1168+
take effect only from the second file.
1169+
1170+
To start viewing images and videos bigger than the window from the top left
1171+
corner, these options can be set in the top level of mpv.conf along with
1172+
``--reset-on-next-file``:
1173+
1174+
.. admonition:: Start from the top left:
1175+
1176+
::
1177+
1178+
video-align-x=-1
1179+
video-align-y=-1
1180+
video-recenter
1181+
1182+
To enable the screensaver only when images are kept open forever, this profile
1183+
can be added to mpv.conf:
1184+
1185+
.. admonition:: Example to enable the screensaver:
1186+
1187+
::
1188+
1189+
[screensaver]
1190+
profile-cond=p['current-tracks/video/image'] and not p['current-tracks/video/albumart'] and image_display_duration == math.huge
1191+
profile-restore=copy
1192+
stop-screensaver=no
1193+
1194+
``--vo=gpu-next`` is recommended for better performance with large images,
1195+
except images larger than the max texture size of the GPU API, for which a VO
1196+
with software rendering can be used as fallback:
1197+
1198+
.. admonition:: Example to display huge images on Wayland:
1199+
1200+
::
1201+
1202+
[huge]
1203+
profile-cond=width > 16384 or height > 16384
1204+
vo=wlshm
1205+
1206+
maxImageExtent may be 8192 instead on old iGPUs.
1207+
10601208
Legacy auto profiles
10611209
--------------------
10621210

DOCS/man/options.rst

+14-6
Original file line numberDiff line numberDiff line change
@@ -877,6 +877,11 @@ Program Behavior
877877
Show the description and content of a profile. Lists all profiles if no
878878
parameter is provided.
879879

880+
``--apply-image-profile=<yes|no>``
881+
Whether to apply the ``builtin-image`` profile and enable the ``image``
882+
input section when viewing an image without audio, and to restore them when
883+
switching to a video or audio file (default: yes).
884+
880885
``--use-filedir-conf``
881886
Look for a file-specific configuration file in the same directory as the
882887
file that is being played. See `File-specific Configuration Files`_.
@@ -1584,7 +1589,7 @@ Video
15841589
These values have special meaning:
15851590

15861591
:0: disable aspect ratio handling, pretend the video has square pixels
1587-
:no: same as ``0``
1592+
:no: same as ``0`` (default for images)
15881593
:-1: use the video stream or container aspect (default)
15891594

15901595
But note that handling of these special values might change in the future.
@@ -1702,11 +1707,11 @@ Video
17021707
when the video becomes smaller than the window in the respective direction
17031708

17041709
After zooming in until the video is bigger the window, panning with
1705-
`--video-align-x` and/or `--video-align-y`, and zooming out until the video
1706-
is smaller than the window, this is useful to recenter the video in the
1707-
window.
1710+
``--video-align-x`` and/or ``--video-align-y``, and zooming out until the
1711+
video is smaller than the window, this is useful to recenter the video in
1712+
the window.
17081713

1709-
Default: no.
1714+
Default: no. The default is changed to yes for images.
17101715

17111716
``--video-margin-ratio-left=<val>``, ``--video-margin-ratio-right=<val>``, ``--video-margin-ratio-top=<val>``, ``--video-margin-ratio-bottom=<val>``
17121717
Set extra video margins on each border (default: 0). Each value is a ratio
@@ -3363,7 +3368,7 @@ Window
33633368
(Windows only)
33643369
Enable/disable playback progress rendering in taskbar (Windows 7 and above).
33653370

3366-
Enabled by default.
3371+
Enabled by default, except for images.
33673372

33683373
``--snap-window``
33693374
(Windows only) Snap the player window to screen edges.
@@ -4445,6 +4450,9 @@ Input
44454450
Note that disabling the preprocessing does not affect any filtering done
44464451
by the OS/driver before these events are delivered to mpv, if any.
44474452

4453+
This defaults to no for images to allow dialog panning when the touchpad is
4454+
bound to pan commands.
4455+
44484456
``--input-right-alt-gr=<yes|no>``
44494457
(macOS and Windows only)
44504458
Use the right Alt key as Alt Gr to produce special characters. If disabled,

DOCS/man/osc.rst

+4
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,8 @@ Configurable Options
178178
bottombar, topbar, slimbottombar and slimtopbar. Default pre-0.21.0 was
179179
'box'.
180180

181+
slimbottombar is the default for images.
182+
181183
``seekbarstyle``
182184
Default: bar
183185

@@ -240,6 +242,8 @@ Configurable Options
240242
OSC will always popup with mouse movement in the window, and 1 means the
241243
OSC will only show up when the mouse hovers it. Default pre-0.21.0 was 0.
242244

245+
0.9 is the default for images.
246+
243247
``minmousemove``
244248
Default: 0
245249

etc/builtin.conf

+10
Original file line numberDiff line numberDiff line change
@@ -94,3 +94,13 @@ sub-shadow-offset=4
9494
[box]
9595
profile=osd-box
9696
profile=sub-box
97+
98+
[builtin-image]
99+
profile-restore=copy-equal
100+
script-opt=osc-layout=slimbottombar
101+
script-opt=osc-deadzonesize=0.9
102+
prefetch-playlist
103+
video-recenter
104+
video-aspect-override=no
105+
input-preprocess-wheel=no
106+
taskbar-progress=no

etc/input.conf

+69
Original file line numberDiff line numberDiff line change
@@ -238,3 +238,72 @@
238238

239239
# ? cycle sub-forced-events-only # display only DVD/PGS forced subtitle events
240240
# ? stop # stop playback (quit or enter idle mode)
241+
242+
#
243+
# Image bindings
244+
#
245+
#LEFT {image} script-binding positioning/pan-x -0.1 # pan left
246+
#DOWN {image} script-binding positioning/pan-y 0.1 # pan down
247+
#UP {image} script-binding positioning/pan-y -0.1 # pan up
248+
#RIGHT {image} script-binding positioning/pan-x 0.1 # pan right
249+
#h {image} script-binding positioning/pan-x -0.1 # pan left
250+
#j {image} script-binding positioning/pan-y 0.1 # pan down
251+
#k {image} script-binding positioning/pan-y -0.1 # pan up
252+
#l {image} script-binding positioning/pan-x 0.1 # pan right
253+
#Shift+LEFT {image} script-binding positioning/pan-x -0.01 # pan left slowly
254+
#Shift+DOWN {image} script-binding positioning/pan-y 0.01 # pan down slowly
255+
#Shift+UP {image} script-binding positioning/pan-y -0.01 # pan up slowly
256+
#Shift+RIGHT {image} script-binding positioning/pan-x 0.01 # pan right slowly
257+
#H {image} script-binding positioning/pan-x -0.01 # pan left slowly
258+
#J {image} script-binding positioning/pan-y 0.01 # pan down slowly
259+
#K {image} script-binding positioning/pan-y -0.01 # pan up slowly
260+
#L {image} script-binding positioning/pan-x 0.01 # pan right slowly
261+
262+
# Recommended on a touchpad:
263+
# WHEEL_UP {image} script-binding positioning/pan-y -0.1 # pan up
264+
# WHEEL_DOWN {image} script-binding positioning/pan-y 0.1 # pan down
265+
# WHEEL_LEFT {image} script-binding positioning/pan-x -0.1 # pan left
266+
# WHEEL_RIGHT {image} script-binding positioning/pan-x 0.1 # pan right
267+
268+
#Ctrl+LEFT {image} no-osd set video-align-x -1 # align to the left
269+
#Ctrl+DOWN {image} no-osd set video-align-y 1 # align to the bottom
270+
#Ctrl+UP {image} no-osd set video-align-y -1 # align to the top
271+
#Ctrl+RIGHT {image} no-osd set video-align-x 1 # align to the right
272+
#Ctrl+h {image} no-osd set video-align-x -1 # align to the left
273+
#Ctrl+j {image} no-osd set video-align-y 1 # align to the bottom
274+
#Ctrl+k {image} no-osd set video-align-y -1 # align to the top
275+
#Ctrl+l {image} no-osd set video-align-x 1 # align to the right
276+
277+
#= {image} add video-zoom 0.1 # zoom in
278+
#- {image} add video-zoom -0.1 # zoom out
279+
#+ {image} add video-zoom 0.01 # zoom in slowly
280+
#_ {image} add video-zoom -0.01 # zoom out slowly
281+
#0 {image} no-osd set video-zoom 0; no-osd set panscan 0 # reset zoom
282+
283+
#WHEEL_UP {image} script-binding cursor-centric-zoom 0.1 # zoom in towards the cursor
284+
#WHEEL_DOWN {image} script-binding cursor-centric-zoom -0.1 # zoom out towards the cursor
285+
286+
#u {image} no-osd cycle-values video-unscaled yes no; no-osd set video-zoom 0; no-osd set panscan 0 # toggle scaling the image to the window.
287+
288+
#o {image} no-osd set panscan 1; no-osd set video-unscaled no; no-osd set video-zoom 0 # fill black bars
289+
290+
#r {image} cycle-values video-rotate 270 180 90 0 # rotate counterclockwise
291+
#R {image} cycle-values video-rotate 90 180 270 0 # rotate clockwise
292+
#t {image} cycle-values video-rotate 90 180 270 0 # rotate clockwise
293+
#v {image} cycle-values video-rotate 0 180 # rotate by 180 degrees
294+
295+
#SPACE {image} cycle-values image-display-duration inf 5; no-osd set pause no # toggle slideshow
296+
#[ {image} add image-display-duration -1 # decrease the slideshow duration
297+
#] {image} add image-display-duration 1 # increment the slideshow duration
298+
#{ {image} multiply image-display-duration 0.5 # halve the slideshow duration
299+
#} {image} multiply image-display-duration 2 # double the slideshow duration
300+
301+
#n {image} repeatable playlist-next # go to the next file
302+
#p {image} repeatable playlist-prev # go to the previous file
303+
#N {image} playlist-next-playlist # go to the next sub-playlist
304+
#P {image} playlist-prev-playlist # go to the previous sub-playlist
305+
306+
#HOME {image} no-osd set playlist-pos 0 # go to the first playlist entry
307+
#g-g {image} no-osd set playlist-pos 0 # go to the first playlist entry
308+
#END {image} no-osd set playlist-pos-1 ${playlist-count} # go to the last playlist entry
309+
#G {image} no-osd set playlist-pos-1 ${playlist-count} # go to the last playlist entry

options/options.c

+2
Original file line numberDiff line numberDiff line change
@@ -474,6 +474,7 @@ static const m_option_t mp_opts[] = {
474474
{"profile", CONF_TYPE_STRING_LIST, 0, .offset = -1},
475475
{"show-profile", CONF_TYPE_STRING, M_OPT_NOCFG | M_OPT_NOPROP |
476476
M_OPT_OPTIONAL_PARAM, .offset = -1},
477+
{"apply-image-profile", OPT_BOOL(apply_image_profile)},
477478
{"list-options", &m_option_type_dummy_flag, M_OPT_NOCFG | M_OPT_NOPROP,
478479
.offset = -1},
479480
{"list-properties", OPT_BOOL(property_print_help),
@@ -1012,6 +1013,7 @@ static const struct MPOpts mp_default_opts = {
10121013
.rebase_start_time = true,
10131014
.keep_open_pause = true,
10141015
.image_display_duration = 5.0,
1016+
.apply_image_profile = true,
10151017
.stream_id = { { [STREAM_AUDIO] = -1,
10161018
[STREAM_VIDEO] = -1,
10171019
[STREAM_SUB] = -1, },

options/options.h

+1
Original file line numberDiff line numberDiff line change
@@ -283,6 +283,7 @@ typedef struct MPOpts {
283283
int keep_open;
284284
bool keep_open_pause;
285285
double image_display_duration;
286+
bool apply_image_profile;
286287
char *lavfi_complex;
287288
int stream_id[2][STREAM_TYPE_COUNT];
288289
char **stream_lang[STREAM_TYPE_COUNT];

player/core.h

+2
Original file line numberDiff line numberDiff line change
@@ -437,6 +437,8 @@ typedef struct MPContext {
437437
// playback rate. Used to avoid showing it multiple times.
438438
bool drop_message_shown;
439439

440+
bool image_profile_applied;
441+
440442
struct screenshot_ctx *screenshot_ctx;
441443
struct command_ctx *command_ctx;
442444
struct encode_lavc_context *encode_lavc_ctx;

player/loadfile.c

+25
Original file line numberDiff line numberDiff line change
@@ -1519,6 +1519,29 @@ static void load_external_opts(struct MPContext *mpctx)
15191519
mp_waiter_wait(&wait);
15201520
}
15211521

1522+
static void toggle_image_profile(struct MPContext *mpctx)
1523+
{
1524+
if (!mpctx->opts->apply_image_profile)
1525+
return;
1526+
1527+
if (!mpctx->image_profile_applied &&
1528+
mpctx->current_track[0][STREAM_VIDEO] &&
1529+
mpctx->current_track[0][STREAM_VIDEO]->image &&
1530+
!mpctx->current_track[0][STREAM_AUDIO]) {
1531+
m_config_set_profile(mpctx->mconfig, "builtin-image", 0);
1532+
mp_input_enable_section(mpctx->input, "image",
1533+
MP_INPUT_ALLOW_HIDE_CURSOR|MP_INPUT_ALLOW_VO_DRAGGING);
1534+
mpctx->image_profile_applied = true;
1535+
} else if (mpctx->image_profile_applied &&
1536+
(!mpctx->current_track[0][STREAM_VIDEO] ||
1537+
!mpctx->current_track[0][STREAM_VIDEO]->image ||
1538+
mpctx->current_track[0][STREAM_AUDIO])) {
1539+
m_config_restore_profile(mpctx->mconfig, "builtin-image");
1540+
mp_input_disable_section(mpctx->input, "image");
1541+
mpctx->image_profile_applied = false;
1542+
}
1543+
}
1544+
15221545
static void append_to_watch_history(struct MPContext *mpctx)
15231546
{
15241547
if (!mpctx->opts->save_watch_history)
@@ -1837,6 +1860,8 @@ static void play_current_file(struct MPContext *mpctx)
18371860
if (!mpctx->vo_chain)
18381861
handle_force_window(mpctx, true);
18391862

1863+
toggle_image_profile(mpctx);
1864+
18401865
MP_VERBOSE(mpctx, "Starting playback...\n");
18411866

18421867
mpctx->playback_initialized = true;

0 commit comments

Comments
 (0)