diff --git a/AESFile/aesfile.py b/AESFile/aesfile.py index a44b3c9..c63d396 100644 --- a/AESFile/aesfile.py +++ b/AESFile/aesfile.py @@ -9,10 +9,24 @@ import os from voussoirkit import bytestring +# 128 bits BLOCK_SIZE = 32 - +KEY_SIZE = 32 SEEK_END = 2 +def decrypt_data(aes, data): + data = aes.decrypt(data) + pad_byte = data[-1:] + data = data.rstrip(pad_byte) + return data + +def encrypt_data(aes, data): + pad_byte = (data[-1] + 1) % 256 + pad_length = BLOCK_SIZE - (len(data) % BLOCK_SIZE) + data += (bytes([pad_byte]) * pad_length) + data = aes.encrypt(data) + return data + def decrypt_file(aes, input_handle, output_handle): current_pos = input_handle.tell() input_size = input_handle.seek(0, SEEK_END) - current_pos @@ -42,8 +56,7 @@ def encrypt_file(aes, input_handle, output_handle): last_byte = chunk[-1] if len(chunk) < BLOCK_SIZE: pad_byte = (last_byte + 1) % 256 - pad_byte = chr(pad_byte) - pad_byte = pad_byte.encode('ascii') + pad_byte = bytes([pad_byte]) chunk += pad_byte * (BLOCK_SIZE - len(chunk)) done = True bytes_read += len(chunk) @@ -60,7 +73,7 @@ def encrypt_argparse(args): input_handle = open(args.input, 'rb') output_handle = open(args.output, 'wb') - password = hashit(args.password, 32) + password = hashit(args.password) initialization_vector = os.urandom(16) aes = AES.new(password, mode=3, IV=initialization_vector) output_handle.write(initialization_vector) @@ -71,15 +84,14 @@ def decrypt_argparse(args): input_handle = open(args.input, 'rb') output_handle = open(args.output, 'wb') - password = hashit(args.password, 32) + password = hashit(args.password) initialization_vector = input_handle.read(16) aes = AES.new(password, mode=3, IV=initialization_vector) decrypt_file(aes, input_handle, output_handle) -def hashit(text, length=None): +def hashit(text): h = hashlib.sha512(text.encode('utf-8')).hexdigest() - if length is not None: - h = h[:length] + h = h[:BLOCK_SIZE] return h def main(argv): @@ -102,4 +114,4 @@ def main(argv): args.func(args) if __name__ == '__main__': - main(sys.argv[1:]) \ No newline at end of file + main(sys.argv[1:]) diff --git a/Downloady/downloady.py b/Downloady/downloady.py index 2d2d7ee..91c8246 100644 --- a/Downloady/downloady.py +++ b/Downloady/downloady.py @@ -23,7 +23,7 @@ FILENAME_BADCHARS = '*?"<>|\r' last_request = 0 CHUNKSIZE = 4 * bytestring.KIBIBYTE -TIMEOUT = 600 +TIMEOUT = 60 TEMP_EXTENSION = '.downloadytemp' PRINT_LIMITER = ratelimiter.Ratelimiter(allowance=5, mode='reject') @@ -35,11 +35,12 @@ def download_file( auth=None, bytespersecond=None, callback_progress=None, + do_head=True, headers=None, overwrite=False, raise_for_undersized=True, + timeout=None, verbose=False, - **get_kwargs ): headers = headers or {} @@ -61,13 +62,20 @@ def download_file( localname, auth=auth, bytespersecond=bytespersecond, + callback_progress=callback_progress, + do_head=do_head, headers=headers, overwrite=overwrite, + raise_for_undersized=raise_for_undersized, + timeout=timeout, ) #print(plan) if plan is None: return + return download_plan(plan) + +def download_plan(plan): localname = plan['download_into'] directory = os.path.split(localname)[0] if directory != '': @@ -77,7 +85,7 @@ def download_file( file_handle.seek(plan['seek_to']) if plan['header_range_min'] is not None: - headers['range'] = 'bytes={min}-{max}'.format( + plan['headers']['range'] = 'bytes={min}-{max}'.format( min=plan['header_range_min'], max=plan['header_range_max'], ) @@ -89,7 +97,20 @@ def download_file( else: bytes_downloaded = 0 - download_stream = request('get', url, stream=True, headers=headers, auth=auth, **get_kwargs) + download_stream = request( + 'get', + plan['url'], + stream=True, + auth=plan['auth'], + headers=plan['headers'], + timeout=plan['timeout'], + ) + + if plan['remote_total_bytes'] is None: + # Since we didn't do a head, let's fill this in now. + plan['remote_total_bytes'] = int(download_stream.headers.get('Content-Length', 0)) + + callback_progress = plan['callback_progress'] if callback_progress is not None: callback_progress = callback_progress(plan['remote_total_bytes']) @@ -108,7 +129,7 @@ def download_file( if os.devnull not in [localname, plan['real_localname']]: localsize = os.path.getsize(localname) undersized = plan['plan_type'] != 'partial' and localsize < plan['remote_total_bytes'] - if raise_for_undersized and undersized: + if plan['raise_for_undersized'] and undersized: message = 'File does not contain expected number of bytes. Received {size} / {total}' message = message.format(size=localsize, total=plan['remote_total_bytes']) raise Exception(message) @@ -121,12 +142,17 @@ def download_file( def prepare_plan( url, localname, - auth, - bytespersecond, - headers, - overwrite, + auth=None, + bytespersecond=None, + callback_progress=None, + do_head=True, + headers=None, + overwrite=False, + raise_for_undersized=True, + timeout=TIMEOUT, ): # Chapter 1: File existence + headers = headers or {} user_provided_range = 'range' in headers real_localname = localname temp_localname = localname + TEMP_EXTENSION @@ -163,21 +189,34 @@ def prepare_plan( temp_headers = headers temp_headers.update({'range': 'bytes=0-'}) - # I'm using a GET instead of an actual HEAD here because some servers respond - # differently, even though they're not supposed to. - head = request('get', url, stream=True, headers=temp_headers, auth=auth) - remote_total_bytes = int(head.headers.get('content-length', 0)) - server_respects_range = (head.status_code == 206 and 'content-range' in head.headers) - head.connection.close() + if do_head: + # I'm using a GET instead of an actual HEAD here because some servers respond + # differently, even though they're not supposed to. + head = request('get', url, stream=True, headers=temp_headers, auth=auth) + remote_total_bytes = int(head.headers.get('content-length', 0)) + server_respects_range = (head.status_code == 206 and 'content-range' in head.headers) + head.connection.close() + else: + remote_total_bytes = None + server_respects_range = False if user_provided_range and not server_respects_range: - raise Exception('Server did not respect your range header') + if not do_head: + raise Exception('Cannot determine range support without the head request') + else: + raise Exception('Server did not respect your range header') # Chapter 5: Plan definitions plan_base = { + 'url': url, + 'auth': auth, + 'callback_progress': callback_progress, 'limiter': limiter, + 'headers': headers, 'real_localname': real_localname, + 'raise_for_undersized': raise_for_undersized, 'remote_total_bytes': remote_total_bytes, + 'timeout': timeout, } plan_fulldownload = dict( plan_base, @@ -373,8 +412,10 @@ def download_argparse(args): localname=args.localname, bytespersecond=bytespersecond, callback_progress=callback, + do_head=args.no_head is False, headers=headers, overwrite=args.overwrite, + timeout=int(args.timeout), verbose=True, ) @@ -388,6 +429,8 @@ if __name__ == '__main__': parser.add_argument('-bps', '--bytespersecond', dest='bytespersecond', default=None) parser.add_argument('-ow', '--overwrite', dest='overwrite', action='store_true') parser.add_argument('-r', '--range', dest='range', default=None) + parser.add_argument('--timeout', dest='timeout', default=TIMEOUT) + parser.add_argument('--no-head', dest='no_head', action='store_true') parser.set_defaults(func=download_argparse) args = parser.parse_args() diff --git a/Pathclass/pathclass.py b/Pathclass/pathclass.py index f4600b6..9e2eb87 100644 --- a/Pathclass/pathclass.py +++ b/Pathclass/pathclass.py @@ -1,25 +1,25 @@ import glob import os + class Path: ''' I started to use pathlib.Path, but it was too much of a pain. ''' def __init__(self, path): - path = os.path.normpath(path) - path = os.path.abspath(path) - self.absolute_path = path + if isinstance(path, Path): + self.absolute_path = path.absolute_path + else: + path = os.path.normpath(path) + path = os.path.abspath(path) + self.absolute_path = path def __contains__(self, other): - this = os.path.normcase(self.absolute_path) - that = os.path.normcase(other.absolute_path) - return that.startswith(this) + return other.normcase.startswith(self.normcase) def __eq__(self, other): if not hasattr(other, 'absolute_path'): return False - this = os.path.normcase(self.absolute_path) - that = os.path.normcase(other.absolute_path) - return this == that + return self.normcase == other.normcase def __hash__(self): return hash(os.path.normcase(self.absolute_path)) @@ -35,6 +35,10 @@ class Path: self.absolute_path = get_path_casing(self.absolute_path) return self.absolute_path + @property + def depth(self): + return len(self.absolute_path.split(os.sep)) + @property def exists(self): return os.path.exists(self.absolute_path) @@ -51,6 +55,10 @@ class Path: def is_link(self): return os.path.islink(self.absolute_path) + @property + def normcase(self): + return os.path.normcase(self.absolute_path) + @property def parent(self): parent = os.path.dirname(self.absolute_path) @@ -59,10 +67,21 @@ class Path: @property def relative_path(self): - relative = self.absolute_path - relative = relative.replace(os.getcwd(), '') - relative = relative.lstrip(os.sep) - return relative + cwd = Path(os.getcwd()) + self.correct_case() + if self.absolute_path == cwd: + return '.' + + if self in cwd: + return self.absolute_path.replace(cwd.absolute_path, '.') + + common = common_path([os.getcwd(), self.absolute_path], fallback=None) + if common is None: + return self.absolute_path + backsteps = cwd.depth - common.depth + backsteps = os.sep.join('..' for x in range(backsteps)) + print('hi') + return self.absolute_path.replace(common.absolute_path, backsteps) @property def size(self): @@ -80,6 +99,34 @@ class Path: return Path(os.path.join(self.absolute_path, basename)) +def common_path(paths, fallback): + ''' + Given a list of file paths, determine the deepest path which all + have in common. + ''' + if isinstance(paths, (str, Path)): + raise TypeError('`paths` must be a collection') + paths = [Path(f) for f in paths] + + if len(paths) == 0: + raise ValueError('Empty list') + + if hasattr(paths, 'pop'): + model = paths.pop() + else: + model = paths[0] + paths = paths[1:] + + while True: + if all(f in model for f in paths): + return model + parent = model.parent + if parent == model: + # We just processed the root, and now we're stuck at the root. + # Which means there was no common path. + return fallback + model = parent + def get_path_casing(path): ''' Take what is perhaps incorrectly cased input and get the path's actual @@ -89,8 +136,21 @@ def get_path_casing(path): Ethan Furman http://stackoverflow.com/a/7133137/5430534 xvorsx http://stackoverflow.com/a/14742779/5430534 ''' - if isinstance(path, Path): - path = path.absolute_path + if not isinstance(path, Path): + path = Path(path) + + # Nonexistent paths don't glob correctly. If the input is a nonexistent + # subpath of an existing path, we have to glob the existing portion first, + # and then attach the fake portion again at the end. + input_path = path + while not path.exists: + parent = path.parent + if path == parent: + # We're stuck at a fake root. + return input_path.absolute_path + path = parent + + path = path.absolute_path (drive, subpath) = os.path.splitdrive(path) drive = drive.upper() @@ -99,11 +159,17 @@ def get_path_casing(path): pattern = [glob_patternize(piece) for piece in subpath.split(os.sep)] pattern = os.sep.join(pattern) pattern = drive + os.sep + pattern - #print(pattern) + try: - return glob.glob(pattern)[0] + cased = glob.glob(pattern)[0] + imaginary_portion = input_path.normcase + real_portion = os.path.normcase(cased) + imaginary_portion = imaginary_portion.replace(real_portion, '') + imaginary_portion = imaginary_portion.lstrip(os.sep) + cased = os.path.join(cased, imaginary_portion) + return cased except IndexError: - return path + return input_path def glob_patternize(piece): ''' @@ -111,10 +177,15 @@ def glob_patternize(piece): correct path name, while guaranteeing that the only result will be the correct path. Special cases are: - !, because in glob syntax, [!x] tells glob to look for paths that don't contain - "x". [!] is invalid syntax, so we pick the first non-! character to put - in the brackets. - [, because this starts a capture group + `!` + because in glob syntax, [!x] tells glob to look for paths that don't contain + "x", and [!] is invalid syntax. + `[`, `]` + because this starts a glob capture group + + so we pick the first non-special character to put in the brackets. + If the path consists entirely of these special characters, then the + casing doesn't need to be corrected anyway. ''' piece = glob.escape(piece) for character in piece: @@ -124,3 +195,13 @@ def glob_patternize(piece): piece = piece.replace(character, replacement, 1) break return piece + +def normalize_sep(path): + for char in ('\\', '/'): + if char != os.sep: + path = path.replace(char, os.sep) + path = path.rstrip(os.sep) + return path + +def system_root(): + return os.path.abspath(os.sep) diff --git a/Safeprint/safeprint.py b/Safeprint/safeprint.py new file mode 100644 index 0000000..51889d8 --- /dev/null +++ b/Safeprint/safeprint.py @@ -0,0 +1,18 @@ +''' +This function is slow and ugly, but I need a way to safely print unicode strings +on systems that don't support it without crippling those who do. +''' +def safeprint(text, file_handle=None): + for character in text: + try: + if file_handle: + file_handle.write(character) + else: + print(character, end='', flush=False) + except UnicodeError: + if file_handle: + file_handle.write('?') + else: + print('?', end='', flush=False) + if not file_handle: + print() diff --git a/ServerReference/simpleserver.py b/ServerReference/simpleserver.py index 605362f..36e71fb 100644 --- a/ServerReference/simpleserver.py +++ b/ServerReference/simpleserver.py @@ -290,7 +290,7 @@ def generate_random_filename(original_filename='', length=8): return identifier def main(): - server = ThreadedServer(('', 32768), RequestHandler) + server = ThreadedServer(('', int(sys.argv[1] or 32768)), RequestHandler) print('server starting') server.serve_forever() diff --git a/Steganographic/asciibet.txt b/Steganographic/asciibet.txt index 498f31c..821e789 100644 --- a/Steganographic/asciibet.txt +++ b/Steganographic/asciibet.txt @@ -1,1209 +1,1310 @@ - ########## -#### #### -#### ###### -#### ######## -#### ## #### -######## #### -###### #### -#### #### - ########## - - - - ## - #### -######## - #### - #### - #### - #### - #### -############ - - - - ######## -#### #### -#### #### - #### - #### - #### - #### -#### #### -############ - - - - ######## -#### #### - #### - #### - ###### - #### - #### -#### #### - ######## - - - - #### - ###### - ######## - #### #### -#### #### -############## - #### - #### - ######## - - - -############ -#### -#### -#### -########## - #### - #### -#### #### - ######## - - - - ###### - #### -#### -#### -########## -#### #### -#### #### -#### #### - ######## - - - -############## -#### #### -#### #### - #### - #### - #### - #### - #### - #### - - - - ######## -#### #### -#### #### -###### #### - ######## -#### ###### -#### #### -#### #### - ######## - - - - ######## -#### #### -#### #### -#### #### - ########## - #### - #### - #### - ###### - - - - - - - ######## - #### - ########## -#### #### -#### #### - ###### #### - - - -###### - #### - #### - ########## - #### #### - #### #### - #### #### - #### #### -#### ###### - - - - - - - ######## -#### #### -#### -#### -#### #### - ######## - - - - ###### - #### - #### - ########## -#### #### -#### #### -#### #### -#### #### - ###### #### - - - - - - - ######## -#### #### -############ -#### -#### #### - ######## - - - - ###### - #### #### - #### - #### -########## - #### - #### - #### -######## - - - - - - - ###### #### -#### #### -#### #### -#### #### - ########## - #### -#### #### - ######## - -###### - #### - #### - #### #### - ###### #### - #### #### - #### #### - #### #### -###### #### - - - - #### - #### - - ######## - #### - #### - #### - #### - ############ - - - - #### - #### - - ######## - #### - #### - #### - #### -#### #### -#### #### - ######## - -###### - #### - #### - #### #### - #### #### - ######## - #### #### - #### #### -###### #### - - - - ######## - #### - #### - #### - #### - #### - #### - #### - ############ - - - - - - -############ -#### ## #### -#### ## #### -#### ## #### -#### ## #### -#### #### - - - - - - -########## -#### #### -#### #### -#### #### -#### #### -#### #### - - - - - - - ######## -#### #### -#### #### -#### #### -#### #### - ######## - - - - - - -#### ###### - #### #### - #### #### - #### #### - #### #### - ########## - #### -######## - - - - - ###### #### -#### #### -#### #### -#### #### -#### #### - ########## - #### - ######## - - - - -###### #### - #### ###### - ###### #### - #### - #### -######## - - - - - - - ######## -#### #### - #### - #### -#### #### - ######## - - - - - ## - #### -############ - #### - #### - #### - #### #### - ###### - - - - - - -#### #### -#### #### -#### #### -#### #### -#### #### - ###### #### - - - - - - -#### #### -#### #### -#### #### -#### #### - ######## - #### - - - - - - -#### #### -#### #### -#### ## #### -#### ## #### - #### #### - #### #### - - - - - - -#### #### - #### #### - ###### - ###### - #### #### -#### #### - - - - - - - #### #### - #### #### - #### #### - #### #### - ######## - #### - #### -######## - - - - -############ -## #### - #### - #### -#### ## -############ - - - - #### - ######## -#### #### -#### #### -#### #### -############ -#### #### -#### #### -#### #### - - - -############ - #### #### - #### #### - #### #### - ########## - #### #### - #### #### - #### #### -############ - - - - ######## - #### #### -#### #### -#### -#### -#### -#### #### - #### #### - ######## - - - -########## - #### #### - #### #### - #### #### - #### #### - #### #### - #### #### - #### #### -########## - - - -############## - #### ## - #### - #### ## - ########## - #### ## - #### - #### ## -############## - - - -############## - #### #### - #### ## - #### ## - ########## - #### ## - #### - #### -######## - - - - ######## - #### #### -#### #### -#### -#### -#### ###### -#### #### - #### #### - ########## - - - -#### #### -#### #### -#### #### -#### #### -############ -#### #### -#### #### -#### #### -#### #### - - - - ######## - #### - #### - #### - #### - #### - #### - #### - ######## - - - - ######## - #### - #### - #### - #### -#### #### -#### #### -#### #### - ######## - - - -###### #### - #### #### - #### #### - #### #### - ######## - #### #### - #### #### - #### #### -###### #### - - - -######## - #### - #### - #### - #### - #### ## - #### #### - #### #### -############## - - - -#### #### -###### ###### -############## -############## -#### ## #### -#### #### -#### #### -#### #### -#### #### - - - -#### #### -#### #### -###### #### -######## #### -############## -#### ######## -#### ###### -#### #### -#### #### - - - - ###### - #### #### -#### #### -#### #### -#### #### -#### #### -#### #### - #### #### - ###### - - - -############ - #### #### - #### #### - #### #### - ########## - #### - #### - #### -######## - - - - ###### - #### #### -#### #### -#### #### -#### #### -#### ###### -#### ######## - ########## - #### - ######## - - -############ - #### #### - #### #### - #### #### - ########## - #### #### - #### #### - #### #### -###### #### - - - - ######## -#### #### -#### #### -#### - ###### - #### -#### #### -#### #### - ######## - - - -############ -## #### ## - #### - #### - #### - #### - #### - #### - ######## - - - -#### #### -#### #### -#### #### -#### #### -#### #### -#### #### -#### #### -#### #### - ######## - - - -#### #### -#### #### -#### #### -#### #### -#### #### -#### #### -#### #### - ######## - #### - - - -#### #### -#### #### -#### #### -#### #### -#### ## #### -#### ## #### - #### #### - #### #### - #### #### - - - -#### #### -#### #### -#### #### - ######## - #### - ######## -#### #### -#### #### -#### #### - - - -#### #### -#### #### -#### #### -#### #### - ######## - #### - #### - #### - ######## - - - -############## -#### ###### -## #### - #### - #### - #### - #### ## -#### #### -############## - - - - #### - ######## - ######## - ######## - #### - #### - - #### - #### - - - - #### #### - #### #### - #### #### - ## ## - - - - - - - - - #### #### - #### #### -############## - #### #### - #### #### - #### #### -############## - #### #### - #### #### - - - #### - #### - ########## -#### -#### - ######## - #### - #### -########## - #### - #### - - - - -#### ## -#### #### - #### - #### - #### -#### #### -## #### - - - - ###### -#### #### -#### #### - ###### -########## ## -#### ######## -#### #### -#### ###### - ###### #### - - - - #### - #### - #### - #### - - - - - - - - - #### - #### - #### - #### - #### - #### - #### - #### - #### - - - - #### - #### - #### - #### - #### - #### - #### - #### - #### - - - - - - #### #### - ######## -################ - ######## - #### #### - - - - - - - - #### - #### - ############ - #### - #### - - - - - - - - - - - - - ###### - ###### - #### - - - - - - -############## - - - - - - - - - - - - - - - ###### - ###### - - - - - ## - #### - #### - #### - #### - #### -#### -## - - - - - - ###### - ###### - - - ###### - ###### - - - - - - - ###### - ###### - - - ###### - ###### - #### - #### - - - #### - #### - #### - #### -#### - #### - #### - #### - #### - - - - - - - ############ - - ############ - - - - - - - #### - #### - #### - #### - #### - #### - #### - #### - #### - - - - ######## -#### #### - #### - #### - #### - #### - - #### - #### - - - - ########## -#### #### -#### #### -#### ######## -#### ######## -#### ######## -#### -#### - ########## - - - - ######## - #### - #### - #### - #### - #### - #### - #### - ######## - - - - -## -#### - #### - #### - #### - #### - #### - ## - - - - ######## - #### - #### - #### - #### - #### - #### - #### - ######## - - - ## - ###### - #### #### -#### #### - - - - - - - - - - - - - - - - - - -################ - - #### - #### - #### - - - - - - - - - - - ###### - #### - #### - #### -#### - #### - #### - #### - ###### - - - - #### - #### - #### - #### - - #### - #### - #### - #### - - - -###### - #### - #### - #### - #### - #### - #### - #### -###### - - - - ###### #### -#### #### ## -#### ###### - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ########## - ###### - ###### ## - ###### ## -########## -#### #### -#### #### -#### #### - ######## - - - - ######## - #### #### - #### #### - #### #### - ######## - #### - ############ - #### - #### \ No newline at end of file +--------------------- +! ########## ! +! #### #### ! +! #### ###### ! +! #### ######## ! +! #### ## #### ! +! ######## #### ! +! ###### #### ! +! #### #### ! +! ########## ! +! ! +! ! +! ! +--------------------- +! ## ! +! #### ! +! ######## ! +! #### ! +! #### ! +! #### ! +! #### ! +! #### ! +! ############ ! +! ! +! ! +! ! +--------------------- +! ######## ! +! #### #### ! +! #### #### ! +! #### ! +! #### ! +! #### ! +! #### ! +! #### #### ! +! ############ ! +! ! +! ! +! ! +--------------------- +! ######## ! +! #### #### ! +! #### ! +! #### ! +! ###### ! +! #### ! +! #### ! +! #### #### ! +! ######## ! +! ! +! ! +! ! +--------------------- +! #### ! +! ###### ! +! ######## ! +! #### #### ! +! #### #### ! +! ############## ! +! #### ! +! #### ! +! ######## ! +! ! +! ! +! ! +--------------------- +! ############ ! +! #### ! +! #### ! +! #### ! +! ########## ! +! #### ! +! #### ! +! #### #### ! +! ######## ! +! ! +! ! +! ! +--------------------- +! ###### ! +! #### ! +! #### ! +! #### ! +! ########## ! +! #### #### ! +! #### #### ! +! #### #### ! +! ######## ! +! ! +! ! +! ! +--------------------- +! ############## ! +! #### #### ! +! #### #### ! +! #### ! +! #### ! +! #### ! +! #### ! +! #### ! +! #### ! +! ! +! ! +! ! +--------------------- +! ######## ! +! #### #### ! +! #### #### ! +! ###### #### ! +! ######## ! +! #### ###### ! +! #### #### ! +! #### #### ! +! ######## ! +! ! +! ! +! ! +--------------------- +! ######## ! +! #### #### ! +! #### #### ! +! #### #### ! +! ########## ! +! #### ! +! #### ! +! #### ! +! ###### ! +! ! +! ! +! ! +--------------------- +! ! +! ! +! ! +! ######## ! +! #### ! +! ########## ! +! #### #### ! +! #### #### ! +! ###### #### ! +! ! +! ! +! ! +--------------------- +! ###### ! +! #### ! +! #### ! +! ########## ! +! #### #### ! +! #### #### ! +! #### #### ! +! #### #### ! +! #### ###### ! +! ! +! ! +! ! +--------------------- +! ! +! ! +! ! +! ######## ! +! #### #### ! +! #### ! +! #### ! +! #### #### ! +! ######## ! +! ! +! ! +! ! +--------------------- +! ###### ! +! #### ! +! #### ! +! ########## ! +! #### #### ! +! #### #### ! +! #### #### ! +! #### #### ! +! ###### #### ! +! ! +! ! +! ! +--------------------- +! ! +! ! +! ! +! ######## ! +! #### #### ! +! ############ ! +! #### ! +! #### #### ! +! ######## ! +! ! +! ! +! ! +--------------------- +! ###### ! +! #### #### ! +! #### ! +! #### ! +! ########## ! +! #### ! +! #### ! +! #### ! +! ######## ! +! ! +! ! +! ! +--------------------- +! ! +! ! +! ! +! ###### #### ! +! #### #### ! +! #### #### ! +! #### #### ! +! ########## ! +! #### ! +! #### #### ! +! ######## ! +! ! +--------------------- +! ###### ! +! #### ! +! #### ! +! #### #### ! +! ###### #### ! +! #### #### ! +! #### #### ! +! #### #### ! +! ###### #### ! +! ! +! ! +! ! +--------------------- +! #### ! +! #### ! +! ! +! ######## ! +! #### ! +! #### ! +! #### ! +! #### ! +! ############ ! +! ! +! ! +! ! +--------------------- +! #### ! +! #### ! +! ! +! ######## ! +! #### ! +! #### ! +! #### ! +! #### ! +! #### #### ! +! #### #### ! +! ######## ! +! ! +--------------------- +! ###### ! +! #### ! +! #### ! +! #### #### ! +! #### #### ! +! ######## ! +! #### #### ! +! #### #### ! +! ###### #### ! +! ! +! ! +! ! +--------------------- +! ######## ! +! #### ! +! #### ! +! #### ! +! #### ! +! #### ! +! #### ! +! #### ! +! ############ ! +! ! +! ! +! ! +--------------------- +! ! +! ! +! ! +! ############ ! +! #### ## #### ! +! #### ## #### ! +! #### ## #### ! +! #### ## #### ! +! #### #### ! +! ! +! ! +! ! +--------------------- +! ! +! ! +! ! +! ########## ! +! #### #### ! +! #### #### ! +! #### #### ! +! #### #### ! +! #### #### ! +! ! +! ! +! ! +--------------------- +! ! +! ! +! ! +! ######## ! +! #### #### ! +! #### #### ! +! #### #### ! +! #### #### ! +! ######## ! +! ! +! ! +! ! +--------------------- +! ! +! ! +! ! +! #### ###### ! +! #### #### ! +! #### #### ! +! #### #### ! +! #### #### ! +! ########## ! +! #### ! +! ######## ! +! ! +--------------------- +! ! +! ! +! ! +! ###### #### ! +! #### #### ! +! #### #### ! +! #### #### ! +! #### #### ! +! ########## ! +! #### ! +! ######## ! +! ! +--------------------- +! ! +! ! +! ! +! ###### #### ! +! #### ###### ! +! ###### #### ! +! #### ! +! #### ! +! ######## ! +! ! +! ! +! ! +--------------------- +! ! +! ! +! ! +! ######## ! +! #### #### ! +! #### ! +! #### ! +! #### #### ! +! ######## ! +! ! +! ! +! ! +--------------------- +! ! +! ## ! +! #### ! +! ############ ! +! #### ! +! #### ! +! #### ! +! #### #### ! +! ###### ! +! ! +! ! +! ! +--------------------- +! ! +! ! +! ! +! #### #### ! +! #### #### ! +! #### #### ! +! #### #### ! +! #### #### ! +! ###### #### ! +! ! +! ! +! ! +--------------------- +! ! +! ! +! ! +! #### #### ! +! #### #### ! +! #### #### ! +! #### #### ! +! ######## ! +! #### ! +! ! +! ! +! ! +--------------------- +! ! +! ! +! ! +! #### #### ! +! #### #### ! +! #### ## #### ! +! #### ## #### ! +! #### #### ! +! #### #### ! +! ! +! ! +! ! +--------------------- +! ! +! ! +! ! +! #### #### ! +! #### #### ! +! ###### ! +! ###### ! +! #### #### ! +! #### #### ! +! ! +! ! +! ! +--------------------- +! ! +! ! +! ! +! #### #### ! +! #### #### ! +! #### #### ! +! #### #### ! +! ######## ! +! #### ! +! #### ! +! ######## ! +! ! +--------------------- +! ! +! ! +! ! +! ############ ! +! ## #### ! +! #### ! +! #### ! +! #### ## ! +! ############ ! +! ! +! ! +! ! +--------------------- +! #### ! +! ######## ! +! #### #### ! +! #### #### ! +! #### #### ! +! ############ ! +! #### #### ! +! #### #### ! +! #### #### ! +! ! +! ! +! ! +--------------------- +! ############ ! +! #### #### ! +! #### #### ! +! #### #### ! +! ########## ! +! #### #### ! +! #### #### ! +! #### #### ! +! ############ ! +! ! +! ! +! ! +--------------------- +! ######## ! +! #### #### ! +! #### #### ! +! #### ! +! #### ! +! #### ! +! #### #### ! +! #### #### ! +! ######## ! +! ! +! ! +! ! +--------------------- +! ########## ! +! #### #### ! +! #### #### ! +! #### #### ! +! #### #### ! +! #### #### ! +! #### #### ! +! #### #### ! +! ########## ! +! ! +! ! +! ! +--------------------- +! ############## ! +! #### ## ! +! #### ! +! #### ## ! +! ########## ! +! #### ## ! +! #### ! +! #### ## ! +! ############## ! +! ! +! ! +! ! +--------------------- +! ############## ! +! #### #### ! +! #### ## ! +! #### ## ! +! ########## ! +! #### ## ! +! #### ! +! #### ! +! ######## ! +! ! +! ! +! ! +--------------------- +! ######## ! +! #### #### ! +! #### #### ! +! #### ! +! #### ! +! #### ###### ! +! #### #### ! +! #### #### ! +! ########## ! +! ! +! ! +! ! +--------------------- +! #### #### ! +! #### #### ! +! #### #### ! +! #### #### ! +! ############ ! +! #### #### ! +! #### #### ! +! #### #### ! +! #### #### ! +! ! +! ! +! ! +--------------------- +! ######## ! +! #### ! +! #### ! +! #### ! +! #### ! +! #### ! +! #### ! +! #### ! +! ######## ! +! ! +! ! +! ! +--------------------- +! ######## ! +! #### ! +! #### ! +! #### ! +! #### ! +! #### #### ! +! #### #### ! +! #### #### ! +! ######## ! +! ! +! ! +! ! +--------------------- +! ###### #### ! +! #### #### ! +! #### #### ! +! #### #### ! +! ######## ! +! #### #### ! +! #### #### ! +! #### #### ! +! ###### #### ! +! ! +! ! +! ! +--------------------- +! ######## ! +! #### ! +! #### ! +! #### ! +! #### ! +! #### ## ! +! #### #### ! +! #### #### ! +! ############## ! +! ! +! ! +! ! +--------------------- +! #### #### ! +! ###### ###### ! +! ############## ! +! ############## ! +! #### ## #### ! +! #### #### ! +! #### #### ! +! #### #### ! +! #### #### ! +! ! +! ! +! ! +--------------------- +! #### #### ! +! #### #### ! +! ###### #### ! +! ######## #### ! +! ############## ! +! #### ######## ! +! #### ###### ! +! #### #### ! +! #### #### ! +! ! +! ! +! ! +--------------------- +! ###### ! +! #### #### ! +! #### #### ! +! #### #### ! +! #### #### ! +! #### #### ! +! #### #### ! +! #### #### ! +! ###### ! +! ! +! ! +! ! +--------------------- +! ############ ! +! #### #### ! +! #### #### ! +! #### #### ! +! ########## ! +! #### ! +! #### ! +! #### ! +! ######## ! +! ! +! ! +! ! +--------------------- +! ###### ! +! #### #### ! +! #### #### ! +! #### #### ! +! #### #### ! +! #### ###### ! +! #### ######## ! +! ########## ! +! #### ! +! ######## ! +! ! +! ! +--------------------- +! ############ ! +! #### #### ! +! #### #### ! +! #### #### ! +! ########## ! +! #### #### ! +! #### #### ! +! #### #### ! +! ###### #### ! +! ! +! ! +! ! +--------------------- +! ######## ! +! #### #### ! +! #### #### ! +! #### ! +! ###### ! +! #### ! +! #### #### ! +! #### #### ! +! ######## ! +! ! +! ! +! ! +--------------------- +! ############ ! +! ## #### ## ! +! #### ! +! #### ! +! #### ! +! #### ! +! #### ! +! #### ! +! ######## ! +! ! +! ! +! ! +--------------------- +! #### #### ! +! #### #### ! +! #### #### ! +! #### #### ! +! #### #### ! +! #### #### ! +! #### #### ! +! #### #### ! +! ######## ! +! ! +! ! +! ! +--------------------- +! #### #### ! +! #### #### ! +! #### #### ! +! #### #### ! +! #### #### ! +! #### #### ! +! #### #### ! +! ######## ! +! #### ! +! ! +! ! +! ! +--------------------- +! #### #### ! +! #### #### ! +! #### #### ! +! #### #### ! +! #### ## #### ! +! #### ## #### ! +! #### #### ! +! #### #### ! +! #### #### ! +! ! +! ! +! ! +--------------------- +! #### #### ! +! #### #### ! +! #### #### ! +! ######## ! +! #### ! +! ######## ! +! #### #### ! +! #### #### ! +! #### #### ! +! ! +! ! +! ! +--------------------- +! #### #### ! +! #### #### ! +! #### #### ! +! #### #### ! +! ######## ! +! #### ! +! #### ! +! #### ! +! ######## ! +! ! +! ! +! ! +--------------------- +! ############## ! +! #### ###### ! +! ## #### ! +! #### ! +! #### ! +! #### ! +! #### ## ! +! #### #### ! +! ############## ! +! ! +! ! +! ! +--------------------- +! #### ! +! ######## ! +! ######## ! +! ######## ! +! #### ! +! #### ! +! ! +! #### ! +! #### ! +! ! +! ! +! ! +--------------------- +! #### #### ! +! #### #### ! +! #### #### ! +! ## ## ! +! ! +! ! +! ! +! ! +! ! +! ! +! ! +! ! +--------------------- +! #### #### ! +! #### #### ! +! ############## ! +! #### #### ! +! #### #### ! +! #### #### ! +! ############## ! +! #### #### ! +! #### #### ! +! ! +! ! +! #### ! +--------------------- +! #### ! +! ########## ! +! #### ! +! #### ! +! ######## ! +! #### ! +! #### ! +! ########## ! +! #### ! +! #### ! +! ! +! ! +--------------------- +! ! +! ! +! #### ## ! +! #### #### ! +! #### ! +! #### ! +! #### ! +! #### #### ! +! ## #### ! +! ! +! ! +! ! +--------------------- +! ###### ! +! #### #### ! +! #### #### ! +! ###### ! +! ########## ## ! +! #### ######## ! +! #### #### ! +! #### ###### ! +! ###### #### ! +! ! +! ! +! ! +--------------------- +! #### ! +! #### ! +! #### ! +! #### ! +! ! +! ! +! ! +! ! +! ! +! ! +! ! +! ! +--------------------- +! #### ! +! #### ! +! #### ! +! #### ! +! #### ! +! #### ! +! #### ! +! #### ! +! #### ! +! ! +! ! +! ! +--------------------- +! #### ! +! #### ! +! #### ! +! #### ! +! #### ! +! #### ! +! #### ! +! #### ! +! #### ! +! ! +! ! +! ! +--------------------- +! ! +! ! +! #### #### ! +! ######## ! +! ################ ! +! ######## ! +! #### #### ! +! ! +! ! +! ! +! ! +! ! +--------------------- +! ! +! ! +! #### ! +! #### ! +! ############ ! +! #### ! +! #### ! +! ! +! ! +! ! +! ! +! ! +--------------------- +! ! +! ! +! ! +! ! +! ! +! ! +! ! +! ###### ! +! ###### ! +! #### ! +! ! +! ! +--------------------- +! ! +! ! +! ! +! ! +! ############## ! +! ! +! ! +! ! +! ! +! ! +! ! +! ! +--------------------- +! ! +! ! +! ! +! ! +! ! +! ! +! ! +! ###### ! +! ###### ! +! ! +! ! +! ! +--------------------- +! ! +! ## ! +! #### ! +! #### ! +! #### ! +! #### ! +! #### ! +! #### ! +! ## ! +! ! +! ! +! ! +--------------------- +! ! +! ! +! ###### ! +! ###### ! +! ! +! ! +! ###### ! +! ###### ! +! ! +! ! +! ! +! ! +--------------------- +! ! +! ! +! ###### ! +! ###### ! +! ! +! ! +! ###### ! +! ###### ! +! #### ! +! #### ! +! ! +! ! +--------------------- +! #### ! +! #### ! +! #### ! +! #### ! +! #### ! +! #### ! +! #### ! +! #### ! +! #### ! +! ! +! ! +! ! +--------------------- +! ! +! ! +! ! +! ############ ! +! ! +! ############ ! +! ! +! ! +! ! +! ! +! ! +! ! +--------------------- +! #### ! +! #### ! +! #### ! +! #### ! +! #### ! +! #### ! +! #### ! +! #### ! +! #### ! +! ! +! ! +! ! +--------------------- +! ######## ! +! #### #### ! +! #### ! +! #### ! +! #### ! +! #### ! +! ! +! #### ! +! #### ! +! ! +! ! +! ! +--------------------- +! ########## ! +! #### #### ! +! #### #### ! +! #### ######## ! +! #### ######## ! +! #### ######## ! +! #### ! +! #### ! +! ########## ! +! ! +! ! +! ! +--------------------- +! ######## ! +! #### ! +! #### ! +! #### ! +! #### ! +! #### ! +! #### ! +! #### ! +! ######## ! +! ! +! ! +! ! +--------------------- +! ! +! ## ! +! #### ! +! #### ! +! #### ! +! #### ! +! #### ! +! #### ! +! ## ! +! ! +! ! +! ! +--------------------- +! ######## ! +! #### ! +! #### ! +! #### ! +! #### ! +! #### ! +! #### ! +! #### ! +! ######## ! +! ! +! ! +! ## ! +--------------------- +! ###### ! +! #### #### ! +! #### #### ! +! ! +! ! +! ! +! ! +! ! +! ! +! ! +! ! +! ! +--------------------- +! ! +! ! +! ! +! ! +! ! +! ! +! ! +! ! +! ! +! ################ ! +! ! +! #### ! +--------------------- +! #### ! +! #### ! +! ! +! ! +! ! +! ! +! ! +! ! +! ! +! ! +! ! +! ! +--------------------- +! ###### ! +! #### ! +! #### ! +! #### ! +! #### ! +! #### ! +! #### ! +! #### ! +! ###### ! +! ! +! ! +! ! +--------------------- +! #### ! +! #### ! +! #### ! +! #### ! +! ! +! #### ! +! #### ! +! #### ! +! #### ! +! ! +! ! +! ! +--------------------- +! ###### ! +! #### ! +! #### ! +! #### ! +! #### ! +! #### ! +! #### ! +! #### ! +! ###### ! +! ! +! ! +! ! +--------------------- +! ###### #### ! +! #### #### ## ! +! #### ###### ! +! ! +! ! +! ! +! ! +! ! +! ! +! ! +! ! +! ! +--------------------- +! ! +! ! +! ! +! ! +! ! +! ! +! ! +! ! +! ! +! ! +! ! +! ! +--------------------- +! ! +! ! +! ! +! ! +! ! +! ! +! ! +! ! +! ! +! ! +! ! +! ! +--------------------- +! ! +! ! +! ! +! ! +! ! +! ! +! ! +! ! +! ! +! ! +! ! +! ! +--------------------- +! ! +! ! +! ! +! ! +! ! +! ! +! ! +! ! +! ! +! ! +! ! +! ! +--------------------- +! ! +! ! +! ! +! ! +! ! +! ! +! ! +! ! +! ! +! ! +! ! +! ! +--------------------- +! ########## ! +! ###### ! +! ###### ## ! +! ###### ## ! +! ########## ! +! #### #### ! +! #### #### ! +! #### #### ! +! ######## ! +! ! +! ! +! ! +--------------------- +! ######## ! +! #### #### ! +! #### #### ! +! #### #### ! +! ######## ! +! #### ! +! ############ ! +! #### ! +! #### ! diff --git a/Templates/timetest.py b/Templates/timetest.py new file mode 100644 index 0000000..6e0a755 --- /dev/null +++ b/Templates/timetest.py @@ -0,0 +1,22 @@ +import time + +LOOPS = 10000 + +def func_1(): + pass + +def func_2(): + pass + + +start = time.time() +for x in range(LOOPS): + func_1() +end = time.time() +print('v1', end - start) + +start = time.time() +for x in range(LOOPS): + func_2() +end = time.time() +print('v2', end - start) diff --git a/ThreadedDL/threaded_dl.py b/ThreadedDL/threaded_dl.py index a091f4a..7285ef3 100644 --- a/ThreadedDL/threaded_dl.py +++ b/ThreadedDL/threaded_dl.py @@ -36,6 +36,10 @@ def threaded_dl(urls, thread_count, filename_format=None): if filename_format is None: filename_format = '{now}_{index}_{basename}' filename_format = filename_format.replace('{index}', '{index:0%0dd}' % index_digits) + if '{' not in filename_format and len(urls) > 1: + filename_format += '_{index}' + if '{extension}' not in filename_format: + filename_format += '{extension}' now = int(time.time()) for (index, url) in enumerate(urls): while len(threads) == thread_count: diff --git a/Toolbox/brename.py b/Toolbox/brename.py index 9172002..f2170dc 100644 --- a/Toolbox/brename.py +++ b/Toolbox/brename.py @@ -16,6 +16,8 @@ import random import re import sys +from voussoirkit import safeprint + def brename(transformation): old = os.listdir() @@ -46,7 +48,7 @@ def loop(pairs, dry=False): line = '{old}\n{new}\n' line = line.format(old=x, new=y) #print(line.encode('utf-8')) - print(line.encode('ascii', 'replace').decode()) + safeprint.safeprint(line) has_content = True else: os.rename(x, y) diff --git a/Toolbox/fileswith.py b/Toolbox/fileswith.py index 2d2011a..598a4bd 100644 --- a/Toolbox/fileswith.py +++ b/Toolbox/fileswith.py @@ -10,6 +10,7 @@ import glob import re import sys +from voussoirkit import safeprint from voussoirkit import spinal filepattern = sys.argv[1] @@ -31,5 +32,5 @@ for filename in spinal.walk_generator(): pass if matches: print(filename) - print('\n'.join(matches).encode('ascii', 'replace').decode()) + safeprint.safeprint('\n'.join(matches)) print() diff --git a/Toolbox/touch.py b/Toolbox/touch.py index a7c6db2..91339d2 100644 --- a/Toolbox/touch.py +++ b/Toolbox/touch.py @@ -5,14 +5,16 @@ import glob import os import sys +from voussoirkit import safeprint + def touch(glob_pattern): filenames = glob.glob(glob_pattern) if len(filenames) == 0: - print(glob_pattern.encode('ascii', 'replace').decode()) + safeprint.safeprint(glob_pattern) open(glob_pattern, 'a').close() else: for filename in filenames: - print(filename.encode('ascii', 'replace').decode()) + safeprint.safeprint(filename) os.utime(filename) if __name__ == '__main__': diff --git a/VoxelSphereGenerator/dot_corner.png b/VoxelSphereGenerator/dot_corner.png new file mode 100644 index 0000000..5ca0cba Binary files /dev/null and b/VoxelSphereGenerator/dot_corner.png differ diff --git a/VoxelSphereGenerator/dot_highlight.png b/VoxelSphereGenerator/dot_highlight.png new file mode 100644 index 0000000..242713b Binary files /dev/null and b/VoxelSphereGenerator/dot_highlight.png differ diff --git a/VoxelSphereGenerator/dot_normal.png b/VoxelSphereGenerator/dot_normal.png new file mode 100644 index 0000000..31837c7 Binary files /dev/null and b/VoxelSphereGenerator/dot_normal.png differ diff --git a/VoxelSphereGenerator/voxelspheregenerator.py b/VoxelSphereGenerator/voxelspheregenerator.py new file mode 100644 index 0000000..241c92a --- /dev/null +++ b/VoxelSphereGenerator/voxelspheregenerator.py @@ -0,0 +1,274 @@ +import argparse +import math +import PIL.Image +import PIL.ImageDraw +import sys + +def choose_guideline_style(guideline_mod): + if guideline_mod % 16 == 0: + return ('#1f32ff', 3) + if guideline_mod % 8 == 0: + return ('#80f783', 2) + if guideline_mod % 4 == 0: + return ('#f4bffb', 1) + +def voxelspheregenerator(WIDTH, HEIGH, DEPTH, WALL_THICKNESS=None): + def in_ellipsoid(x, y, z, rad_x, rad_y, rad_z, center_x=None, center_y=None, center_z=None): + ''' + Given a point (x, y, z), return whether that point lies inside the + ellipsoid defined by (x/a)^2 + (y/b)^2 + (z/c)^2 = 1 + ''' + if center_x is None: center_x = rad_x + if center_y is None: center_y = rad_y + if center_z is None: center_z = rad_z + #print(x, y, z, rad_x, rad_y, rad_z, center_x, center_y, center_z) + x = ((x - center_x) / rad_x) ** 2 + y = ((y - center_y) / rad_y) ** 2 + z = ((z - center_z) / rad_z) ** 2 + distance = x + y + z + #print(distance) + return distance < 1 + + ODD_W = WIDTH % 2 == 1 + ODD_H = HEIGH % 2 == 1 + ODD_D = DEPTH % 2 == 1 + + RAD_X = WIDTH / 2 + RAD_Y = HEIGH / 2 + RAD_Z = DEPTH / 2 + + if WALL_THICKNESS: + INNER_RAD_X = RAD_X - WALL_THICKNESS + INNER_RAD_Y = RAD_Y - WALL_THICKNESS + INNER_RAD_Z = RAD_Z - WALL_THICKNESS + + X_CENTER = {WIDTH // 2} if ODD_W else {WIDTH // 2, (WIDTH // 2) - 1} + Y_CENTER = {HEIGH // 2} if ODD_H else {HEIGH // 2, (HEIGH // 2) - 1} + Z_CENTER = {DEPTH // 2} if ODD_D else {DEPTH // 2, (DEPTH // 2) - 1} + + layer_digits = len(str(DEPTH)) + filename_form = '{w}x{h}x{d}w{wall}-{{layer:0{digits}}}.png' + filename_form = filename_form.format( + w=WIDTH, + h=HEIGH, + d=DEPTH, + wall=WALL_THICKNESS if WALL_THICKNESS else 0, + digits=layer_digits, + ) + + dot_highlight = PIL.Image.open('dot_highlight.png') + dot_normal = PIL.Image.open('dot_normal.png') + dot_corner = PIL.Image.open('dot_corner.png') + pixel_scale = dot_highlight.size[0] + + # Space between each pixel + PIXEL_MARGIN = 7 + + # Space between the pixel area and the canvas + PIXELSPACE_MARGIN = 20 + + # Space between the canvas area and the image edge + CANVAS_MARGIN = 20 + + LABEL_HEIGH = 20 + FINAL_IMAGE_SCALE = 1 + + PIXELSPACE_WIDTH = (WIDTH * pixel_scale) + ((WIDTH - 1) * PIXEL_MARGIN) + PIXELSPACE_HEIGH = (HEIGH * pixel_scale) + ((HEIGH - 1) * PIXEL_MARGIN) + + CANVAS_WIDTH = PIXELSPACE_WIDTH + (2 * PIXELSPACE_MARGIN) + CANVAS_HEIGH = PIXELSPACE_HEIGH + (2 * PIXELSPACE_MARGIN) + + IMAGE_WIDTH = CANVAS_WIDTH + (2 * CANVAS_MARGIN) + IMAGE_HEIGH = CANVAS_HEIGH + (2 * CANVAS_MARGIN) + LABEL_HEIGH + + CANVAS_START_X = CANVAS_MARGIN + CANVAS_START_Y = CANVAS_MARGIN + CANVAS_END_X = CANVAS_START_X + CANVAS_WIDTH + CANVAS_END_Y = CANVAS_START_Y + CANVAS_HEIGH + + PIXELSPACE_START_X = CANVAS_START_X + PIXELSPACE_MARGIN + PIXELSPACE_START_Y = CANVAS_START_Y + PIXELSPACE_MARGIN + PIXELSPACE_END_X = PIXELSPACE_START_X + PIXELSPACE_WIDTH + PIXELSPACE_END_Y = PIXELSPACE_START_Y + PIXELSPACE_HEIGH + + GUIDELINE_MOD_X = math.ceil(RAD_X) + GUIDELINE_MOD_Y = math.ceil(RAD_Y) + + def pixel_coord(x, y): + x = PIXELSPACE_START_X + (x * pixel_scale) + (x * PIXEL_MARGIN) + y = PIXELSPACE_START_Y + (y * pixel_scale) + (y * PIXEL_MARGIN) + return (x, y) + + def make_layer_matrix(z): + layer_matrix = [[None for y in range(math.ceil(RAD_Y))] for x in range(math.ceil(RAD_X))] + + # Generate the upper left corner. + furthest_x = RAD_X + furthest_y = RAD_Y + for y in range(math.ceil(RAD_Y)): + for x in range(math.ceil(RAD_X)): + ux = x + 0.5 + uy = y + 0.5 + uz = z + 0.5 + + within = in_ellipsoid(ux, uy, uz, RAD_X, RAD_Y, RAD_Z) + if WALL_THICKNESS: + in_hole = in_ellipsoid( + ux, uy, uz, + INNER_RAD_X, INNER_RAD_Y, INNER_RAD_Z, + RAD_X, RAD_Y, RAD_Z + ) + within = within and not in_hole + if within: + if x in X_CENTER or y in Y_CENTER: + if z in Z_CENTER: + dot = dot_normal + else: + dot = dot_highlight + else: + if z in Z_CENTER: + dot = dot_highlight + else: + dot = dot_normal + layer_matrix[x][y] = dot + furthest_x = min(x, furthest_x) + furthest_y = min(y, furthest_y) + #layer_image.paste(dot, box=(pixel_coord_x, pixel_coord_y)) + + # Mark the corner pieces + for y in range(furthest_y, math.ceil(RAD_Y-1)): + for x in range(furthest_x, math.ceil(RAD_X-1)): + is_corner = ( + layer_matrix[x][y] is not None and + layer_matrix[x-1][y+1] is not None and + layer_matrix[x+1][y-1] is not None and + ( + # Outer corners + (layer_matrix[x][y-1] is None and layer_matrix[x-1][y] is None) or + # Inner corners, if hollow + (layer_matrix[x][y+1] is None and layer_matrix[x+1][y] is None) + ) + ) + if is_corner: + layer_matrix[x][y] = dot_corner + + return layer_matrix + + def make_layer_image(layer_matrix): + layer_image = PIL.Image.new('RGBA', size=(IMAGE_WIDTH, IMAGE_HEIGH), color=(0, 0, 0, 0)) + draw = PIL.ImageDraw.ImageDraw(layer_image) + + # Plot. + for y in range(math.ceil(RAD_Y)): + for x in range(math.ceil(RAD_X)): + right_x = (WIDTH - 1) - x + bottom_y = (HEIGH - 1) - y + if layer_matrix[x][y] is not None: + layer_image.paste(layer_matrix[x][y], box=pixel_coord(x, y)) + layer_image.paste(layer_matrix[x][y], box=pixel_coord(right_x, y)) + layer_image.paste(layer_matrix[x][y], box=pixel_coord(x, bottom_y)) + layer_image.paste(layer_matrix[x][y], box=pixel_coord(right_x, bottom_y)) + + # To draw the guidelines, start from + for x in range(GUIDELINE_MOD_X % 4, WIDTH + 4, 4): + # Vertical guideline + as_if = GUIDELINE_MOD_X - x + #print(x, as_if) + line_x = PIXELSPACE_START_X + (x * pixel_scale) + (x * PIXEL_MARGIN) + line_x = line_x - PIXEL_MARGIN + (PIXEL_MARGIN // 2) + if line_x >= PIXELSPACE_END_X: + continue + (color, width) = choose_guideline_style(as_if) + draw.line((line_x, CANVAS_START_Y, line_x, CANVAS_END_Y - 1), fill=color, width=width) + draw.text((line_x, CANVAS_END_X), str(x), fill='#000') + + for y in range(GUIDELINE_MOD_Y % 4, HEIGH + 4, 4): + # Horizontal guideline + as_if = GUIDELINE_MOD_Y - y + #print(y, as_if) + line_y = PIXELSPACE_START_Y + (y * pixel_scale) + (y * PIXEL_MARGIN) + line_y = line_y - PIXEL_MARGIN + (PIXEL_MARGIN // 2) + if line_y >= PIXELSPACE_END_Y: + continue + (color, width) = choose_guideline_style(as_if) + draw.line((CANVAS_START_X, line_y, CANVAS_END_X - 1, line_y), fill=color, width=width) + draw.text((CANVAS_END_X, line_y), str(y), fill='#000') + + draw.rectangle((CANVAS_START_X, CANVAS_START_Y, CANVAS_END_X - 1, CANVAS_END_Y - 1), outline='#000') + draw.text((CANVAS_START_X, IMAGE_HEIGH - LABEL_HEIGH), layer_filename, fill='#000') + print(layer_filename) + if FINAL_IMAGE_SCALE != 1: + layer_image = layer_image.resize((FINAL_IMAGE_SCALE * IMAGE_WIDTH, FINAL_IMAGE_SCALE * IMAGE_HEIGH)) + + return layer_image + + layer_matrices = [] + for z in range(DEPTH): + if z < math.ceil(RAD_Z): + layer_matrix = make_layer_matrix(z) + layer_matrices.append(layer_matrix) + else: + layer_matrix = layer_matrices[(DEPTH - 1) - z] + layer_filename = filename_form.format(layer=z) + layer_image = make_layer_image(layer_matrix) + layer_image.save(layer_filename) + + + # Copy to the upper right corner. + #for y in range(math.ceil(RAD_Y)): + # #print(y) + # for x in range(math.ceil(RAD_X), WIDTH): + # #print(x, '==', (WIDTH-1) - x) + # mapped_x = (WIDTH - 1) - x + # layer_matrix[x][y] = layer_matrix[mapped_x][y] + + # Copy to the lower semicircle. + #for y in range(math.ceil(RAD_Y), HEIGH): + # #print(y) + # for x in range(WIDTH): + # #print(y, '==', (HEIGH-1) - y) + # mapped_y = (HEIGH-1) - y + # layer_matrix[x][y] = layer_matrix[x][mapped_y] + + + + #break + #layer_matrix = [['▓' if dot == dot_highlight else '░' if dot == dot_normal else ' 'for dot in sublist] for sublist in layer_matrix] + #layer_matrix = [''.join(sublist) for sublist in layer_matrix] + #layer_matrix = '\n'.join(layer_matrix) + #print(layer_matrix) + #print() + + +def voxelsphere_argparse(args): + height_depth_match = bool(args.height) == bool(args.depth) + if not height_depth_match: + raise ValueError('Must provide both or neither of height+depth. Not just one.') + + if (args.height is args.depth is None): + args.height = args.width + args.depth = args.width + + voxelspheregenerator( + int(args.width), + int(args.height), + int(args.depth), + WALL_THICKNESS=int(args.wall_thickness) if args.wall_thickness else None, + ) + + +def main(argv): + parser = argparse.ArgumentParser() + + parser.add_argument('width') + parser.add_argument('height', nargs='?', default=None) + parser.add_argument('depth', nargs='?', default=None) + parser.add_argument('--wall', dest='wall_thickness', default=None) + parser.set_defaults(func=voxelsphere_argparse) + + args = parser.parse_args(argv) + args.func(args) + +if __name__ == '__main__': + main(sys.argv[1:]) diff --git a/WebstreamZip/README.md b/WebstreamZip/README.md new file mode 100644 index 0000000..e111313 --- /dev/null +++ b/WebstreamZip/README.md @@ -0,0 +1,3 @@ +PLEASE DON'T USE THIS + +Use [python-zipstream](https://github.com/allanlei/python-zipstream) instead. diff --git a/WebstreamZip/test.zip b/WebstreamZip/test.zip deleted file mode 100644 index a2f3957..0000000 Binary files a/WebstreamZip/test.zip and /dev/null differ diff --git a/WebstreamZip/tester.py b/WebstreamZip/tester.py deleted file mode 100644 index f158cfb..0000000 --- a/WebstreamZip/tester.py +++ /dev/null @@ -1,7 +0,0 @@ -import webstreamzip - -g = webstreamzip.stream_zip({'C:\\git\\else\\readme.md':'michael.md'}) - -x = open('test.zip', 'wb') -for chunk in g: - x.write(chunk) \ No newline at end of file diff --git a/_voussoirkit/voussoirkit.py b/_voussoirkit/voussoirkit.py index 184afb9..41fcf97 100644 --- a/_voussoirkit/voussoirkit.py +++ b/_voussoirkit/voussoirkit.py @@ -10,6 +10,7 @@ PATHS = [ 'C:\\git\\else\\Pathclass\\pathclass.py', 'C:\\git\\else\\Ratelimiter\\ratelimiter.py', 'C:\\git\\else\\RateMeter\\ratemeter.py', +'C:\\git\\else\\Safeprint\\safeprint.py', 'C:\\git\\else\\SpinalTap\\spinal.py', 'C:\\git\\else\\WebstreamZip\\webstreamzip.py', ] @@ -40,7 +41,7 @@ import setuptools setuptools.setup( author='voussoir', name='{package}', - version='0.0.3', + version='0.0.4', description='', py_modules=[{py_modules}], ) diff --git a/_voussoirkit/voussoirkit.zip b/_voussoirkit/voussoirkit.zip index dad8524..635ae9a 100644 Binary files a/_voussoirkit/voussoirkit.zip and b/_voussoirkit/voussoirkit.zip differ