|
| 1 | +import datetime |
| 2 | +import glob |
| 3 | +import os |
| 4 | +import os.path |
| 5 | +import re |
| 6 | +from typing import Optional |
| 7 | + |
1 | 8 | import fire |
| 9 | +import fire.core |
| 10 | +from PIL import Image, UnidentifiedImageError |
2 | 11 |
|
3 | | -from anshitsu.process import process |
| 12 | +from anshitsu.__version__ import version as __version__ |
| 13 | +from anshitsu.process.processor import Processor |
4 | 14 |
|
5 | 15 |
|
6 | | -def main(): |
| 16 | +def cli( |
| 17 | + path: Optional[str] = None, |
| 18 | + colorautoadjust: bool = False, |
| 19 | + colorstretch: bool = False, |
| 20 | + grayscale: bool = False, |
| 21 | + invert: bool = False, |
| 22 | + color: Optional[float] = None, |
| 23 | + brightness: Optional[float] = None, |
| 24 | + sharpness: Optional[float] = None, |
| 25 | + contrast: Optional[float] = None, |
| 26 | + tosaka: Optional[float] = None, |
| 27 | + outputrgb: bool = False, |
| 28 | + sepia: bool = False, |
| 29 | + cyanotype: bool = False, |
| 30 | + noise: Optional[float] = None, |
| 31 | + overwrite: bool = False, |
| 32 | + version: bool = False, |
| 33 | + line_drawing: bool = False, |
| 34 | + posterize: Optional[int] = None, |
| 35 | +) -> str: |
7 | 36 | """ |
8 | | - main [summary] |
| 37 | + Process Runnner for Command Line Interface |
| 38 | +
|
| 39 | + This utility converts the colors of images such as photos. |
| 40 | +
|
| 41 | + If you specify a directory path, it will convert |
| 42 | + the image files in the specified directory. |
| 43 | + If you specify a file path, it will convert the specified file. |
| 44 | + If you specify an option, the specified conversion will be performed. |
| 45 | +
|
| 46 | + Tosaka mode is a mode that expresses the preference of |
| 47 | + Tosaka-senpai, a character in "Kyūkyoku Chōjin R", |
| 48 | + for "photos taken with Tri-X that look like they were |
| 49 | + burned onto No. 4 or No. 5 photographic paper". |
| 50 | + Only use floating-point numbers when using this mode; |
| 51 | + numbers around 2.4 will make it look right. |
| 52 | +
|
| 53 | + Args: |
| 54 | + path (Optional[str], optional): Directory or File Path. Defaults to None. |
| 55 | + overwrite (bool, optional): Overwrite original files. Defaults to False. |
| 56 | + colorautoadjust (bool, optional): Use colorautoadjust algorithm. Defaults to False. |
| 57 | + colorstretch (bool, optional): Use colorstretch algorithm. Defaults to False. |
| 58 | + grayscale (bool, optional): Convert to grayscale. Defaults to False. |
| 59 | + invert (bool, optional): Invert color. Defaults to False. |
| 60 | + color (Optional[float], optional): Fix color balance. Defaults to None. |
| 61 | + brightness (Optional[float], optional): Fix brightness. Defaults to None. |
| 62 | + sharpness (Optional[float], optional): Fix sharpness. Defaults to None. |
| 63 | + contrast (Optional[float], optional): Fix contrast. Defaults to None. |
| 64 | + tosaka (Optional[float], optional): Convert to grayscale with fix contrast. Defaults to None. |
| 65 | + outputrgb (bool, optional): Outputs a monochrome image in RGB. Defaults to False. |
| 66 | + cyanotype (bool, optional): Convert to RGB like cyanotype. Defaults to False. |
| 67 | + sepia (bool, optional): Convert to RGB colored by sepia. Defaults to False. |
| 68 | + noise (Optional[float], optional): Add Gaussian noise. Defaults to None. |
| 69 | + line_drawing (bool, optional): Convert to like line drawing. Defaults to False. |
| 70 | + version (bool, optional): Show version. Defaults to False. |
| 71 | +
|
| 72 | + Raises: |
| 73 | + fire.core.FireError: Error that occurs when the specified string is not a path. |
| 74 | +
|
| 75 | + Returns: |
| 76 | + str: Message. |
9 | 77 | """ |
10 | | - fire.Fire(process) |
| 78 | + if version: |
| 79 | + return "Anshitsu version {}".format(__version__) |
| 80 | + if path is None: |
| 81 | + raise fire.core.FireError("No path specified!") |
| 82 | + types = ("*.jpg", "*.JPG", "*.jpeg", "*.JPEG", "*.png", "*.PNG") |
| 83 | + files_glob = [] |
| 84 | + return_path = "" |
| 85 | + now_s = datetime.datetime.now() |
| 86 | + output_dir = "anshitsu_out" |
| 87 | + original_dir = "anshitsu_orig" |
| 88 | + if os.path.isdir(path): |
| 89 | + for type in types: |
| 90 | + files_glob.extend(glob.glob(os.path.join(path, '**', type), recursive=True)) |
| 91 | + files_glob = [file for file in files_glob if not file.__contains__(output_dir)] |
| 92 | + return_path = path |
11 | 93 |
|
| 94 | + if len(files_glob) == 0: |
| 95 | + raise fire.core.FireError( |
| 96 | + "There are no JPEG or PNG files in this directory." |
| 97 | + ) |
| 98 | + elif os.path.isfile(path): |
| 99 | + files_glob.extend(glob.glob(path)) |
| 100 | + return_path = os.path.abspath(os.path.join(path, os.pardir)) |
| 101 | + else: |
| 102 | + raise fire.core.FireError("A non-path string was passed.") |
| 103 | + if overwrite is True: |
| 104 | + os.makedirs(os.path.join(return_path, original_dir)) |
| 105 | + for i, file in enumerate(files_glob): |
| 106 | + try: |
| 107 | + image = Image.open(file) |
| 108 | + except UnidentifiedImageError as e: |
| 109 | + raise fire.core.FireError(e) |
| 110 | + exif = image.getexif() |
| 111 | + original_filename: str = os.path.split(file)[1] |
| 112 | + extension = original_filename.split(".")[-1] |
| 113 | + timestamp = now_s.strftime("%Y-%m-%d_%H-%M-%S") |
| 114 | + if overwrite is True: |
| 115 | + backup_filename = original_filename |
| 116 | + image.save(os.path.join( |
| 117 | + return_path, |
| 118 | + original_dir, |
| 119 | + backup_filename |
| 120 | + )) |
| 121 | + filename = os.path.join(return_path, re.sub(r"\.[^.]+$", "", original_filename) + ".png") |
| 122 | + remove_file_list = [".jpg", ".JPG", ".jpeg", ".JPEG", ".PNG"] |
| 123 | + for remove_file in remove_file_list: |
| 124 | + remove_file_name = re.sub(r"\.[^.]+$", "", original_filename) + remove_file |
| 125 | + remove_file_path = os.path.join(return_path, remove_file_name) |
| 126 | + if os.path.isfile(remove_file_path): |
| 127 | + os.remove(remove_file_path) |
| 128 | + else: |
| 129 | + filename = os.path.join( |
| 130 | + return_path, |
| 131 | + output_dir, |
| 132 | + re.sub(r"\.[^.]+$", "_", original_filename) |
| 133 | + + "_{0}_converted_at_{1}.png".format(extension, timestamp)) |
| 134 | + psr = Processor( |
| 135 | + image=image, |
| 136 | + colorautoadjust=colorautoadjust, |
| 137 | + colorstretch=colorstretch, |
| 138 | + grayscale=grayscale, |
| 139 | + color=color, |
| 140 | + contrast=contrast, |
| 141 | + brightness=brightness, |
| 142 | + sharpness=sharpness, |
| 143 | + invert=invert, |
| 144 | + tosaka=tosaka, |
| 145 | + outputrgb=outputrgb, |
| 146 | + cyanotype=cyanotype, |
| 147 | + sepia=sepia, |
| 148 | + noise=noise, |
| 149 | + line_drawing=line_drawing, |
| 150 | + posterize=posterize, |
| 151 | + ) |
| 152 | + saved_image = psr.process() |
| 153 | + os.makedirs(os.path.join(return_path, output_dir), exist_ok=True) |
| 154 | + saved_image.save( |
| 155 | + filename, |
| 156 | + quality=100, # Specify 100 as the highest image quality |
| 157 | + subsampling=0, |
| 158 | + exif=exif, |
| 159 | + ) |
| 160 | + print("{0}/{1} done!".format((i + 1), str(len(files_glob)))) |
12 | 161 |
|
13 | | -if __name__ == "__main__": |
14 | | - main() |
| 162 | + return "The cli was completed successfully." |
0 commit comments