Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improvements to Image and Grid Image Rendering #13

Merged
merged 37 commits into from
May 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
f3c25f3
fix,refac: render: Improve image rendering
AnonymouX47 Apr 21, 2024
cf48dc1
refac: render: Refactor `manage_grid_renders()`
AnonymouX47 Apr 21, 2024
88aff68
feat,docs: config: Add thumbnailing options
AnonymouX47 Apr 21, 2024
feea530
feat: cli: Add thumbnailing options
AnonymouX47 Apr 21, 2024
c9d6b30
chore: widget: Update comments in `Image.render()`
AnonymouX47 Apr 23, 2024
e164f1f
refac: cli: Remove thumbnailing options
AnonymouX47 Apr 23, 2024
60b9a8f
refac: config: Update `thumbnail size` option
AnonymouX47 Apr 23, 2024
e6669f5
refac: render: Improve grid render synchronization
AnonymouX47 Apr 25, 2024
1d47529
feat: render: Implement image grid thumbnailing
AnonymouX47 Apr 25, 2024
6b19913
feat,refac: tui: Improve grid thumbnailing
AnonymouX47 Apr 26, 2024
736e4eb
refac: tui: Deduplicate grid render refresh code
AnonymouX47 Apr 26, 2024
6ef2a51
refac: tui: Improve grid render refresh on resize
AnonymouX47 Apr 26, 2024
df4e723
refac: tui.render: Improve grid thumbnail quality
AnonymouX47 Apr 26, 2024
1f9faa0
fix: render: Finalize thumbnail images properly
AnonymouX47 Apr 26, 2024
f5363eb
feat,docs: cli,config: Enable/Disable thumbnailing
AnonymouX47 Apr 26, 2024
9194190
feat,refac: tui: Implement thumbnailing en/disable
AnonymouX47 Apr 26, 2024
4b989d3
chore: tui.keys,tui.render: Update comments
AnonymouX47 Apr 26, 2024
70a57bc
feat: tui: Make "max pixels" optional for the grid
AnonymouX47 Apr 27, 2024
735c192
docs: cli,config: Update option descriptions
AnonymouX47 Apr 27, 2024
f20e31e
chore: Add thumbnail options to the sample config
AnonymouX47 Apr 27, 2024
b3aec3f
Revert 'Make "max pixels" optional for the grid'
AnonymouX47 Apr 29, 2024
f2c0c02
docs: args,config: Update "max pixels" description
AnonymouX47 Apr 29, 2024
a6ee003
refac,docs: args,config: Make "max pixels" opt-in
AnonymouX47 Apr 29, 2024
54950d2
refac,docs: render,config: Minor refactor/reword
AnonymouX47 Apr 30, 2024
03358cb
refac,docs: args: Remove `--max-pixels-cli`
AnonymouX47 Apr 30, 2024
4ecb8cf
refac: tui: No "max pixels" in "full-grid-image"
AnonymouX47 Apr 30, 2024
723583b
feat: tui: Distinguish high-res images in the grid
AnonymouX47 Apr 30, 2024
9336dae
feat: tui: Force-rendering in the "menu" context
AnonymouX47 Apr 30, 2024
9ced040
refac: tui,config: Reorder "Force Render" actions
AnonymouX47 Apr 30, 2024
ec10137
feat,refac,docs: render: Thumbnail deduplication
AnonymouX47 May 1, 2024
0e00650
fix: render: Fix thumbnail eviction
AnonymouX47 May 2, 2024
e76476a
refac: render: Simplify grid image rendering
AnonymouX47 May 2, 2024
440d987
refac: tui.widgets: Simplify grid cell height comp
AnonymouX47 May 2, 2024
a50bf00
refac: tui.render: Rename a function
AnonymouX47 May 2, 2024
611c931
fix: tui.keys: Fix grid render resync upon resize
AnonymouX47 May 2, 2024
047378e
chore: Update the sample default config file
AnonymouX47 May 3, 2024
328d504
chore: Update CHANGELOG for #13
AnonymouX47 May 3, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 18 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,25 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased]
### Fixed
- tui: Crash on image grid view ([c64f195]).
- cli,tui: Sorting of top-level (command line) entries ([9ea0572])
- cli,tui: Sorting of top-level (command line) entries ([9ea0572]).

### Added
- tui: Thumbnail generation (with deduplication) and caching for the image grid ([#13]).
- config: `thumbnail`, `thumbnail cache` and `thumbnail size` config options.
- args: `--thumbnail/--no-thumbnail` command-line option.
- tui: `Force Render` action to the `menu` context ([#13]).

### Changed
- cli,tui: Revamped the *max pixels* setting ([#13]).
- It is now **opt-in** i.e by default, all images are now rendered regardless of resolution.
- config: Changed the default value of the `max pixels` config option to `0` (disabled).
- tui: It no longer applies in the `full-grid-image` context.
- tui: In the `image-grid` context, images with more pixels than *max pixels* (**if non-zero**) are now distinguished by a yellow title and border.

### Removed
- args: `--max-pixels-cli` command-line option ([#13]).

[#13]: https://github.com/AnonymouX47/termvisage/pull/13
[c64f195]: https://github.com/AnonymouX47/termvisage/commit/c64f195a79557fdf5a9323db907a5716a12d6440
[9ea0572]: https://github.com/AnonymouX47/termvisage/commit/9ea0572e6db35984a4ae0af1691edfd179e5d393

Expand Down
29 changes: 16 additions & 13 deletions default-termvisage.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,14 @@
"grid renderers": 1,
"log file": "~/.local/state/termvisage/termvisage.log",
"max notifications": 2,
"max pixels": 4194304,
"max pixels": 0,
"multi": true,
"query timeout": 0.1,
"style": "auto",
"swap win size": false,
"thumbnail": true,
"thumbnail cache": 0,
"thumbnail size": 256,
"keys": {
"navigation": {
"Left": [
Expand Down Expand Up @@ -81,13 +84,13 @@
"Switch Pane": [
"tab",
"\u21b9"
]
},
"image": {
],
"Force Render": [
"F",
"\u21e7F"
],
]
},
"image": {
"Maximize": [
"f",
"f"
Expand All @@ -99,6 +102,10 @@
"Switch Pane": [
"tab",
"\u21b9"
],
"Force Render": [
"F",
"\u21e7F"
]
},
"image-grid": {
Expand All @@ -124,23 +131,19 @@
"esc",
"\u238b"
],
"Force Render": [
"F",
"\u21e7F"
],
"Delete": [
"d",
"d"
],
"Force Render": [
"F",
"\u21e7F"
]
},
"full-grid-image": {
"Back": [
"esc",
"\u238b"
],
"Force Render": [
"F",
"\u21e7F"
]
},
"confirmation": {
Expand Down
11 changes: 0 additions & 11 deletions docs/source/cli.rst
Original file line number Diff line number Diff line change
Expand Up @@ -45,17 +45,6 @@ Options and Arguments
:option:`--original-size` is used if not larger than the :term:`available size`,
else :option:`--fit`.

.. [#] Any image having more pixels than the specified maximum will be:

- skipped, in CLI mode, if :option:`--max-pixels-cli` is specified.
- replaced, in TUI mode, with a placeholder when displayed but can still be
explicitly made to display.

Note that increasing this should not have any effect on general performance
(i.e navigation, etc) but the larger an image is, the more the time and memory
it'll take to render it. Thus, a large image might delay the rendering of other
images to be rendered immediately after it.

.. [#] Any event with a level lower than the specified one is not reported.

.. [#] 0 -> worst quality; smallest data size, 95 -> best quality; largest data size.
Expand Down
65 changes: 54 additions & 11 deletions docs/source/config.rst
Original file line number Diff line number Diff line change
Expand Up @@ -130,21 +130,22 @@ These are top-level fields whose values control various settings of the viewer.
Adjusts the height of the :ref:`notification bar <notif-bar>`.

.. confval:: max pixels
:synopsis: The maximum amount of pixels in images to be displayed in the TUI.
:synopsis: The maximum pixel-count for images that should be rendered.
:type: integer
:valid: *x* > ``0``
:default: ``4194304`` (2 ** 22)
:valid: *x* >= ``0``
:default: ``0``

Any image having more pixels than the specified value will be:
If zero, all images will be rendered normally, regardless of their resolution.
Otherwise, any image having more pixels than the specified value will be:

* skipped, in CLI mode, if :option:`--max-pixels-cli` is specified.
* replaced, in TUI mode, with a placeholder when displayed but can still be forced
to display or viewed externally.
* **skipped** in CLI mode.
* **replaced** in TUI mode (except in the ``full-grid-image``
:ref:`context <contexts>`), with a placeholder (filled with exclamation marks)
but can be forced to render using the ``Force Render`` :ref:`action <actions>`
in :ref:`contexts <contexts>` with a full-sized image view.

Note that increasing this should not have any effect on general performance (i.e
navigation, etc) but the larger an image is, the more the time and memory it'll take
to render it. Thus, a large image might delay the rendering of other images to be
rendered immediately after it.
In the ``image-grid`` :ref:`context <contexts>`, such images have a **yellow**
border (when selected) and title.

.. note:: Overridden by :option:`--max-pixels`.

Expand Down Expand Up @@ -191,6 +192,48 @@ These are top-level fields whose values control various settings of the viewer.
* Overridden by :option:`--swap-win-size` and :option:`--no-swap-win-size`.
* Affects *auto* :term:`cell ratio` computation.

.. confval:: thumbnail
:synopsis: Enable or disable thumbnailing for the image grid.
:type: boolean
:valid: ``true``, ``false``
:default: ``true``

If ``true``, thumbnails are generated for some images (based on their resolution),
cached on disk and cleaned up upon exit. Otherwise, all images in the grid are
rendered directly from the original image files.

.. note::

- Overridden by :option:`--thumbnail` and :option:`--no-thumbnail`.
- Thumbnails are generated **on demand** i.e a thumbnail will be generated for
an image only if its grid cell has come into view at least once.
- Thumbnails are **deduplicated** i.e only one thumbnail is cached and used for
different images having exactly identical thumbnails.

.. confval:: thumbnail cache
:synopsis: The maximum amount of thumbnails that can be cached per time.
:type: integer
:valid: *x* >= ``0``
:default: ``0``

If ``0``, the cache size is infinite i.e no eviction. Otherwise, older thumbnails
will be evicted to accommodate newer ones when the cache is full (i.e the specified
size limit is reached).

.. note:: Unused if :confval:`thumbnail` is ``false`` or :option:`--no-thumbnail`
is specified.

.. confval:: thumbnail size
:synopsis: Maxiumum thumbnail dimension.
:type: integer
:valid: ``32`` <= *x* <= ``512``
:default: ``256``

Thumbnails generated will have a maximum of *x* pixels in the long dimension.

.. note:: Unused if :confval:`thumbnail` is ``false`` or :option:`--no-thumbnail`
is specified.


Keybindings
-----------
Expand Down
2 changes: 1 addition & 1 deletion src/termvisage/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -948,7 +948,7 @@ def main() -> None:
show_name = len(args.sources) > 1
for entry in images:
image = entry[1]._ti_image
if args.max_pixels_cli and mul(*image._original_size) > args.max_pixels:
if 0 < args.max_pixels < mul(*image._original_size):
log(
f"Has more than the maximum pixel-count, skipping: {entry[0]!r}",
logger,
Expand Down
39 changes: 27 additions & 12 deletions src/termvisage/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -592,9 +592,9 @@ def update_context_nav(
"must be an integer between 0 and 5 (both inclusive)",
),
"max pixels": Option(
2**22, # 2048x2048
lambda x: isinstance(x, int) and x > 0,
"must be an integer greater than zero",
0,
lambda x: isinstance(x, int) and x >= 0,
"must be a non-negative integer",
),
"multi": Option(
True,
Expand All @@ -616,6 +616,21 @@ def update_context_nav(
lambda x: isinstance(x, bool),
"must be a boolean",
),
"thumbnail": Option(
True,
lambda x: isinstance(x, bool),
"must be a boolean",
),
"thumbnail cache": Option(
0,
lambda x: isinstance(x, int) and x >= 0,
"must be a non-negative integer",
),
"thumbnail size": Option(
256,
lambda x: isinstance(x, int) and 32 <= x <= 512,
"must be an integer between 32 and 512 (both inclusive)",
),
}
config_options = ConfigOptions(config_options)

Expand Down Expand Up @@ -647,6 +662,11 @@ def update_context_nav(
"Back": ["backspace", "\u27f5 ", "Return to the previous directory"],
"Delete": ["d", "d", "Delete selected image"],
"Switch Pane": ["tab", "\u21b9", "Switch to image pane"],
"Force Render": [
"F",
"\u21e7F",
"Force an image, with more pixels than the set maximum, to be displayed",
],
"Page Up": ["page up", "", "Jump up one page"],
"Page Down": ["page down", "", "Jump down one page"],
"Top": ["home", "", "Jump to the top of the list"],
Expand All @@ -655,14 +675,14 @@ def update_context_nav(
"image": {
"Prev": ["left", "", "Move to the previous image"],
"Next": ["right", "", "Move to the next image"],
"Maximize": ["f", "f", "Maximize the current image"],
"Delete": ["d", "d", "Delete current image"],
"Switch Pane": ["tab", "\u21b9", "Switch to list pane"],
"Force Render": [
"F",
"\u21e7F",
"Force an image, with more pixels than the set maximum, to be displayed",
],
"Maximize": ["f", "f", "Maximize the current image"],
"Delete": ["d", "d", "Delete current image"],
"Switch Pane": ["tab", "\u21b9", "Switch to list pane"],
},
"image-grid": {
"Open": ["enter", "\u23ce", "Maximize the selected image"],
Expand All @@ -682,20 +702,15 @@ def update_context_nav(
"Restore": ["esc", "\u238b", "Exit maximized view"],
"Prev": ["left", "", "Move to the previous image"],
"Next": ["right", "", "Move to the next image"],
"Delete": ["d", "d", "Delete current image"],
"Force Render": [
"F",
"\u21e7F",
"Force an image, with more pixels than the set maximum, to be displayed",
],
"Delete": ["d", "d", "Delete current image"],
},
"full-grid-image": {
"Back": ["esc", "\u238b", "Back to grid view"],
"Force Render": [
"F",
"\u21e7F",
"Force an image, with more pixels than the set maximum, to be displayed",
],
},
"confirmation": {
"Confirm": ["enter", "\u23ce", ""],
Expand Down
19 changes: 12 additions & 7 deletions src/termvisage/parsers.py
Original file line number Diff line number Diff line change
Expand Up @@ -593,6 +593,16 @@ def strip_markup(string: str) -> str:
default=sys.getrecursionlimit() - 50,
help=f"Maximum recursion depth (default: {sys.getrecursionlimit() - 50})",
)
tui_options.add_argument(
"--thumbnail",
action=BooleanOptionalAction,
default=None,
help=(
"Enable or disable thumbnail generation for the image grid; if enabled, "
"thumbnails are cached on disk and cleaned up upon exit "
"(default: :confval:`thumbnail` config)"
),
)

# Performance
perf_options = parser.add_argument_group("Performance Options")
Expand All @@ -601,15 +611,10 @@ def strip_markup(string: str) -> str:
type=int,
metavar="N",
help=(
"Maximum amount of pixels in images to be displayed "
"(default: :confval:`max pixels` config) [#]_"
"The maximum pixel-count for images that should be rendered "
"(default: :confval:`max pixels` config)"
),
)
perf_options.add_argument(
"--max-pixels-cli",
action="store_true",
help="Apply :option:`--max-pixels` in CLI mode",
)
perf_options.add_argument(
"--multi",
action=BooleanOptionalAction,
Expand Down
Loading
Loading