mirror of
https://github.com/jeertmans/manim-slides.git
synced 2025-07-02 04:46:45 +08:00
fix(ui): enhance window quality (#22)
* fix(ui): enhance window quality This fix always resizes the frame size, as this seems to be a good cross-platform fix to the quality issue that occurs when the frame does not match the window size. * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * fix: remove unused import * fix: actually only resize on Windows * feat(cli): optional interpolation flag * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * chore: add image fox windows quality fix * chore(README): document Windows fix Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
This commit is contained in:
14
README.md
14
README.md
@ -9,7 +9,7 @@ Tool for live presentations using either [Manim (community edition)](https://www
|
|||||||
|
|
||||||
> **_NOTE:_** This project extends the work of [`manim-presentation`](https://github.com/galatolofederico/manim-presentation), with a lot more features!
|
> **_NOTE:_** This project extends the work of [`manim-presentation`](https://github.com/galatolofederico/manim-presentation), with a lot more features!
|
||||||
|
|
||||||
- [Install](#install)
|
- [Installation](#installation)
|
||||||
* [Dependencies](#dependencies)
|
* [Dependencies](#dependencies)
|
||||||
* [Pip install](#pip-install)
|
* [Pip install](#pip-install)
|
||||||
* [Install From Repository](#install-from-repository)
|
* [Install From Repository](#install-from-repository)
|
||||||
@ -18,6 +18,8 @@ Tool for live presentations using either [Manim (community edition)](https://www
|
|||||||
* [Key Bindings](#key-bindings)
|
* [Key Bindings](#key-bindings)
|
||||||
* [Other Examples](#other-examples)
|
* [Other Examples](#other-examples)
|
||||||
- [Features and Comparison with Original manim-presentation](#features-and-comparison-with-original-manim-presentation)
|
- [Features and Comparison with Original manim-presentation](#features-and-comparison-with-original-manim-presentation)
|
||||||
|
- [F.A.Q](#faq)
|
||||||
|
* [How to increase quality on Windows](#how-to-increase-quality-on-windows)
|
||||||
- [Contributing](#contributing)
|
- [Contributing](#contributing)
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
@ -168,6 +170,16 @@ Below is a non-exhaustive list of features:
|
|||||||
| Documented code | :heavy_check_mark: | :heavy_multiplication_x: |
|
| Documented code | :heavy_check_mark: | :heavy_multiplication_x: |
|
||||||
| Tested on Unix, macOS, and Windows | :heavy_check_mark: | :heavy_multiplication_x: |
|
| Tested on Unix, macOS, and Windows | :heavy_check_mark: | :heavy_multiplication_x: |
|
||||||
|
|
||||||
|
## F.A.Q
|
||||||
|
|
||||||
|
### How to increase quality on Windows
|
||||||
|
|
||||||
|
On Windows platform, one may encounter a lower image resolution than expected. Usually, this is observed because Windows rescales every application to fit the screen.
|
||||||
|
As found by [@arashash](https://github.com/arashash), in [#20](https://github.com/jeertmans/manim-slides/issues/20), the problem can be addressed by changing the scaling factor to 100%:
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
in *Settings*->*Display*.
|
||||||
|
|
||||||
## Contributing
|
## Contributing
|
||||||
|
|
||||||
|
@ -2,7 +2,7 @@ import os
|
|||||||
from enum import Enum
|
from enum import Enum
|
||||||
from typing import List, Optional, Set
|
from typing import List, Optional, Set
|
||||||
|
|
||||||
from pydantic import BaseModel, FilePath, root_validator, validator
|
from pydantic import BaseModel, root_validator, validator
|
||||||
|
|
||||||
from .defaults import LEFT_ARROW_KEY_CODE, RIGHT_ARROW_KEY_CODE
|
from .defaults import LEFT_ARROW_KEY_CODE, RIGHT_ARROW_KEY_CODE
|
||||||
|
|
||||||
|
@ -7,9 +7,6 @@ import time
|
|||||||
from enum import IntEnum, auto, unique
|
from enum import IntEnum, auto, unique
|
||||||
from typing import List, Tuple
|
from typing import List, Tuple
|
||||||
|
|
||||||
if platform.system() == "Windows":
|
|
||||||
import ctypes
|
|
||||||
|
|
||||||
import click
|
import click
|
||||||
import cv2
|
import cv2
|
||||||
import numpy as np
|
import numpy as np
|
||||||
@ -19,8 +16,19 @@ from .commons import config_path_option
|
|||||||
from .config import Config, PresentationConfig, SlideConfig, SlideType
|
from .config import Config, PresentationConfig, SlideConfig, SlideType
|
||||||
from .defaults import CONFIG_PATH, FOLDER_PATH, FONT_ARGS
|
from .defaults import CONFIG_PATH, FOLDER_PATH, FONT_ARGS
|
||||||
|
|
||||||
|
INTERPOLATION_FLAGS = {
|
||||||
|
"nearest": cv2.INTER_NEAREST,
|
||||||
|
"linear": cv2.INTER_LINEAR,
|
||||||
|
"cubic": cv2.INTER_CUBIC,
|
||||||
|
"area": cv2.INTER_AREA,
|
||||||
|
"lanczos4": cv2.INTER_LANCZOS4,
|
||||||
|
"linear-exact": cv2.INTER_LINEAR_EXACT,
|
||||||
|
"nearest-exact": cv2.INTER_NEAREST_EXACT,
|
||||||
|
}
|
||||||
|
|
||||||
WINDOW_NAME = "Manim Slides"
|
WINDOW_NAME = "Manim Slides"
|
||||||
WINDOW_INFO_NAME = f"{WINDOW_NAME}: Info"
|
WINDOW_INFO_NAME = f"{WINDOW_NAME}: Info"
|
||||||
|
WINDOWS = platform.system() == "Windows"
|
||||||
|
|
||||||
|
|
||||||
@unique
|
@unique
|
||||||
@ -252,14 +260,19 @@ class Display:
|
|||||||
start_paused=False,
|
start_paused=False,
|
||||||
fullscreen=False,
|
fullscreen=False,
|
||||||
skip_all=False,
|
skip_all=False,
|
||||||
resolution=(1280, 720),
|
resolution=(1980, 1080),
|
||||||
|
interpolation_flag=cv2.INTER_LINEAR,
|
||||||
):
|
):
|
||||||
self.presentations = presentations
|
self.presentations = presentations
|
||||||
self.start_paused = start_paused
|
self.start_paused = start_paused
|
||||||
self.config = config
|
self.config = config
|
||||||
self.skip_all = skip_all
|
self.skip_all = skip_all
|
||||||
self.fullscreen = fullscreen
|
self.fullscreen = fullscreen
|
||||||
self.is_windows = platform.system() == "Windows"
|
self.resolution = resolution
|
||||||
|
self.interpolation_flag = interpolation_flag
|
||||||
|
self.window_flags = (
|
||||||
|
cv2.WINDOW_GUI_NORMAL | cv2.WINDOW_FREERATIO | cv2.WINDOW_NORMAL
|
||||||
|
)
|
||||||
|
|
||||||
self.state = State.PLAYING
|
self.state = State.PLAYING
|
||||||
self.lastframe = None
|
self.lastframe = None
|
||||||
@ -274,39 +287,16 @@ class Display:
|
|||||||
cv2.WINDOW_GUI_NORMAL | cv2.WINDOW_FREERATIO | cv2.WINDOW_AUTOSIZE,
|
cv2.WINDOW_GUI_NORMAL | cv2.WINDOW_FREERATIO | cv2.WINDOW_AUTOSIZE,
|
||||||
)
|
)
|
||||||
|
|
||||||
if self.is_windows:
|
|
||||||
user32 = ctypes.windll.user32
|
|
||||||
self.screen_width, self.screen_height = user32.GetSystemMetrics(
|
|
||||||
0
|
|
||||||
), user32.GetSystemMetrics(1)
|
|
||||||
|
|
||||||
if self.fullscreen:
|
if self.fullscreen:
|
||||||
cv2.namedWindow(WINDOW_NAME, cv2.WND_PROP_FULLSCREEN)
|
cv2.namedWindow(
|
||||||
|
WINDOW_NAME, cv2.WINDOW_GUI_NORMAL | cv2.WND_PROP_FULLSCREEN
|
||||||
|
)
|
||||||
cv2.setWindowProperty(
|
cv2.setWindowProperty(
|
||||||
WINDOW_NAME, cv2.WND_PROP_FULLSCREEN, cv2.WINDOW_FULLSCREEN
|
WINDOW_NAME, cv2.WND_PROP_FULLSCREEN, cv2.WINDOW_FULLSCREEN
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
cv2.namedWindow(
|
cv2.namedWindow(WINDOW_NAME, self.window_flags)
|
||||||
WINDOW_NAME,
|
cv2.resizeWindow(WINDOW_NAME, *self.resolution)
|
||||||
cv2.WINDOW_GUI_NORMAL | cv2.WINDOW_FREERATIO | cv2.WINDOW_NORMAL,
|
|
||||||
)
|
|
||||||
cv2.resizeWindow(WINDOW_NAME, *resolution)
|
|
||||||
|
|
||||||
def resize_frame_to_screen(self, frame: np.ndarray) -> np.ndarray:
|
|
||||||
"""
|
|
||||||
Resizes a given frame to match screen dimensions.
|
|
||||||
|
|
||||||
Only works on Windows.
|
|
||||||
"""
|
|
||||||
assert self.is_windows, "Only Windows platforms need this method"
|
|
||||||
frame_height, frame_width = frame.shape[:2]
|
|
||||||
|
|
||||||
scale_height = self.screen_height / frame_height
|
|
||||||
scale_width = self.screen_width / frame_width
|
|
||||||
|
|
||||||
scale = min(scale_height, scale_width)
|
|
||||||
|
|
||||||
return cv2.resize(frame, (int(scale * frame_height), int(scale * frame_width)))
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def current_presentation(self) -> Presentation:
|
def current_presentation(self) -> Presentation:
|
||||||
@ -343,8 +333,17 @@ class Display:
|
|||||||
|
|
||||||
frame = self.lastframe
|
frame = self.lastframe
|
||||||
|
|
||||||
if self.is_windows and self.fullscreen:
|
# If Window was manually closed (impossible in fullscreen),
|
||||||
frame = self.resize_frame_to_screen(frame)
|
# we reopen it
|
||||||
|
if cv2.getWindowProperty(WINDOW_NAME, cv2.WND_PROP_VISIBLE) < 1:
|
||||||
|
cv2.namedWindow(WINDOW_NAME, self.window_flags)
|
||||||
|
cv2.resizeWindow(WINDOW_NAME, *self.resolution)
|
||||||
|
|
||||||
|
if WINDOWS: # Only resize on Windows
|
||||||
|
_, _, w, h = cv2.getWindowImageRect(WINDOW_NAME)
|
||||||
|
|
||||||
|
if (h, w) != frame.shape[:2]: # Only if shape is different
|
||||||
|
frame = cv2.resize(frame, (w, h), self.interpolation_flag)
|
||||||
|
|
||||||
cv2.imshow(WINDOW_NAME, frame)
|
cv2.imshow(WINDOW_NAME, frame)
|
||||||
|
|
||||||
@ -477,15 +476,31 @@ def _list_scenes(folder) -> List[str]:
|
|||||||
help="Skip all slides, useful the test if slides are working.",
|
help="Skip all slides, useful the test if slides are working.",
|
||||||
)
|
)
|
||||||
@click.option(
|
@click.option(
|
||||||
|
"-r",
|
||||||
"--resolution",
|
"--resolution",
|
||||||
type=(int, int),
|
type=(int, int),
|
||||||
default=(1280, 720),
|
default=(1920, 1080),
|
||||||
help="Window resolution used if fullscreen is not set. You may manually resize the window afterward.",
|
help="Window resolution used if fullscreen is not set. You may manually resize the window afterward.",
|
||||||
show_default=True,
|
show_default=True,
|
||||||
)
|
)
|
||||||
|
@click.option(
|
||||||
|
"-i",
|
||||||
|
"--interpolation-flag",
|
||||||
|
type=click.Choice(INTERPOLATION_FLAGS.keys(), case_sensitive=False),
|
||||||
|
default="linear",
|
||||||
|
help="Set the interpolation flag to be used when resizing image. See OpenCV cv::InterpolationFlags.",
|
||||||
|
show_default=True,
|
||||||
|
)
|
||||||
@click.help_option("-h", "--help")
|
@click.help_option("-h", "--help")
|
||||||
def present(
|
def present(
|
||||||
scenes, config_path, folder, start_paused, fullscreen, skip_all, resolution
|
scenes,
|
||||||
|
config_path,
|
||||||
|
folder,
|
||||||
|
start_paused,
|
||||||
|
fullscreen,
|
||||||
|
skip_all,
|
||||||
|
resolution,
|
||||||
|
interpolation_flag,
|
||||||
):
|
):
|
||||||
"""Present the different scenes."""
|
"""Present the different scenes."""
|
||||||
|
|
||||||
@ -552,5 +567,6 @@ def present(
|
|||||||
fullscreen=fullscreen,
|
fullscreen=fullscreen,
|
||||||
skip_all=skip_all,
|
skip_all=skip_all,
|
||||||
resolution=resolution,
|
resolution=resolution,
|
||||||
|
interpolation_flag=INTERPOLATION_FLAGS[interpolation_flag],
|
||||||
)
|
)
|
||||||
display.run()
|
display.run()
|
||||||
|
BIN
static/windows_quality_fix.png
Normal file
BIN
static/windows_quality_fix.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 35 KiB |
Reference in New Issue
Block a user