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

fix(ui): enhance window quality #22

Merged
merged 10 commits into from
Sep 21, 2022
14 changes: 13 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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!

- [Install](#install)
- [Installation](#installation)
* [Dependencies](#dependencies)
* [Pip install](#pip-install)
* [Install From Repository](#install-from-repository)
Expand All @@ -18,6 +18,8 @@ Tool for live presentations using either [Manim (community edition)](https://www
* [Key Bindings](#key-bindings)
* [Other Examples](#other-examples)
- [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)

## Installation
Expand Down Expand Up @@ -168,6 +170,16 @@ Below is a non-exhaustive list of features:
| Documented code | :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%:

![Windows Fix Scaling](static/windows_quality_fix.png)

in *Settings*->*Display*.

## Contributing

Expand Down
2 changes: 1 addition & 1 deletion manim_slides/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
from enum import Enum
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

Expand Down
90 changes: 53 additions & 37 deletions manim_slides/present.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,6 @@
from enum import IntEnum, auto, unique
from typing import List, Tuple

if platform.system() == "Windows":
import ctypes

import click
import cv2
import numpy as np
Expand All @@ -19,8 +16,19 @@
from .config import Config, PresentationConfig, SlideConfig, SlideType
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_INFO_NAME = f"{WINDOW_NAME}: Info"
WINDOWS = platform.system() == "Windows"


@unique
Expand Down Expand Up @@ -252,14 +260,19 @@ def __init__(
start_paused=False,
fullscreen=False,
skip_all=False,
resolution=(1280, 720),
resolution=(1980, 1080),
interpolation_flag=cv2.INTER_LINEAR,
):
self.presentations = presentations
self.start_paused = start_paused
self.config = config
self.skip_all = skip_all
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.lastframe = None
Expand All @@ -274,39 +287,16 @@ def __init__(
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:
cv2.namedWindow(WINDOW_NAME, cv2.WND_PROP_FULLSCREEN)
cv2.namedWindow(
WINDOW_NAME, cv2.WINDOW_GUI_NORMAL | cv2.WND_PROP_FULLSCREEN
)
cv2.setWindowProperty(
WINDOW_NAME, cv2.WND_PROP_FULLSCREEN, cv2.WINDOW_FULLSCREEN
)
else:
cv2.namedWindow(
WINDOW_NAME,
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)))
cv2.namedWindow(WINDOW_NAME, self.window_flags)
cv2.resizeWindow(WINDOW_NAME, *self.resolution)

@property
def current_presentation(self) -> Presentation:
Expand Down Expand Up @@ -343,8 +333,17 @@ def show_video(self):

frame = self.lastframe

if self.is_windows and self.fullscreen:
frame = self.resize_frame_to_screen(frame)
# If Window was manually closed (impossible in fullscreen),
# 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)

Expand Down Expand Up @@ -477,15 +476,31 @@ def _list_scenes(folder) -> List[str]:
help="Skip all slides, useful the test if slides are working.",
)
@click.option(
"-r",
"--resolution",
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.",
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")
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."""

Expand Down Expand Up @@ -552,5 +567,6 @@ def value_proc(value: str):
fullscreen=fullscreen,
skip_all=skip_all,
resolution=resolution,
interpolation_flag=INTERPOLATION_FLAGS[interpolation_flag],
)
display.run()
Binary file added static/windows_quality_fix.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.