mkv-episode-matcher 0.1.5__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.

@@ -1,87 +1,87 @@
1
- import numpy as np
2
- from PIL import Image
3
-
4
-
5
- def read_rle_bytes(ods_bytes):
6
-
7
- pixels = []
8
- line_builder = []
9
-
10
- i = 0
11
- while i < len(ods_bytes):
12
- if ods_bytes[i]:
13
- incr = 1
14
- color = ods_bytes[i]
15
- length = 1
16
- else:
17
- check = ods_bytes[i + 1]
18
- if check == 0:
19
- incr = 2
20
- color = 0
21
- length = 0
22
- pixels.append(line_builder)
23
- line_builder = []
24
- elif check < 64:
25
- incr = 2
26
- color = 0
27
- length = check
28
- elif check < 128:
29
- incr = 3
30
- color = 0
31
- length = ((check - 64) << 8) + ods_bytes[i + 2]
32
- elif check < 192:
33
- incr = 3
34
- color = ods_bytes[i + 2]
35
- length = check - 128
36
- else:
37
- incr = 4
38
- color = ods_bytes[i + 3]
39
- length = ((check - 192) << 8) + ods_bytes[i + 2]
40
- line_builder.extend([color] * length)
41
- i += incr
42
-
43
- if line_builder:
44
- print(f'Probably an error; hanging pixels: {line_builder}')
45
-
46
- return pixels
47
-
48
- def ycbcr2rgb(ar):
49
- xform = np.array([[1, 0, 1.402], [1, -0.34414, -.71414], [1, 1.772, 0]])
50
- rgb = ar.astype(float)
51
- # Subtracting by 128 the R and G channels
52
- rgb[:, [1, 2]] -= 128
53
- # .dot is multiplication of the matrices and xform.T is a transpose of the array axes
54
- rgb = rgb.dot(xform.T)
55
- # Makes any pixel value greater than 255 just be 255 (Max for RGB colorspace)
56
- np.putmask(rgb, rgb > 255, 255)
57
- # Sets any pixel value less than 0 to 0 (Min for RGB colorspace)
58
- np.putmask(rgb, rgb < 0, 0)
59
- return np.uint8(rgb)
60
-
61
- def px_rgb_a(ods, pds, swap):
62
- px = read_rle_bytes(ods.img_data)
63
- px = np.array([[255] * (ods.width - len(l)) + l for l in px], dtype=np.uint8)
64
-
65
- # Extract the YCbCrA palette data, swapping channels if requested.
66
- if swap:
67
- ycbcr = np.array([(entry.Y, entry.Cb, entry.Cr) for entry in pds.palette])
68
- else:
69
- ycbcr = np.array([(entry.Y, entry.Cr, entry.Cb) for entry in pds.palette])
70
- try:
71
- rgb = ycbcr2rgb(ycbcr)
72
- except AttributeError:
73
- print("Error: The image is not in YCbCr format.")
74
- exit(1)
75
- # Separate the Alpha channel from the YCbCr palette data
76
- a = [entry.Alpha for entry in pds.palette]
77
- a = np.array([[a[x] for x in l] for l in px], dtype=np.uint8)
78
-
79
- return px, rgb, a
80
-
81
- def make_image(ods, pds, swap=False):
82
- px, rgb, a = px_rgb_a(ods, pds, swap)
83
- alpha = Image.fromarray(a, mode='L')
84
- img = Image.fromarray(px, mode='P')
85
- img.putalpha(alpha)
86
- img.putpalette(rgb)
87
- return img
1
+ import numpy as np
2
+ from PIL import Image
3
+
4
+
5
+ def read_rle_bytes(ods_bytes):
6
+
7
+ pixels = []
8
+ line_builder = []
9
+
10
+ i = 0
11
+ while i < len(ods_bytes):
12
+ if ods_bytes[i]:
13
+ incr = 1
14
+ color = ods_bytes[i]
15
+ length = 1
16
+ else:
17
+ check = ods_bytes[i + 1]
18
+ if check == 0:
19
+ incr = 2
20
+ color = 0
21
+ length = 0
22
+ pixels.append(line_builder)
23
+ line_builder = []
24
+ elif check < 64:
25
+ incr = 2
26
+ color = 0
27
+ length = check
28
+ elif check < 128:
29
+ incr = 3
30
+ color = 0
31
+ length = ((check - 64) << 8) + ods_bytes[i + 2]
32
+ elif check < 192:
33
+ incr = 3
34
+ color = ods_bytes[i + 2]
35
+ length = check - 128
36
+ else:
37
+ incr = 4
38
+ color = ods_bytes[i + 3]
39
+ length = ((check - 192) << 8) + ods_bytes[i + 2]
40
+ line_builder.extend([color] * length)
41
+ i += incr
42
+
43
+ if line_builder:
44
+ print(f'Probably an error; hanging pixels: {line_builder}')
45
+
46
+ return pixels
47
+
48
+ def ycbcr2rgb(ar):
49
+ xform = np.array([[1, 0, 1.402], [1, -0.34414, -.71414], [1, 1.772, 0]])
50
+ rgb = ar.astype(float)
51
+ # Subtracting by 128 the R and G channels
52
+ rgb[:, [1, 2]] -= 128
53
+ # .dot is multiplication of the matrices and xform.T is a transpose of the array axes
54
+ rgb = rgb.dot(xform.T)
55
+ # Makes any pixel value greater than 255 just be 255 (Max for RGB colorspace)
56
+ np.putmask(rgb, rgb > 255, 255)
57
+ # Sets any pixel value less than 0 to 0 (Min for RGB colorspace)
58
+ np.putmask(rgb, rgb < 0, 0)
59
+ return np.uint8(rgb)
60
+
61
+ def px_rgb_a(ods, pds, swap):
62
+ px = read_rle_bytes(ods.img_data)
63
+ px = np.array([[255] * (ods.width - len(l)) + l for l in px], dtype=np.uint8)
64
+
65
+ # Extract the YCbCrA palette data, swapping channels if requested.
66
+ if swap:
67
+ ycbcr = np.array([(entry.Y, entry.Cb, entry.Cr) for entry in pds.palette])
68
+ else:
69
+ ycbcr = np.array([(entry.Y, entry.Cr, entry.Cb) for entry in pds.palette])
70
+ try:
71
+ rgb = ycbcr2rgb(ycbcr)
72
+ except AttributeError:
73
+ print("Error: The image is not in YCbCr format.")
74
+ exit(1)
75
+ # Separate the Alpha channel from the YCbCr palette data
76
+ a = [entry.Alpha for entry in pds.palette]
77
+ a = np.array([[a[x] for x in l] for l in px], dtype=np.uint8)
78
+
79
+ return px, rgb, a
80
+
81
+ def make_image(ods, pds, swap=False):
82
+ px, rgb, a = px_rgb_a(ods, pds, swap)
83
+ alpha = Image.fromarray(a, mode='L')
84
+ img = Image.fromarray(px, mode='P')
85
+ img.putalpha(alpha)
86
+ img.putpalette(rgb)
87
+ return img
@@ -1,121 +1,121 @@
1
- #!/usr/bin/env python3
2
-
3
- import argparse
4
- import re
5
- from datetime import datetime, timedelta
6
-
7
- import pytesseract
8
- from imagemaker import make_image
9
- from pgsreader import PGSReader
10
- from PIL import Image, ImageOps
11
-
12
- from Libraries.SubZero.post_processing import CommonFixes, FixOCR
13
-
14
- parser = argparse.ArgumentParser(description='Convert PGS subtitles to SubRip format.')
15
-
16
- parser.add_argument('input', type=str, help="The input file (a .sup file).")
17
- parser.add_argument('--output', type=str, help="The output file (a .srt file).")
18
- parser.add_argument('--oem', type=int, help="The OCR Engine Mode to use (Default: 1).", default=1, choices=range(4))
19
- parser.add_argument('--language', type=str, help="The language to use (Default: eng).", default='eng')
20
- parser.add_argument('--fix_common', help='Fixes common whitespace/punctuation issues.',
21
- dest='fix_common', action='store_true')
22
- parser.add_argument('--fix_common_ocr', help='Fixes common OCR issues for supported languages.',
23
- dest='fix_ocr', action='store_true')
24
-
25
- args = parser.parse_args()
26
-
27
- assert args.input is not None
28
-
29
- # Unescape escaped spaces
30
- file = args.input.replace("\\ ", " ")
31
-
32
- print(f"Parsing: {file}")
33
-
34
- # Load a PGS/SUP file.
35
- pgs = PGSReader(file)
36
-
37
- # Set index
38
- i = 0
39
-
40
- # Complete subtitle track index
41
- si = 0
42
-
43
- tesseract_lang = args.language
44
- tesseract_config = f"-c tessedit_char_blacklist=[] --psm 6 --oem {args.oem}"
45
-
46
- # If an output file for the subrip output is provided, use that.
47
- # Otherwise remove the ".sup" extension from the input and append
48
- # ".srt".
49
- output_file = args.output if args.output is not None else (args.input.replace('.sup', '') + '.srt')
50
-
51
- # SubRip output
52
- output = ""
53
-
54
- fix_common = CommonFixes() if args.fix_common else None
55
- fix_ocr = FixOCR(args.language) if args.fix_ocr else None
56
-
57
- # Iterate the pgs generator
58
- for ds in pgs.iter_displaysets():
59
- try:
60
- # If set has image, parse the image
61
- if ds.has_image:
62
- # Get Palette Display Segment
63
- pds = ds.pds[0]
64
- # Get Object Display Segment
65
- ods = ds.ods[0]
66
-
67
- if pds and ods:
68
- # Create and show the bitmap image and convert it to RGBA
69
- src = make_image(ods, pds).convert('RGBA')
70
-
71
- # Create grayscale image with black background
72
- img = Image.new("L", src.size, "BLACK")
73
- # Paste the subtitle bitmap
74
- img.paste(src, (0, 0), src)
75
- # Invert images so the text is readable by Tesseract
76
- img = ImageOps.invert(img)
77
-
78
- # Parse the image with tesesract
79
- text = pytesseract.image_to_string(img, lang=tesseract_lang, config=tesseract_config).strip()
80
-
81
- # Replace "|" with "I"
82
- # Works better than blacklisting "|" in Tesseract,
83
- # which results in I becoming "!" "i" and "1"
84
- text = re.sub(r'[|/\\]', 'I', text)
85
- text = re.sub(r'[_]', 'L', text)
86
-
87
- if args.fix_common:
88
- text = fix_common.process(text)
89
- if args.fix_ocr:
90
- text = fix_ocr.modify(text)
91
-
92
- start = datetime.fromtimestamp(ods.presentation_timestamp / 1000)
93
- start = start + timedelta(hours=-1)
94
-
95
- else:
96
- # Get Presentation Composition Segment
97
- pcs = ds.pcs[0]
98
-
99
- if pcs:
100
- end = datetime.fromtimestamp(pcs.presentation_timestamp / 1000)
101
- end = end + timedelta(hours=-1)
102
-
103
- if isinstance(start, datetime) and isinstance(end, datetime) and len(text):
104
- si = si + 1
105
- sub_output = str(si) + "\n"
106
- sub_output += start.strftime("%H:%M:%S,%f")[0:12] + \
107
- " --> " + end.strftime("%H:%M:%S,%f")[0:12] + "\n"
108
- sub_output += text + "\n\n"
109
-
110
- output += sub_output
111
- start = end = text = None
112
- i = i + 1
113
-
114
- except Exception as e:
115
- print(e)
116
- exit(1)
117
-
118
- f = open(output_file, "w")
119
- f.write(output)
120
- f.close()
121
- print(f"Saved to: {output_file}")
1
+ #!/usr/bin/env python3
2
+
3
+ import argparse
4
+ import re
5
+ from datetime import datetime, timedelta
6
+
7
+ import pytesseract
8
+ from imagemaker import make_image
9
+ from pgsreader import PGSReader
10
+ from PIL import Image, ImageOps
11
+
12
+ from Libraries.SubZero.post_processing import CommonFixes, FixOCR
13
+
14
+ parser = argparse.ArgumentParser(description='Convert PGS subtitles to SubRip format.')
15
+
16
+ parser.add_argument('input', type=str, help="The input file (a .sup file).")
17
+ parser.add_argument('--output', type=str, help="The output file (a .srt file).")
18
+ parser.add_argument('--oem', type=int, help="The OCR Engine Mode to use (Default: 1).", default=1, choices=range(4))
19
+ parser.add_argument('--language', type=str, help="The language to use (Default: eng).", default='eng')
20
+ parser.add_argument('--fix_common', help='Fixes common whitespace/punctuation issues.',
21
+ dest='fix_common', action='store_true')
22
+ parser.add_argument('--fix_common_ocr', help='Fixes common OCR issues for supported languages.',
23
+ dest='fix_ocr', action='store_true')
24
+
25
+ args = parser.parse_args()
26
+
27
+ assert args.input is not None
28
+
29
+ # Unescape escaped spaces
30
+ file = args.input.replace("\\ ", " ")
31
+
32
+ print(f"Parsing: {file}")
33
+
34
+ # Load a PGS/SUP file.
35
+ pgs = PGSReader(file)
36
+
37
+ # Set index
38
+ i = 0
39
+
40
+ # Complete subtitle track index
41
+ si = 0
42
+
43
+ tesseract_lang = args.language
44
+ tesseract_config = f"-c tessedit_char_blacklist=[] --psm 6 --oem {args.oem}"
45
+
46
+ # If an output file for the subrip output is provided, use that.
47
+ # Otherwise remove the ".sup" extension from the input and append
48
+ # ".srt".
49
+ output_file = args.output if args.output is not None else (args.input.replace('.sup', '') + '.srt')
50
+
51
+ # SubRip output
52
+ output = ""
53
+
54
+ fix_common = CommonFixes() if args.fix_common else None
55
+ fix_ocr = FixOCR(args.language) if args.fix_ocr else None
56
+
57
+ # Iterate the pgs generator
58
+ for ds in pgs.iter_displaysets():
59
+ try:
60
+ # If set has image, parse the image
61
+ if ds.has_image:
62
+ # Get Palette Display Segment
63
+ pds = ds.pds[0]
64
+ # Get Object Display Segment
65
+ ods = ds.ods[0]
66
+
67
+ if pds and ods:
68
+ # Create and show the bitmap image and convert it to RGBA
69
+ src = make_image(ods, pds).convert('RGBA')
70
+
71
+ # Create grayscale image with black background
72
+ img = Image.new("L", src.size, "BLACK")
73
+ # Paste the subtitle bitmap
74
+ img.paste(src, (0, 0), src)
75
+ # Invert images so the text is readable by Tesseract
76
+ img = ImageOps.invert(img)
77
+
78
+ # Parse the image with tesesract
79
+ text = pytesseract.image_to_string(img, lang=tesseract_lang, config=tesseract_config).strip()
80
+
81
+ # Replace "|" with "I"
82
+ # Works better than blacklisting "|" in Tesseract,
83
+ # which results in I becoming "!" "i" and "1"
84
+ text = re.sub(r'[|/\\]', 'I', text)
85
+ text = re.sub(r'[_]', 'L', text)
86
+
87
+ if args.fix_common:
88
+ text = fix_common.process(text)
89
+ if args.fix_ocr:
90
+ text = fix_ocr.modify(text)
91
+
92
+ start = datetime.fromtimestamp(ods.presentation_timestamp / 1000)
93
+ start = start + timedelta(hours=-1)
94
+
95
+ else:
96
+ # Get Presentation Composition Segment
97
+ pcs = ds.pcs[0]
98
+
99
+ if pcs:
100
+ end = datetime.fromtimestamp(pcs.presentation_timestamp / 1000)
101
+ end = end + timedelta(hours=-1)
102
+
103
+ if isinstance(start, datetime) and isinstance(end, datetime) and len(text):
104
+ si = si + 1
105
+ sub_output = str(si) + "\n"
106
+ sub_output += start.strftime("%H:%M:%S,%f")[0:12] + \
107
+ " --> " + end.strftime("%H:%M:%S,%f")[0:12] + "\n"
108
+ sub_output += text + "\n\n"
109
+
110
+ output += sub_output
111
+ start = end = text = None
112
+ i = i + 1
113
+
114
+ except Exception as e:
115
+ print(e)
116
+ exit(1)
117
+
118
+ f = open(output_file, "w")
119
+ f.write(output)
120
+ f.close()
121
+ print(f"Saved to: {output_file}")