Skip to content
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.