132 lines
3.6 KiB
Python
132 lines
3.6 KiB
Python
# People's Video Editor: high quality, GPU accelerated mp4 editor
|
|
# Copyright (C) 2025 Roz K <roz@rozk.net>
|
|
#
|
|
# This file is part of People's Video Editor.
|
|
#
|
|
# People's Video Editor is free software: you can redistribute it and/or modify it under the terms of the
|
|
# GNU General Public License as published by the Free Software Foundation, either version 3 of the License,
|
|
# or (at your option) any later version.
|
|
#
|
|
# People's Video Editor is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
|
# without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
# See the GNU General Public License for more details.
|
|
#
|
|
# You should have received a copy of the GNU General Public License along with People's Video Editor.
|
|
# If not, see <https://www.gnu.org/licenses/>.
|
|
|
|
from fractions import Fraction
|
|
|
|
class Geometry:
|
|
__slots__ = '_width', '_height', '_ratio', '_size'
|
|
|
|
def __init__(self, width = 0, height = 0, ratio = None):
|
|
if width > 0 and height > 0:
|
|
assert ratio is None
|
|
self._width = width
|
|
self._height = height
|
|
self._ratio = Fraction(width, height).limit_denominator()
|
|
self._size = width * height
|
|
elif width > 0 and ratio:
|
|
self._width = width
|
|
self._height = round((width * ratio.numerator) / ratio.denominator)
|
|
self._ratio = ratio
|
|
self._size = width * self._height
|
|
elif height > 0 and ratio:
|
|
self._width = round((height * ratio.denominator) / ratio.numerator)
|
|
self._height = height
|
|
self._ratio = ratio
|
|
self._size = self._width * height
|
|
else:
|
|
raise ValueError
|
|
|
|
def __ge__(self, other):
|
|
return (self._width >= other._width and self._height >= other._height)
|
|
|
|
@property
|
|
def width(self):
|
|
return self._width
|
|
|
|
@property
|
|
def height(self):
|
|
return self._height
|
|
|
|
@property
|
|
def ratio(self):
|
|
return self._ratio
|
|
|
|
class Format:
|
|
__slots__ = '_channels', '_depth', '_type', '_size'
|
|
|
|
def __init__(self, channels, depth):
|
|
self._channels = channels
|
|
self._depth = depth
|
|
if depth == 8:
|
|
self._type = 'B'
|
|
self._size = channels
|
|
elif depth == 16:
|
|
self._type = 'H'
|
|
self._size = channels * 2
|
|
else:
|
|
raise ValueError
|
|
|
|
def __eq__(self, other):
|
|
return (self._channels == other._channels and self._depth == other._depth)
|
|
|
|
@property
|
|
def channels(self):
|
|
return self._channels
|
|
|
|
@property
|
|
def depth(self):
|
|
return self._depth
|
|
|
|
class Pixmap:
|
|
__slots__ = '_geometry', '_format', '_line_size', '_bytes', '_view'
|
|
|
|
def __init__(self, geometry, format):
|
|
self._geometry = geometry
|
|
self._format = format
|
|
self._line_size = geometry._width * format._size
|
|
self._bytes = bytearray(geometry._size * format._size)
|
|
self._view = memoryview(self._bytes)
|
|
|
|
def __del__(self):
|
|
del self._view
|
|
del self._bytes
|
|
|
|
@property
|
|
def geometry(self):
|
|
return self._geometry
|
|
|
|
@property
|
|
def width(self):
|
|
return self._geometry._width
|
|
|
|
@property
|
|
def height(self):
|
|
return self._geometry._height
|
|
|
|
@property
|
|
def ratio(self):
|
|
return self._geometry._ratio
|
|
|
|
@property
|
|
def format(self):
|
|
return self._format
|
|
|
|
@property
|
|
def channels(self):
|
|
return self._format._channels
|
|
|
|
@property
|
|
def depth(self):
|
|
return self._format._depth
|
|
|
|
@property
|
|
def line_size(self):
|
|
return self._line_size
|
|
|
|
@property
|
|
def view(self):
|
|
return self._view
|