mkv-episode-matcher 0.1.4__py3-none-any.whl → 0.1.9__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of mkv-episode-matcher might be problematic. Click here for more details.
- mkv_episode_matcher/__init__.py +1 -1
- mkv_episode_matcher/__main__.py +12 -10
- mkv_episode_matcher/libraries/pgs2srt/.gitignore +2 -2
- mkv_episode_matcher/libraries/pgs2srt/Libraries/SubZero/SubZero.py +295 -295
- mkv_episode_matcher/libraries/pgs2srt/Libraries/SubZero/dictionaries/data.py +249 -249
- mkv_episode_matcher/libraries/pgs2srt/Libraries/SubZero/post_processing.py +215 -215
- mkv_episode_matcher/libraries/pgs2srt/README.md +26 -26
- mkv_episode_matcher/libraries/pgs2srt/imagemaker.py +87 -87
- mkv_episode_matcher/libraries/pgs2srt/pgs2srt.py +121 -121
- mkv_episode_matcher/libraries/pgs2srt/pgsreader.py +221 -221
- mkv_episode_matcher/libraries/pgs2srt/requirements.txt +4 -4
- mkv_episode_matcher/mkv_to_srt.py +174 -174
- mkv_episode_matcher/notebooks/get_subtitles_test.ipynb +252 -0
- mkv_episode_matcher/requirements.txt +6 -7
- mkv_episode_matcher/utils.py +5 -2
- {mkv_episode_matcher-0.1.4.dist-info → mkv_episode_matcher-0.1.9.dist-info}/METADATA +53 -37
- mkv_episode_matcher-0.1.9.dist-info/RECORD +25 -0
- {mkv_episode_matcher-0.1.4.dist-info → mkv_episode_matcher-0.1.9.dist-info}/WHEEL +2 -1
- mkv_episode_matcher-0.1.9.dist-info/top_level.txt +1 -0
- mkv_episode_matcher/libraries/pgs2srt/.git +0 -1
- mkv_episode_matcher-0.1.4.dist-info/RECORD +0 -24
- {mkv_episode_matcher-0.1.4.dist-info → mkv_episode_matcher-0.1.9.dist-info}/entry_points.txt +0 -0
|
@@ -1,221 +1,221 @@
|
|
|
1
|
-
#!/usr/bin/env python3
|
|
2
|
-
|
|
3
|
-
from collections import namedtuple
|
|
4
|
-
from os.path import split as pathsplit
|
|
5
|
-
|
|
6
|
-
# Constants for Segments
|
|
7
|
-
PDS = int('0x14', 16)
|
|
8
|
-
ODS = int('0x15', 16)
|
|
9
|
-
PCS = int('0x16', 16)
|
|
10
|
-
WDS = int('0x17', 16)
|
|
11
|
-
END = int('0x80', 16)
|
|
12
|
-
|
|
13
|
-
# Named tuple access for static PDS palettes
|
|
14
|
-
Palette = namedtuple('Palette', "Y Cr Cb Alpha")
|
|
15
|
-
|
|
16
|
-
class InvalidSegmentError(Exception):
|
|
17
|
-
'''Raised when a segment does not match PGS specification'''
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
class PGSReader:
|
|
21
|
-
|
|
22
|
-
def __init__(self, filepath):
|
|
23
|
-
self.filedir, self.file = pathsplit(filepath)
|
|
24
|
-
with open(filepath, 'rb') as f:
|
|
25
|
-
self.bytes = f.read()
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
def make_segment(self, bytes_):
|
|
29
|
-
cls = SEGMENT_TYPE[bytes_[10]]
|
|
30
|
-
return cls(bytes_)
|
|
31
|
-
|
|
32
|
-
def iter_segments(self):
|
|
33
|
-
bytes_ = self.bytes[:]
|
|
34
|
-
while bytes_:
|
|
35
|
-
size = 13 + int(bytes_[11:13].hex(), 16)
|
|
36
|
-
yield self.make_segment(bytes_[:size])
|
|
37
|
-
bytes_ = bytes_[size:]
|
|
38
|
-
|
|
39
|
-
def iter_displaysets(self):
|
|
40
|
-
ds = []
|
|
41
|
-
for s in self.iter_segments():
|
|
42
|
-
ds.append(s)
|
|
43
|
-
if s.type == 'END':
|
|
44
|
-
yield DisplaySet(ds)
|
|
45
|
-
ds = []
|
|
46
|
-
|
|
47
|
-
@property
|
|
48
|
-
def segments(self):
|
|
49
|
-
if not hasattr(self, '_segments'):
|
|
50
|
-
self._segments = list(self.iter_segments())
|
|
51
|
-
return self._segments
|
|
52
|
-
|
|
53
|
-
@property
|
|
54
|
-
def displaysets(self):
|
|
55
|
-
if not hasattr(self, '_displaysets'):
|
|
56
|
-
self._displaysets = list(self.iter_displaysets())
|
|
57
|
-
return self._displaysets
|
|
58
|
-
|
|
59
|
-
class BaseSegment:
|
|
60
|
-
|
|
61
|
-
SEGMENT = {
|
|
62
|
-
PDS: 'PDS',
|
|
63
|
-
ODS: 'ODS',
|
|
64
|
-
PCS: 'PCS',
|
|
65
|
-
WDS: 'WDS',
|
|
66
|
-
END: 'END'
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
def __init__(self, bytes_):
|
|
70
|
-
self.bytes = bytes_
|
|
71
|
-
if bytes_[:2] != b'PG':
|
|
72
|
-
raise InvalidSegmentError
|
|
73
|
-
self.pts = int(bytes_[2:6].hex(), base=16) / 90
|
|
74
|
-
self.dts = int(bytes_[6:10].hex(), base=16) / 90
|
|
75
|
-
self.type = self.SEGMENT[bytes_[10]]
|
|
76
|
-
self.size = int(bytes_[11:13].hex(), base=16)
|
|
77
|
-
self.data = bytes_[13:]
|
|
78
|
-
|
|
79
|
-
def __len__(self):
|
|
80
|
-
return self.size
|
|
81
|
-
|
|
82
|
-
@property
|
|
83
|
-
def presentation_timestamp(self): return self.pts
|
|
84
|
-
|
|
85
|
-
@property
|
|
86
|
-
def decoding_timestamp(self): return self.dts
|
|
87
|
-
|
|
88
|
-
@property
|
|
89
|
-
def segment_type(self): return self.type
|
|
90
|
-
|
|
91
|
-
class PresentationCompositionSegment(BaseSegment):
|
|
92
|
-
|
|
93
|
-
class CompositionObject:
|
|
94
|
-
|
|
95
|
-
def __init__(self, bytes_):
|
|
96
|
-
self.bytes = bytes_
|
|
97
|
-
self.object_id = int(bytes_[0:2].hex(), base=16)
|
|
98
|
-
self.window_id = bytes_[2]
|
|
99
|
-
self.cropped = bool(bytes_[3])
|
|
100
|
-
self.x_offset = int(bytes_[4:6].hex(), base=16)
|
|
101
|
-
self.y_offset = int(bytes_[6:8].hex(), base=16)
|
|
102
|
-
if self.cropped:
|
|
103
|
-
self.crop_x_offset = int(bytes_[8:10].hex(), base=16)
|
|
104
|
-
self.crop_y_offset = int(bytes_[10:12].hex(), base=16)
|
|
105
|
-
self.crop_width = int(bytes_[12:14].hex(), base=16)
|
|
106
|
-
self.crop_height = int(bytes_[14:16].hex(), base=16)
|
|
107
|
-
|
|
108
|
-
STATE = {
|
|
109
|
-
int('0x00', base=16): 'Normal',
|
|
110
|
-
int('0x40', base=16): 'Acquisition Point',
|
|
111
|
-
int('0x80', base=16): 'Epoch Start'
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
def __init__(self, bytes_):
|
|
115
|
-
BaseSegment.__init__(self, bytes_)
|
|
116
|
-
self.width = int(self.data[0:2].hex(), base=16)
|
|
117
|
-
self.height = int(self.data[2:4].hex(), base=16)
|
|
118
|
-
self.frame_rate = self.data[4]
|
|
119
|
-
self._num = int(self.data[5:7].hex(), base=16)
|
|
120
|
-
self._state = self.STATE[self.data[7]]
|
|
121
|
-
self.palette_update = bool(self.data[8])
|
|
122
|
-
self.palette_id = self.data[9]
|
|
123
|
-
self._num_comps = self.data[10]
|
|
124
|
-
|
|
125
|
-
@property
|
|
126
|
-
def composition_number(self): return self._num
|
|
127
|
-
|
|
128
|
-
@property
|
|
129
|
-
def composition_state(self): return self._state
|
|
130
|
-
|
|
131
|
-
@property
|
|
132
|
-
def composition_objects(self):
|
|
133
|
-
if not hasattr(self, '_composition_objects'):
|
|
134
|
-
self._composition_objects = self.get_composition_objects()
|
|
135
|
-
if len(self._composition_objects) != self._num_comps:
|
|
136
|
-
print('Warning: Number of composition objects asserted '
|
|
137
|
-
'does not match the amount found.')
|
|
138
|
-
return self._composition_objects
|
|
139
|
-
|
|
140
|
-
def get_composition_objects(self):
|
|
141
|
-
bytes_ = self.data[11:]
|
|
142
|
-
comps = []
|
|
143
|
-
while bytes_:
|
|
144
|
-
length = 8 * (1 + bool(bytes_[3]))
|
|
145
|
-
comps.append(self.CompositionObject(bytes_[:length]))
|
|
146
|
-
bytes_ = bytes_[length:]
|
|
147
|
-
return comps
|
|
148
|
-
|
|
149
|
-
class WindowDefinitionSegment(BaseSegment):
|
|
150
|
-
|
|
151
|
-
def __init__(self, bytes_):
|
|
152
|
-
BaseSegment.__init__(self, bytes_)
|
|
153
|
-
self.num_windows = self.data[0]
|
|
154
|
-
self.window_id = self.data[1]
|
|
155
|
-
self.x_offset = int(self.data[2:4].hex(), base=16)
|
|
156
|
-
self.y_offset = int(self.data[4:6].hex(), base=16)
|
|
157
|
-
self.width = int(self.data[6:8].hex(), base=16)
|
|
158
|
-
self.height = int(self.data[8:10].hex(), base=16)
|
|
159
|
-
|
|
160
|
-
class PaletteDefinitionSegment(BaseSegment):
|
|
161
|
-
|
|
162
|
-
def __init__(self, bytes_):
|
|
163
|
-
BaseSegment.__init__(self, bytes_)
|
|
164
|
-
self.palette_id = self.data[0]
|
|
165
|
-
self.version = self.data[1]
|
|
166
|
-
self.palette = [Palette(0, 0, 0, 0)] * 256
|
|
167
|
-
# Slice from byte 2 til end of segment. Divide by 5 to determine number of palette entries
|
|
168
|
-
# Iterate entries. Explode the 5 bytes into namedtuple Palette. Must be exploded
|
|
169
|
-
for entry in range(len(self.data[2:]) // 5):
|
|
170
|
-
i = 2 + entry * 5
|
|
171
|
-
self.palette[self.data[i]] = Palette(*self.data[i + 1:i + 5])
|
|
172
|
-
|
|
173
|
-
class ObjectDefinitionSegment(BaseSegment):
|
|
174
|
-
|
|
175
|
-
SEQUENCE = {
|
|
176
|
-
int('0x40', base=16): 'Last',
|
|
177
|
-
int('0x80', base=16): 'First',
|
|
178
|
-
int('0xc0', base=16): 'First and last'
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
def __init__(self, bytes_):
|
|
182
|
-
BaseSegment.__init__(self, bytes_)
|
|
183
|
-
self.id = int(self.data[0:2].hex(), base=16)
|
|
184
|
-
self.version = self.data[2]
|
|
185
|
-
self.in_sequence = self.SEQUENCE[self.data[3]]
|
|
186
|
-
self.data_len = int(self.data[4:7].hex(), base=16)
|
|
187
|
-
self.width = int(self.data[7:9].hex(), base=16)
|
|
188
|
-
self.height = int(self.data[9:11].hex(), base=16)
|
|
189
|
-
self.img_data = self.data[11:]
|
|
190
|
-
if len(self.img_data) != self.data_len - 4:
|
|
191
|
-
print('Warning: Image data length asserted does not match the '
|
|
192
|
-
'length found.')
|
|
193
|
-
|
|
194
|
-
class EndSegment(BaseSegment):
|
|
195
|
-
|
|
196
|
-
@property
|
|
197
|
-
def is_end(self): return True
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
SEGMENT_TYPE = {
|
|
201
|
-
PDS: PaletteDefinitionSegment,
|
|
202
|
-
ODS: ObjectDefinitionSegment,
|
|
203
|
-
PCS: PresentationCompositionSegment,
|
|
204
|
-
WDS: WindowDefinitionSegment,
|
|
205
|
-
END: EndSegment
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
class DisplaySet:
|
|
209
|
-
|
|
210
|
-
def __init__(self, segments):
|
|
211
|
-
self.segments = segments
|
|
212
|
-
self.segment_types = [s.type for s in segments]
|
|
213
|
-
self.has_image = 'ODS' in self.segment_types
|
|
214
|
-
|
|
215
|
-
def segment_by_type_getter(type_):
|
|
216
|
-
def f(self):
|
|
217
|
-
return [s for s in self.segments if s.type == type_]
|
|
218
|
-
return f
|
|
219
|
-
|
|
220
|
-
for type_ in BaseSegment.SEGMENT.values():
|
|
221
|
-
setattr(DisplaySet, type_.lower(), property(segment_by_type_getter(type_)))
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
|
|
3
|
+
from collections import namedtuple
|
|
4
|
+
from os.path import split as pathsplit
|
|
5
|
+
|
|
6
|
+
# Constants for Segments
|
|
7
|
+
PDS = int('0x14', 16)
|
|
8
|
+
ODS = int('0x15', 16)
|
|
9
|
+
PCS = int('0x16', 16)
|
|
10
|
+
WDS = int('0x17', 16)
|
|
11
|
+
END = int('0x80', 16)
|
|
12
|
+
|
|
13
|
+
# Named tuple access for static PDS palettes
|
|
14
|
+
Palette = namedtuple('Palette', "Y Cr Cb Alpha")
|
|
15
|
+
|
|
16
|
+
class InvalidSegmentError(Exception):
|
|
17
|
+
'''Raised when a segment does not match PGS specification'''
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class PGSReader:
|
|
21
|
+
|
|
22
|
+
def __init__(self, filepath):
|
|
23
|
+
self.filedir, self.file = pathsplit(filepath)
|
|
24
|
+
with open(filepath, 'rb') as f:
|
|
25
|
+
self.bytes = f.read()
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def make_segment(self, bytes_):
|
|
29
|
+
cls = SEGMENT_TYPE[bytes_[10]]
|
|
30
|
+
return cls(bytes_)
|
|
31
|
+
|
|
32
|
+
def iter_segments(self):
|
|
33
|
+
bytes_ = self.bytes[:]
|
|
34
|
+
while bytes_:
|
|
35
|
+
size = 13 + int(bytes_[11:13].hex(), 16)
|
|
36
|
+
yield self.make_segment(bytes_[:size])
|
|
37
|
+
bytes_ = bytes_[size:]
|
|
38
|
+
|
|
39
|
+
def iter_displaysets(self):
|
|
40
|
+
ds = []
|
|
41
|
+
for s in self.iter_segments():
|
|
42
|
+
ds.append(s)
|
|
43
|
+
if s.type == 'END':
|
|
44
|
+
yield DisplaySet(ds)
|
|
45
|
+
ds = []
|
|
46
|
+
|
|
47
|
+
@property
|
|
48
|
+
def segments(self):
|
|
49
|
+
if not hasattr(self, '_segments'):
|
|
50
|
+
self._segments = list(self.iter_segments())
|
|
51
|
+
return self._segments
|
|
52
|
+
|
|
53
|
+
@property
|
|
54
|
+
def displaysets(self):
|
|
55
|
+
if not hasattr(self, '_displaysets'):
|
|
56
|
+
self._displaysets = list(self.iter_displaysets())
|
|
57
|
+
return self._displaysets
|
|
58
|
+
|
|
59
|
+
class BaseSegment:
|
|
60
|
+
|
|
61
|
+
SEGMENT = {
|
|
62
|
+
PDS: 'PDS',
|
|
63
|
+
ODS: 'ODS',
|
|
64
|
+
PCS: 'PCS',
|
|
65
|
+
WDS: 'WDS',
|
|
66
|
+
END: 'END'
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
def __init__(self, bytes_):
|
|
70
|
+
self.bytes = bytes_
|
|
71
|
+
if bytes_[:2] != b'PG':
|
|
72
|
+
raise InvalidSegmentError
|
|
73
|
+
self.pts = int(bytes_[2:6].hex(), base=16) / 90
|
|
74
|
+
self.dts = int(bytes_[6:10].hex(), base=16) / 90
|
|
75
|
+
self.type = self.SEGMENT[bytes_[10]]
|
|
76
|
+
self.size = int(bytes_[11:13].hex(), base=16)
|
|
77
|
+
self.data = bytes_[13:]
|
|
78
|
+
|
|
79
|
+
def __len__(self):
|
|
80
|
+
return self.size
|
|
81
|
+
|
|
82
|
+
@property
|
|
83
|
+
def presentation_timestamp(self): return self.pts
|
|
84
|
+
|
|
85
|
+
@property
|
|
86
|
+
def decoding_timestamp(self): return self.dts
|
|
87
|
+
|
|
88
|
+
@property
|
|
89
|
+
def segment_type(self): return self.type
|
|
90
|
+
|
|
91
|
+
class PresentationCompositionSegment(BaseSegment):
|
|
92
|
+
|
|
93
|
+
class CompositionObject:
|
|
94
|
+
|
|
95
|
+
def __init__(self, bytes_):
|
|
96
|
+
self.bytes = bytes_
|
|
97
|
+
self.object_id = int(bytes_[0:2].hex(), base=16)
|
|
98
|
+
self.window_id = bytes_[2]
|
|
99
|
+
self.cropped = bool(bytes_[3])
|
|
100
|
+
self.x_offset = int(bytes_[4:6].hex(), base=16)
|
|
101
|
+
self.y_offset = int(bytes_[6:8].hex(), base=16)
|
|
102
|
+
if self.cropped:
|
|
103
|
+
self.crop_x_offset = int(bytes_[8:10].hex(), base=16)
|
|
104
|
+
self.crop_y_offset = int(bytes_[10:12].hex(), base=16)
|
|
105
|
+
self.crop_width = int(bytes_[12:14].hex(), base=16)
|
|
106
|
+
self.crop_height = int(bytes_[14:16].hex(), base=16)
|
|
107
|
+
|
|
108
|
+
STATE = {
|
|
109
|
+
int('0x00', base=16): 'Normal',
|
|
110
|
+
int('0x40', base=16): 'Acquisition Point',
|
|
111
|
+
int('0x80', base=16): 'Epoch Start'
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
def __init__(self, bytes_):
|
|
115
|
+
BaseSegment.__init__(self, bytes_)
|
|
116
|
+
self.width = int(self.data[0:2].hex(), base=16)
|
|
117
|
+
self.height = int(self.data[2:4].hex(), base=16)
|
|
118
|
+
self.frame_rate = self.data[4]
|
|
119
|
+
self._num = int(self.data[5:7].hex(), base=16)
|
|
120
|
+
self._state = self.STATE[self.data[7]]
|
|
121
|
+
self.palette_update = bool(self.data[8])
|
|
122
|
+
self.palette_id = self.data[9]
|
|
123
|
+
self._num_comps = self.data[10]
|
|
124
|
+
|
|
125
|
+
@property
|
|
126
|
+
def composition_number(self): return self._num
|
|
127
|
+
|
|
128
|
+
@property
|
|
129
|
+
def composition_state(self): return self._state
|
|
130
|
+
|
|
131
|
+
@property
|
|
132
|
+
def composition_objects(self):
|
|
133
|
+
if not hasattr(self, '_composition_objects'):
|
|
134
|
+
self._composition_objects = self.get_composition_objects()
|
|
135
|
+
if len(self._composition_objects) != self._num_comps:
|
|
136
|
+
print('Warning: Number of composition objects asserted '
|
|
137
|
+
'does not match the amount found.')
|
|
138
|
+
return self._composition_objects
|
|
139
|
+
|
|
140
|
+
def get_composition_objects(self):
|
|
141
|
+
bytes_ = self.data[11:]
|
|
142
|
+
comps = []
|
|
143
|
+
while bytes_:
|
|
144
|
+
length = 8 * (1 + bool(bytes_[3]))
|
|
145
|
+
comps.append(self.CompositionObject(bytes_[:length]))
|
|
146
|
+
bytes_ = bytes_[length:]
|
|
147
|
+
return comps
|
|
148
|
+
|
|
149
|
+
class WindowDefinitionSegment(BaseSegment):
|
|
150
|
+
|
|
151
|
+
def __init__(self, bytes_):
|
|
152
|
+
BaseSegment.__init__(self, bytes_)
|
|
153
|
+
self.num_windows = self.data[0]
|
|
154
|
+
self.window_id = self.data[1]
|
|
155
|
+
self.x_offset = int(self.data[2:4].hex(), base=16)
|
|
156
|
+
self.y_offset = int(self.data[4:6].hex(), base=16)
|
|
157
|
+
self.width = int(self.data[6:8].hex(), base=16)
|
|
158
|
+
self.height = int(self.data[8:10].hex(), base=16)
|
|
159
|
+
|
|
160
|
+
class PaletteDefinitionSegment(BaseSegment):
|
|
161
|
+
|
|
162
|
+
def __init__(self, bytes_):
|
|
163
|
+
BaseSegment.__init__(self, bytes_)
|
|
164
|
+
self.palette_id = self.data[0]
|
|
165
|
+
self.version = self.data[1]
|
|
166
|
+
self.palette = [Palette(0, 0, 0, 0)] * 256
|
|
167
|
+
# Slice from byte 2 til end of segment. Divide by 5 to determine number of palette entries
|
|
168
|
+
# Iterate entries. Explode the 5 bytes into namedtuple Palette. Must be exploded
|
|
169
|
+
for entry in range(len(self.data[2:]) // 5):
|
|
170
|
+
i = 2 + entry * 5
|
|
171
|
+
self.palette[self.data[i]] = Palette(*self.data[i + 1:i + 5])
|
|
172
|
+
|
|
173
|
+
class ObjectDefinitionSegment(BaseSegment):
|
|
174
|
+
|
|
175
|
+
SEQUENCE = {
|
|
176
|
+
int('0x40', base=16): 'Last',
|
|
177
|
+
int('0x80', base=16): 'First',
|
|
178
|
+
int('0xc0', base=16): 'First and last'
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
def __init__(self, bytes_):
|
|
182
|
+
BaseSegment.__init__(self, bytes_)
|
|
183
|
+
self.id = int(self.data[0:2].hex(), base=16)
|
|
184
|
+
self.version = self.data[2]
|
|
185
|
+
self.in_sequence = self.SEQUENCE[self.data[3]]
|
|
186
|
+
self.data_len = int(self.data[4:7].hex(), base=16)
|
|
187
|
+
self.width = int(self.data[7:9].hex(), base=16)
|
|
188
|
+
self.height = int(self.data[9:11].hex(), base=16)
|
|
189
|
+
self.img_data = self.data[11:]
|
|
190
|
+
if len(self.img_data) != self.data_len - 4:
|
|
191
|
+
print('Warning: Image data length asserted does not match the '
|
|
192
|
+
'length found.')
|
|
193
|
+
|
|
194
|
+
class EndSegment(BaseSegment):
|
|
195
|
+
|
|
196
|
+
@property
|
|
197
|
+
def is_end(self): return True
|
|
198
|
+
|
|
199
|
+
|
|
200
|
+
SEGMENT_TYPE = {
|
|
201
|
+
PDS: PaletteDefinitionSegment,
|
|
202
|
+
ODS: ObjectDefinitionSegment,
|
|
203
|
+
PCS: PresentationCompositionSegment,
|
|
204
|
+
WDS: WindowDefinitionSegment,
|
|
205
|
+
END: EndSegment
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
class DisplaySet:
|
|
209
|
+
|
|
210
|
+
def __init__(self, segments):
|
|
211
|
+
self.segments = segments
|
|
212
|
+
self.segment_types = [s.type for s in segments]
|
|
213
|
+
self.has_image = 'ODS' in self.segment_types
|
|
214
|
+
|
|
215
|
+
def segment_by_type_getter(type_):
|
|
216
|
+
def f(self):
|
|
217
|
+
return [s for s in self.segments if s.type == type_]
|
|
218
|
+
return f
|
|
219
|
+
|
|
220
|
+
for type_ in BaseSegment.SEGMENT.values():
|
|
221
|
+
setattr(DisplaySet, type_.lower(), property(segment_by_type_getter(type_)))
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
pytesseract==0.3.7
|
|
2
|
-
numpy==1.19.4
|
|
3
|
-
Pillow==8.2.0
|
|
4
|
-
tld~=0.12.3
|
|
1
|
+
pytesseract==0.3.7
|
|
2
|
+
numpy==1.19.4
|
|
3
|
+
Pillow==8.2.0
|
|
4
|
+
tld~=0.12.3
|