auto-editor 28.1.0__py3-none-any.whl → 29.0.1__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.
Files changed (60) hide show
  1. auto_editor/__init__.py +3 -1
  2. auto_editor/__main__.py +31 -497
  3. auto_editor/cli.py +12 -0
  4. {auto_editor-28.1.0.dist-info → auto_editor-29.0.1.dist-info}/METADATA +5 -6
  5. auto_editor-29.0.1.dist-info/RECORD +9 -0
  6. auto_editor-29.0.1.dist-info/entry_points.txt +2 -0
  7. {auto_editor-28.1.0.dist-info → auto_editor-29.0.1.dist-info}/top_level.txt +0 -1
  8. auto_editor/analyze.py +0 -393
  9. auto_editor/cmds/__init__.py +0 -0
  10. auto_editor/cmds/cache.py +0 -69
  11. auto_editor/cmds/desc.py +0 -32
  12. auto_editor/cmds/info.py +0 -213
  13. auto_editor/cmds/levels.py +0 -199
  14. auto_editor/cmds/palet.py +0 -29
  15. auto_editor/cmds/repl.py +0 -113
  16. auto_editor/cmds/subdump.py +0 -72
  17. auto_editor/cmds/test.py +0 -816
  18. auto_editor/edit.py +0 -560
  19. auto_editor/exports/__init__.py +0 -0
  20. auto_editor/exports/fcp11.py +0 -195
  21. auto_editor/exports/fcp7.py +0 -313
  22. auto_editor/exports/json.py +0 -63
  23. auto_editor/exports/kdenlive.py +0 -322
  24. auto_editor/exports/shotcut.py +0 -147
  25. auto_editor/ffwrapper.py +0 -187
  26. auto_editor/help.py +0 -224
  27. auto_editor/imports/__init__.py +0 -0
  28. auto_editor/imports/fcp7.py +0 -275
  29. auto_editor/imports/json.py +0 -234
  30. auto_editor/json.py +0 -297
  31. auto_editor/lang/__init__.py +0 -0
  32. auto_editor/lang/libintrospection.py +0 -10
  33. auto_editor/lang/libmath.py +0 -23
  34. auto_editor/lang/palet.py +0 -724
  35. auto_editor/lang/stdenv.py +0 -1179
  36. auto_editor/lib/__init__.py +0 -0
  37. auto_editor/lib/contracts.py +0 -235
  38. auto_editor/lib/data_structs.py +0 -278
  39. auto_editor/lib/err.py +0 -2
  40. auto_editor/make_layers.py +0 -315
  41. auto_editor/preview.py +0 -93
  42. auto_editor/render/__init__.py +0 -0
  43. auto_editor/render/audio.py +0 -517
  44. auto_editor/render/subtitle.py +0 -205
  45. auto_editor/render/video.py +0 -307
  46. auto_editor/timeline.py +0 -331
  47. auto_editor/utils/__init__.py +0 -0
  48. auto_editor/utils/bar.py +0 -142
  49. auto_editor/utils/chunks.py +0 -2
  50. auto_editor/utils/cmdkw.py +0 -206
  51. auto_editor/utils/container.py +0 -101
  52. auto_editor/utils/func.py +0 -128
  53. auto_editor/utils/log.py +0 -126
  54. auto_editor/utils/types.py +0 -277
  55. auto_editor/vanparse.py +0 -313
  56. auto_editor-28.1.0.dist-info/RECORD +0 -57
  57. auto_editor-28.1.0.dist-info/entry_points.txt +0 -6
  58. docs/build.py +0 -70
  59. {auto_editor-28.1.0.dist-info → auto_editor-29.0.1.dist-info}/WHEEL +0 -0
  60. {auto_editor-28.1.0.dist-info → auto_editor-29.0.1.dist-info}/licenses/LICENSE +0 -0
@@ -1,101 +0,0 @@
1
- from __future__ import annotations
2
-
3
- from dataclasses import dataclass
4
- from typing import TypedDict
5
-
6
- from av import Codec, open
7
-
8
- from auto_editor.utils.log import Log
9
-
10
-
11
- class DictContainer(TypedDict, total=False):
12
- max_videos: int | None
13
- max_audios: int | None
14
- max_subtitles: int | None
15
- samplerate: list[int] | None
16
-
17
-
18
- @dataclass(slots=True)
19
- class Container:
20
- allow_image: bool
21
- vcodecs: set[str]
22
- acodecs: set[str]
23
- scodecs: set[str]
24
- default_vid: str
25
- default_aud: str
26
- default_sub: str
27
- max_videos: int | None = None
28
- max_audios: int | None = None
29
- max_subtitles: int | None = None
30
- samplerate: list[int] | None = None # Any samplerate is allowed
31
-
32
-
33
- containers: dict[str, DictContainer] = {
34
- "aac": {"max_audios": 1},
35
- "adts": {"max_audios": 1},
36
- "ass": {"max_subtitles": 1},
37
- "ssa": {"max_subtitles": 1},
38
- "apng": {"max_videos": 1},
39
- "gif": {"max_videos": 1},
40
- "wav": {"max_audios": 1},
41
- "ast": {"max_audios": 1},
42
- "mp3": {"max_audios": 1},
43
- "flac": {"max_audios": 1},
44
- "srt": {"max_subtitles": 1},
45
- "vtt": {"max_subtitles": 1},
46
- "swf": {"samplerate": [44100, 22050, 11025]},
47
- }
48
-
49
-
50
- def codec_type(x: str) -> str:
51
- if x in {"vp9", "vp8", "h264", "hevc", "av1", "gif", "apng"}:
52
- return "video"
53
- if x in {"aac", "flac", "mp3"}:
54
- return "audio"
55
- if x in {"ass", "ssa", "srt"}:
56
- return "subtitle"
57
-
58
- try:
59
- return Codec(x, "w").type
60
- except Exception:
61
- return ""
62
-
63
-
64
- def container_constructor(ext: str, log: Log) -> Container:
65
- try:
66
- container = open(f".{ext}", "w")
67
- except ValueError:
68
- log.error(f"Could not find a suitable format for extension: {ext}")
69
-
70
- codecs = container.supported_codecs
71
- if ext == "webm":
72
- vdefault = "vp9"
73
- else:
74
- vdefault = container.default_video_codec
75
- adefault = container.default_audio_codec
76
- sdefault = container.default_subtitle_codec
77
- if sdefault == "none" and ext == "mp4":
78
- sdefault = "srt"
79
-
80
- container.close()
81
- vcodecs = set()
82
- acodecs = set()
83
- scodecs = set()
84
-
85
- for codec in codecs:
86
- if ext == "wav" and codec == "aac":
87
- continue
88
- kind = codec_type(codec)
89
- if kind == "video":
90
- vcodecs.add(codec)
91
- if kind == "audio":
92
- acodecs.add(codec)
93
- if kind == "subtitle":
94
- scodecs.add(codec)
95
-
96
- allow_image = ext in {"mp4", "mkv"}
97
- kwargs = containers[ext] if ext in containers else {}
98
-
99
- return Container(
100
- allow_image, vcodecs, acodecs, scodecs, vdefault, adefault, sdefault, **kwargs
101
- )
auto_editor/utils/func.py DELETED
@@ -1,128 +0,0 @@
1
- from __future__ import annotations
2
-
3
- from typing import TYPE_CHECKING
4
-
5
- import numpy as np
6
-
7
- from auto_editor.utils.log import Log
8
- from auto_editor.utils.types import split_num_str
9
-
10
- if TYPE_CHECKING:
11
- from collections.abc import Callable
12
- from fractions import Fraction
13
-
14
- from numpy.typing import NDArray
15
-
16
- BoolList = NDArray[np.bool_]
17
- BoolOperand = Callable[[BoolList, BoolList], BoolList]
18
-
19
-
20
- def boolop(a: BoolList, b: BoolList, call: BoolOperand) -> BoolList:
21
- if len(a) > len(b):
22
- k = np.copy(b)
23
- k.resize(len(a))
24
- b = k
25
- if len(b) > len(a):
26
- k = np.copy(a)
27
- k.resize(len(b))
28
- a = k
29
-
30
- return call(a, b)
31
-
32
-
33
- def to_timecode(secs: float | Fraction, fmt: str) -> str:
34
- sign = ""
35
- if secs < 0:
36
- sign = "-"
37
- secs = -secs
38
-
39
- _m, _s = divmod(secs, 60)
40
- _h, _m = divmod(_m, 60)
41
- s, m, h = float(_s), int(_m), int(_h)
42
-
43
- if fmt == "webvtt":
44
- if h == 0:
45
- return f"{sign}{m:02d}:{s:06.3f}"
46
- return f"{sign}{h:02d}:{m:02d}:{s:06.3f}"
47
- if fmt in {"srt", "mov_text"}:
48
- return f"{sign}{h:02d}:{m:02d}:" + f"{s:06.3f}".replace(".", ",", 1)
49
- if fmt == "standard":
50
- return f"{sign}{h:02d}:{m:02d}:{s:06.3f}"
51
- if fmt == "ass":
52
- return f"{sign}{h:d}:{m:02d}:{s:05.2f}"
53
- if fmt == "rass":
54
- return f"{sign}{h:d}:{m:02d}:{s:02.0f}"
55
-
56
- raise ValueError("to_timecode: Unreachable")
57
-
58
-
59
- def mut_margin(arr: BoolList, start_m: int, end_m: int) -> None:
60
- # Find start and end indexes
61
- start_index = []
62
- end_index = []
63
- arrlen = len(arr)
64
- for j in range(1, arrlen):
65
- if arr[j] != arr[j - 1]:
66
- if arr[j]:
67
- start_index.append(j)
68
- else:
69
- end_index.append(j)
70
-
71
- # Apply margin
72
- if start_m > 0:
73
- for i in start_index:
74
- arr[max(i - start_m, 0) : i] = True
75
- if start_m < 0:
76
- for i in start_index:
77
- arr[i : min(i - start_m, arrlen)] = False
78
-
79
- if end_m > 0:
80
- for i in end_index:
81
- arr[i : min(i + end_m, arrlen)] = True
82
- if end_m < 0:
83
- for i in end_index:
84
- arr[max(i + end_m, 0) : i] = False
85
-
86
-
87
- def get_stdout(cmd: list[str]) -> str:
88
- from subprocess import DEVNULL, PIPE, Popen
89
-
90
- stdout = Popen(cmd, stdin=DEVNULL, stdout=PIPE, stderr=PIPE).communicate()[0]
91
- return stdout.decode("utf-8", "replace")
92
-
93
-
94
- def get_stdout_bytes(cmd: list[str]) -> bytes:
95
- from subprocess import DEVNULL, PIPE, Popen
96
-
97
- return Popen(cmd, stdin=DEVNULL, stdout=PIPE, stderr=PIPE).communicate()[0]
98
-
99
-
100
- def aspect_ratio(width: int, height: int) -> tuple[int, int]:
101
- if height == 0:
102
- return (0, 0)
103
-
104
- def gcd(a: int, b: int) -> int:
105
- while b:
106
- a, b = b, a % b
107
- return a
108
-
109
- c = gcd(width, height)
110
- return width // c, height // c
111
-
112
-
113
- def parse_bitrate(input_: str, log: Log) -> int:
114
- try:
115
- val, unit = split_num_str(input_)
116
- except Exception as e:
117
- log.error(e)
118
-
119
- if unit.lower() == "k":
120
- return int(val * 1000)
121
- if unit == "M":
122
- return int(val * 1_000_000)
123
- if unit == "G":
124
- return int(val * 1_000_000_000)
125
- if unit == "":
126
- return int(val)
127
-
128
- log.error(f"Unknown bitrate: {input_}")
auto_editor/utils/log.py DELETED
@@ -1,126 +0,0 @@
1
- import sys
2
- from datetime import timedelta
3
- from shutil import get_terminal_size, rmtree
4
- from tempfile import mkdtemp
5
- from time import perf_counter, sleep
6
- from typing import NoReturn
7
-
8
-
9
- class Log:
10
- __slots__ = ("is_debug", "quiet", "machine", "no_color", "_temp", "_ut", "_s")
11
-
12
- def __init__(
13
- self,
14
- is_debug: bool = False,
15
- quiet: bool = False,
16
- temp_dir: str | None = None,
17
- machine: bool = False,
18
- no_color: bool = True,
19
- ):
20
- self.is_debug = is_debug
21
- self.quiet = quiet
22
- self.machine = machine
23
- self.no_color = no_color
24
- self._temp: str | None = None
25
- self._ut = temp_dir
26
- self._s = 0 if self.quiet or self.machine else perf_counter()
27
-
28
- def debug(self, message: object) -> None:
29
- if self.is_debug:
30
- self.conwrite("")
31
- sys.stderr.write(f"Debug: {message}\n")
32
-
33
- @property
34
- def temp(self) -> str:
35
- if self._temp is not None:
36
- return self._temp
37
-
38
- if self._ut is None:
39
- result = mkdtemp()
40
- else:
41
- import os.path
42
- from os import listdir, mkdir
43
-
44
- if os.path.isfile(self._ut):
45
- self.error("Temp directory cannot be an already existing file.")
46
-
47
- if os.path.isdir(self._ut):
48
- if len(listdir(self._ut)) != 0:
49
- self.error("Temp directory should be empty!")
50
- else:
51
- mkdir(self._ut)
52
- result = self._ut
53
-
54
- self.debug(f"Temp Directory: {result}")
55
- self._temp = result
56
- return result
57
-
58
- def cleanup(self) -> None:
59
- if self._temp is None:
60
- return
61
- try:
62
- rmtree(self._temp)
63
- self.debug("Removed Temp Directory.")
64
- except FileNotFoundError:
65
- pass
66
- except PermissionError:
67
- sleep(0.1)
68
- try:
69
- rmtree(self._temp)
70
- self.debug("Removed Temp Directory.")
71
- except Exception as e:
72
- self.debug(f"Failed to delete temp dir:\n{e}")
73
-
74
- def conwrite(self, message: str) -> None:
75
- if self.machine:
76
- print(message, flush=True)
77
- elif not self.quiet:
78
- buffer = " " * (get_terminal_size().columns - len(message) - 3)
79
- sys.stdout.write(f" {message}{buffer}\r")
80
-
81
- def print(self, message: str) -> None:
82
- if not self.quiet:
83
- self.conwrite("")
84
- sys.stdout.write(f"{message}\n")
85
-
86
- def warning(self, message: str) -> None:
87
- if not self.quiet:
88
- self.conwrite("")
89
- sys.stderr.write(f"Warning! {message}\n")
90
-
91
- def stop_timer(self) -> None:
92
- if not self.quiet and not self.machine:
93
- second_len = round(perf_counter() - self._s, 2)
94
- minute_len = timedelta(seconds=round(second_len))
95
-
96
- sys.stdout.write(f"Finished. took {second_len} seconds ({minute_len})\n")
97
-
98
- @staticmethod
99
- def deprecated(message: str) -> None:
100
- sys.stderr.write(f"\033[1m\033[33m{message}\033[0m\n")
101
-
102
- def error(self, message: str | Exception) -> NoReturn:
103
- if self.is_debug:
104
- self.cleanup()
105
- if isinstance(message, str):
106
- raise Exception(message)
107
- raise message
108
-
109
- self.conwrite("")
110
- if self.no_color:
111
- sys.stderr.write(f"Error! {message}\n")
112
- else:
113
- sys.stderr.write(f"\033[31;40mError! {message}\033[0m\n")
114
-
115
- self.cleanup()
116
- from platform import system
117
-
118
- if system() == "Linux":
119
- sys.exit(1)
120
- else:
121
- try:
122
- sys.exit(1)
123
- except SystemExit:
124
- import os
125
-
126
- os._exit(1)
@@ -1,277 +0,0 @@
1
- from __future__ import annotations
2
-
3
- import re
4
- from fractions import Fraction
5
-
6
-
7
- class CoerceError(Exception):
8
- pass
9
-
10
-
11
- def split_num_str(val: str | float) -> tuple[float, str]:
12
- if isinstance(val, float | int):
13
- return val, ""
14
-
15
- index = 0
16
- for char in val:
17
- if char not in "0123456789_ .-":
18
- break
19
- index += 1
20
- num, unit = val[:index], val[index:]
21
- try:
22
- float(num)
23
- except ValueError:
24
- raise CoerceError(f"Invalid number: '{val}'")
25
- return float(num), unit
26
-
27
-
28
- # Numbers: 0, 1, 2, 3, ...
29
- def natural(val: str | float) -> int:
30
- num, unit = split_num_str(val)
31
- if unit != "":
32
- raise CoerceError(f"'{val}': Natural does not allow units.")
33
- if not isinstance(num, int) and not num.is_integer():
34
- raise CoerceError(f"'{val}': Natural must be a valid integer.")
35
- if num < 0:
36
- raise CoerceError(f"'{val}': Natural cannot be negative.")
37
- return int(num)
38
-
39
-
40
- def number(val: str | float) -> float:
41
- if isinstance(val, str) and "/" in val:
42
- nd = val.split("/")
43
- if len(nd) != 2:
44
- raise CoerceError(f"'{val}': One divisor allowed.")
45
- vs = []
46
- for v in nd:
47
- try:
48
- vs.append(int(v))
49
- except ValueError:
50
- raise CoerceError(
51
- f"'{val}': Numerator and Denominator must be integers."
52
- )
53
- if vs[1] == 0:
54
- raise CoerceError(f"'{val}': Denominator must not be zero.")
55
- return vs[0] / vs[1]
56
-
57
- num, unit = split_num_str(val)
58
- if unit == "%":
59
- return num / 100
60
- if unit == "":
61
- return num
62
- raise CoerceError(f"Unknown unit: '{unit}'")
63
-
64
-
65
- def frame_rate(val: str) -> Fraction:
66
- if val == "ntsc":
67
- return Fraction(30000, 1001)
68
- if val == "ntsc_film":
69
- return Fraction(24000, 1001)
70
- if val == "pal":
71
- return Fraction(25)
72
- if val == "film":
73
- return Fraction(24)
74
- return Fraction(val)
75
-
76
-
77
- def time(val: str, tb: Fraction) -> int:
78
- if ":" in val:
79
- boxes = val.split(":")
80
- if len(boxes) == 2:
81
- return round((int(boxes[0]) * 60 + float(boxes[1])) * tb)
82
- if len(boxes) == 3:
83
- return round(
84
- (int(boxes[0]) * 3600 + int(boxes[1]) * 60 + float(boxes[2])) * tb
85
- )
86
- raise CoerceError(f"'{val}': Invalid time format")
87
-
88
- num, unit = split_num_str(val)
89
- if unit in {"s", "sec", "secs", "second", "seconds"}:
90
- return round(num * tb)
91
- if unit in {"min", "mins", "minute", "minutes"}:
92
- return round(num * tb * 60)
93
- if unit == "hour":
94
- return round(num * tb * 3600)
95
-
96
- if unit != "":
97
- raise CoerceError(f"'{val}': Time format got unknown unit: `{unit}`")
98
- if not num.is_integer():
99
- raise CoerceError(f"'{val}': Time format expects: int?")
100
- return int(num)
101
-
102
-
103
- def parse_color(val: str) -> str:
104
- """
105
- Convert a color str into an RGB tuple
106
-
107
- Accepts:
108
- - color names (black, red, blue)
109
- - 3 digit hex codes (#FFF, #3AE)
110
- - 6 digit hex codes (#3F0401, #005601)
111
- """
112
-
113
- color = val.lower()
114
-
115
- if color in colormap:
116
- color = colormap[color]
117
-
118
- if re.match("#[a-f0-9]{3}$", color):
119
- return "#" + "".join([x * 2 for x in color[1:]])
120
-
121
- if re.match("#[a-f0-9]{6}$", color):
122
- return color
123
-
124
- raise ValueError(f"Invalid Color: '{color}'")
125
-
126
-
127
- colormap = {
128
- # Taken from https://www.w3.org/TR/css-color-4/#named-color
129
- "aliceblue": "#f0f8ff",
130
- "antiquewhite": "#faebd7",
131
- "aqua": "#00ffff",
132
- "aquamarine": "#7fffd4",
133
- "azure": "#f0ffff",
134
- "beige": "#f5f5dc",
135
- "bisque": "#ffe4c4",
136
- "black": "#000000",
137
- "blanchedalmond": "#ffebcd",
138
- "blue": "#0000ff",
139
- "blueviolet": "#8a2be2",
140
- "brown": "#a52a2a",
141
- "burlywood": "#deb887",
142
- "cadetblue": "#5f9ea0",
143
- "chartreuse": "#7fff00",
144
- "chocolate": "#d2691e",
145
- "coral": "#ff7f50",
146
- "cornflowerblue": "#6495ed",
147
- "cornsilk": "#fff8dc",
148
- "crimson": "#dc143c",
149
- "cyan": "#00ffff",
150
- "darkblue": "#00008b",
151
- "darkcyan": "#008b8b",
152
- "darkgoldenrod": "#b8860b",
153
- "darkgray": "#a9a9a9",
154
- "darkgrey": "#a9a9a9",
155
- "darkgreen": "#006400",
156
- "darkkhaki": "#bdb76b",
157
- "darkmagenta": "#8b008b",
158
- "darkolivegreen": "#556b2f",
159
- "darkorange": "#ff8c00",
160
- "darkorchid": "#9932cc",
161
- "darkred": "#8b0000",
162
- "darksalmon": "#e9967a",
163
- "darkseagreen": "#8fbc8f",
164
- "darkslateblue": "#483d8b",
165
- "darkslategray": "#2f4f4f",
166
- "darkslategrey": "#2f4f4f",
167
- "darkturquoise": "#00ced1",
168
- "darkviolet": "#9400d3",
169
- "deeppink": "#ff1493",
170
- "deepskyblue": "#00bfff",
171
- "dimgray": "#696969",
172
- "dimgrey": "#696969",
173
- "dodgerblue": "#1e90ff",
174
- "firebrick": "#b22222",
175
- "floralwhite": "#fffaf0",
176
- "forestgreen": "#228b22",
177
- "fuchsia": "#ff00ff",
178
- "gainsboro": "#dcdcdc",
179
- "ghostwhite": "#f8f8ff",
180
- "gold": "#ffd700",
181
- "goldenrod": "#daa520",
182
- "gray": "#808080",
183
- "grey": "#808080",
184
- "green": "#008000",
185
- "greenyellow": "#adff2f",
186
- "honeydew": "#f0fff0",
187
- "hotpink": "#ff69b4",
188
- "indianred": "#cd5c5c",
189
- "indigo": "#4b0082",
190
- "ivory": "#fffff0",
191
- "khaki": "#f0e68c",
192
- "lavender": "#e6e6fa",
193
- "lavenderblush": "#fff0f5",
194
- "lawngreen": "#7cfc00",
195
- "lemonchiffon": "#fffacd",
196
- "lightblue": "#add8e6",
197
- "lightcoral": "#f08080",
198
- "lightcyan": "#e0ffff",
199
- "lightgoldenrodyellow": "#fafad2",
200
- "lightgreen": "#90ee90",
201
- "lightgray": "#d3d3d3",
202
- "lightgrey": "#d3d3d3",
203
- "lightpink": "#ffb6c1",
204
- "lightsalmon": "#ffa07a",
205
- "lightseagreen": "#20b2aa",
206
- "lightskyblue": "#87cefa",
207
- "lightslategray": "#778899",
208
- "lightslategrey": "#778899",
209
- "lightsteelblue": "#b0c4de",
210
- "lightyellow": "#ffffe0",
211
- "lime": "#00ff00",
212
- "limegreen": "#32cd32",
213
- "linen": "#faf0e6",
214
- "magenta": "#ff00ff",
215
- "maroon": "#800000",
216
- "mediumaquamarine": "#66cdaa",
217
- "mediumblue": "#0000cd",
218
- "mediumorchid": "#ba55d3",
219
- "mediumpurple": "#9370db",
220
- "mediumseagreen": "#3cb371",
221
- "mediumslateblue": "#7b68ee",
222
- "mediumspringgreen": "#00fa9a",
223
- "mediumturquoise": "#48d1cc",
224
- "mediumvioletred": "#c71585",
225
- "midnightblue": "#191970",
226
- "mintcream": "#f5fffa",
227
- "mistyrose": "#ffe4e1",
228
- "moccasin": "#ffe4b5",
229
- "navajowhite": "#ffdead",
230
- "navy": "#000080",
231
- "oldlace": "#fdf5e6",
232
- "olive": "#808000",
233
- "olivedrab": "#6b8e23",
234
- "orange": "#ffa500",
235
- "orangered": "#ff4500",
236
- "orchid": "#da70d6",
237
- "palegoldenrod": "#eee8aa",
238
- "palegreen": "#98fb98",
239
- "paleturquoise": "#afeeee",
240
- "palevioletred": "#db7093",
241
- "papayawhip": "#ffefd5",
242
- "peachpuff": "#ffdab9",
243
- "peru": "#cd853f",
244
- "pink": "#ffc0cb",
245
- "plum": "#dda0dd",
246
- "powderblue": "#b0e0e6",
247
- "purple": "#800080",
248
- "rebeccapurple": "#663399",
249
- "red": "#ff0000",
250
- "rosybrown": "#bc8f8f",
251
- "royalblue": "#4169e1",
252
- "saddlebrown": "#8b4513",
253
- "salmon": "#fa8072",
254
- "sandybrown": "#f4a460",
255
- "seagreen": "#2e8b57",
256
- "seashell": "#fff5ee",
257
- "sienna": "#a0522d",
258
- "silver": "#c0c0c0",
259
- "skyblue": "#87ceeb",
260
- "slateblue": "#6a5acd",
261
- "slategray": "#708090",
262
- "slategrey": "#708090",
263
- "snow": "#fffafa",
264
- "springgreen": "#00ff7f",
265
- "steelblue": "#4682b4",
266
- "tan": "#d2b48c",
267
- "teal": "#008080",
268
- "thistle": "#d8bfd8",
269
- "tomato": "#ff6347",
270
- "turquoise": "#40e0d0",
271
- "violet": "#ee82ee",
272
- "wheat": "#f5deb3",
273
- "white": "#ffffff",
274
- "whitesmoke": "#f5f5f5",
275
- "yellow": "#ffff00",
276
- "yellowgreen": "#9acd32",
277
- }