artificialguybr commited on
Commit
d58e89b
1 Parent(s): 07b8c5e

Upload 9 files

Browse files
scripts/__pycache__/pixelart.cpython-310.pyc ADDED
Binary file (4.38 kB). View file
 
scripts/__pycache__/postprocessing_pixelart.cpython-310.pyc ADDED
Binary file (4.33 kB). View file
 
scripts/__pycache__/utils.cpython-310.pyc ADDED
Binary file (2.2 kB). View file
 
scripts/pixelart.py ADDED
@@ -0,0 +1,148 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+
3
+ import modules.scripts as scripts
4
+ from modules import images
5
+ from modules.shared import opts
6
+
7
+ from sd_webui_pixelart.utils import DITHER_METHODS, QUANTIZATION_METHODS, downscale_image, limit_colors, resize_image, convert_to_black_and_white, convert_to_grayscale
8
+
9
+ class Script(scripts.Script):
10
+ def title(self):
11
+ return "Pixel art"
12
+
13
+
14
+ def show(self, is_img2img):
15
+ return scripts.AlwaysVisible
16
+
17
+
18
+ def ui(self, is_img2img):
19
+ quantization_methods = ['Median cut', 'Maximum coverage', 'Fast octree']
20
+ dither_methods = ['None', 'Floyd-Steinberg']
21
+
22
+ with gr.Accordion("Pixel art", open=False):
23
+ with gr.Row():
24
+ enabled = gr.Checkbox(label="Enable", value=False)
25
+
26
+ with gr.Column():
27
+ with gr.Row():
28
+ downscale = gr.Slider(label="Downscale", minimum=1, maximum=32, step=2, value=8)
29
+ need_rescale = gr.Checkbox(label="Rescale to original size", value=True)
30
+ with gr.Tabs():
31
+ with gr.TabItem("Color"):
32
+ enable_color_limit = gr.Checkbox(label="Enable", value=False)
33
+ number_of_colors = gr.Slider(label="Palette Size", minimum=1, maximum=256, step=1, value=16)
34
+ quantization_method = gr.Radio(choices=quantization_methods, value=quantization_methods[0], label='Colors quantization method')
35
+ dither_method = gr.Radio(choices=dither_methods, value=dither_methods[0], label='Colors dither method')
36
+ use_k_means = gr.Checkbox(label="Enable k-means for color quantization", value=True)
37
+ with gr.TabItem("Grayscale"):
38
+ is_grayscale = gr.Checkbox(label="Enable", value=False)
39
+ number_of_shades = gr.Slider(label="Palette Size", minimum=1, maximum=256, step=1, value=16)
40
+ quantization_method_grayscale = gr.Radio(choices=quantization_methods, value=quantization_methods[0], label='Colors quantization method')
41
+ dither_method_grayscale = gr.Radio(choices=dither_methods, value=dither_methods[0], label='Colors dither method')
42
+ use_k_means_grayscale = gr.Checkbox(label="Enable k-means for color quantization", value=True)
43
+ with gr.TabItem("Black and white"):
44
+ with gr.Row():
45
+ is_black_and_white = gr.Checkbox(label="Enable", value=False)
46
+ is_inversed_black_and_white = gr.Checkbox(label="Inverse", value=False)
47
+ with gr.Row():
48
+ black_and_white_threshold = gr.Slider(label="Threshold", minimum=1, maximum=256, step=1, value=128)
49
+ with gr.TabItem("Custom color palette"):
50
+ use_color_palette = gr.Checkbox(label="Enable", value=False)
51
+ palette_image=gr.Image(label="Color palette image", type="pil")
52
+ palette_colors = gr.Slider(label="Palette Size (only for complex images)", minimum=1, maximum=256, step=1, value=16)
53
+ dither_method_palette = gr.Radio(choices=dither_methods, value=dither_methods[0], label='Colors dither method')
54
+
55
+ return [enabled, downscale, need_rescale, enable_color_limit, number_of_colors, quantization_method, dither_method, use_k_means, is_grayscale, number_of_shades, quantization_method_grayscale, dither_method_grayscale, use_k_means_grayscale, is_black_and_white, is_inversed_black_and_white, black_and_white_threshold, use_color_palette, palette_image, palette_colors, dither_method_palette]
56
+
57
+ def postprocess(
58
+ self,
59
+ p,
60
+ processed,
61
+ enabled,
62
+
63
+ downscale,
64
+ need_rescale,
65
+
66
+ enable_color_limit,
67
+ number_of_colors,
68
+ quantization_method,
69
+ dither_method,
70
+ use_k_means,
71
+
72
+ is_grayscale,
73
+ number_of_shades,
74
+ quantization_method_grayscale,
75
+ dither_method_grayscale,
76
+ use_k_means_grayscale,
77
+
78
+ is_black_and_white,
79
+ is_inversed_black_and_white,
80
+ black_and_white_threshold,
81
+
82
+ use_color_palette,
83
+ palette_image,
84
+ palette_colors,
85
+ dither_method_palette
86
+ ):
87
+ if not enabled:
88
+ return
89
+
90
+ dither = DITHER_METHODS[dither_method]
91
+ quantize = QUANTIZATION_METHODS[quantization_method]
92
+ dither_grayscale = DITHER_METHODS[dither_method_grayscale]
93
+ quantize_grayscale = QUANTIZATION_METHODS[quantization_method_grayscale]
94
+ dither_palette = DITHER_METHODS[dither_method_palette]
95
+
96
+ def process_image(original_image):
97
+ original_width, original_height = original_image.size
98
+
99
+ if original_image.mode != "RGB":
100
+ new_image = original_image.convert("RGB")
101
+ else:
102
+ new_image = original_image
103
+
104
+ new_image = downscale_image(new_image, downscale)
105
+
106
+ if use_color_palette:
107
+ new_image = limit_colors(
108
+ image=new_image,
109
+ palette=palette_image,
110
+ palette_colors=palette_colors,
111
+ dither=dither_palette
112
+ )
113
+
114
+ if is_black_and_white:
115
+ new_image = convert_to_black_and_white(new_image, black_and_white_threshold, is_inversed_black_and_white)
116
+
117
+ if is_grayscale:
118
+ new_image = convert_to_grayscale(new_image)
119
+ new_image = limit_colors(
120
+ image=new_image,
121
+ limit=int(number_of_shades),
122
+ quantize=quantize_grayscale,
123
+ dither=dither_grayscale,
124
+ use_k_means=use_k_means_grayscale
125
+ )
126
+
127
+ if enable_color_limit:
128
+ new_image = limit_colors(
129
+ image=new_image,
130
+ limit=int(number_of_colors),
131
+ quantize=quantize,
132
+ dither=dither,
133
+ use_k_means=use_k_means
134
+ )
135
+
136
+ if need_rescale:
137
+ new_image = resize_image(new_image, (original_width, original_height))
138
+
139
+ return new_image.convert('RGBA')
140
+
141
+ for i in range(len(processed.images)):
142
+ pixel_image = process_image(processed.images[i])
143
+ processed.images.append(pixel_image)
144
+
145
+ images.save_image(pixel_image, p.outpath_samples, "pixel",
146
+ processed.seed + i, processed.prompt, opts.samples_format, info= processed.info, p=p)
147
+
148
+ return processed
scripts/postprocessing_pixelart.py ADDED
@@ -0,0 +1,166 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ from PIL import features
3
+
4
+ from modules import scripts_postprocessing
5
+ from modules.shared import opts
6
+
7
+ from sd_webui_pixelart.utils import DITHER_METHODS, QUANTIZATION_METHODS, downscale_image, limit_colors, resize_image, convert_to_grayscale, convert_to_black_and_white
8
+
9
+
10
+ class ScriptPostprocessingUpscale(scripts_postprocessing.ScriptPostprocessing):
11
+ name = "Pixel art"
12
+ order = 20005
13
+ model = None
14
+
15
+ def ui(self):
16
+ quantization_methods = ['Median cut', 'Maximum coverage', 'Fast octree']
17
+ dither_methods = ['None', 'Floyd-Steinberg']
18
+
19
+ if features.check_feature("libimagequant"):
20
+ quantization_methods.insert(0, "libimagequant")
21
+
22
+ with gr.Blocks():
23
+ with gr.Accordion(label="Pixel art", open=False):
24
+ enabled = gr.Checkbox(label="Enable", value=False)
25
+ with gr.Row():
26
+ downscale = gr.Slider(label="Downscale", minimum=1, maximum=32, step=2, value=8)
27
+ need_rescale = gr.Checkbox(label="Rescale to original size", value=True)
28
+ with gr.Tabs():
29
+ with gr.TabItem("Color"):
30
+ enable_color_limit = gr.Checkbox(label="Enable", value=False)
31
+ number_of_colors = gr.Slider(label="Palette Size", minimum=1, maximum=256, step=1, value=16)
32
+ quantization_method = gr.Radio(choices=quantization_methods, value=quantization_methods[0], label='Colors quantization method')
33
+ dither_method = gr.Radio(choices=dither_methods, value=dither_methods[0], label='Colors dither method')
34
+ use_k_means = gr.Checkbox(label="Enable k-means for color quantization", value=True)
35
+ with gr.TabItem("Grayscale"):
36
+ is_grayscale = gr.Checkbox(label="Enable", value=False)
37
+ number_of_shades = gr.Slider(label="Palette Size", minimum=1, maximum=256, step=1, value=16)
38
+ quantization_method_grayscale = gr.Radio(choices=quantization_methods, value=quantization_methods[0], label='Colors quantization method')
39
+ dither_method_grayscale = gr.Radio(choices=dither_methods, value=dither_methods[0], label='Colors dither method')
40
+ use_k_means_grayscale = gr.Checkbox(label="Enable k-means for color quantization", value=True)
41
+ with gr.TabItem("Black and white"):
42
+ with gr.Row():
43
+ black_and_white = gr.Checkbox(label="Enable", value=False)
44
+ inversed_black_and_white = gr.Checkbox(label="Inverse", value=False)
45
+ with gr.Row():
46
+ black_and_white_threshold = gr.Slider(label="Threshold", minimum=1, maximum=256, step=1, value=128)
47
+ with gr.TabItem("Custom color palette"):
48
+ use_color_palette = gr.Checkbox(label="Enable", value=False)
49
+ palette_image=gr.Image(label="Color palette image", type="pil")
50
+ palette_colors = gr.Slider(label="Palette Size (only for complex images)", minimum=1, maximum=256, step=1, value=16)
51
+ dither_method_palette = gr.Radio(choices=dither_methods, value=dither_methods[0], label='Colors dither method')
52
+
53
+ return {
54
+ "enabled": enabled,
55
+
56
+ "downscale": downscale,
57
+ "need_rescale": need_rescale,
58
+
59
+ "enable_color_limit": enable_color_limit,
60
+ "number_of_colors": number_of_colors,
61
+ "quantization_method": quantization_method,
62
+ "dither_method": dither_method,
63
+ "use_k_means": use_k_means,
64
+
65
+ "is_grayscale": is_grayscale,
66
+ "number_of_shades": number_of_shades,
67
+ "quantization_method_grayscale": quantization_method_grayscale,
68
+ "dither_method_grayscale": dither_method_grayscale,
69
+ "use_k_means_grayscale": use_k_means_grayscale,
70
+
71
+ "use_color_palette": use_color_palette,
72
+ "palette_image": palette_image,
73
+ "palette_colors": palette_colors,
74
+ "dither_method_palette": dither_method_palette,
75
+
76
+ "black_and_white": black_and_white,
77
+ "inversed_black_and_white": inversed_black_and_white,
78
+ "black_and_white_threshold": black_and_white_threshold,
79
+ }
80
+
81
+
82
+ def process(
83
+ self,
84
+ pp: scripts_postprocessing.PostprocessedImage,
85
+
86
+ enabled,
87
+
88
+ downscale,
89
+ need_rescale,
90
+
91
+ enable_color_limit,
92
+ number_of_colors,
93
+ quantization_method,
94
+ dither_method,
95
+ use_k_means,
96
+
97
+ is_grayscale,
98
+ number_of_shades,
99
+ quantization_method_grayscale,
100
+ dither_method_grayscale,
101
+ use_k_means_grayscale,
102
+
103
+ use_color_palette,
104
+ palette_image,
105
+ palette_colors,
106
+ dither_method_palette,
107
+
108
+ black_and_white,
109
+ inversed_black_and_white,
110
+ black_and_white_threshold
111
+ ):
112
+ dither = DITHER_METHODS[dither_method]
113
+ quantize = QUANTIZATION_METHODS[quantization_method]
114
+ dither_grayscale = DITHER_METHODS[dither_method_grayscale]
115
+ quantize_grayscale = QUANTIZATION_METHODS[quantization_method_grayscale]
116
+ dither_palette = DITHER_METHODS[dither_method_palette]
117
+
118
+ if not enabled:
119
+ return
120
+
121
+ def process_image(original_image):
122
+ original_width, original_height = original_image.size
123
+
124
+ if original_image.mode != "RGB":
125
+ new_image = original_image.convert("RGB")
126
+ else:
127
+ new_image = original_image
128
+
129
+ new_image = downscale_image(new_image, downscale)
130
+
131
+ if use_color_palette:
132
+ new_image = limit_colors(
133
+ image=new_image,
134
+ palette=palette_image,
135
+ palette_colors=palette_colors,
136
+ dither=dither_palette
137
+ )
138
+
139
+ if black_and_white:
140
+ new_image = convert_to_black_and_white(new_image, black_and_white_threshold, inversed_black_and_white)
141
+
142
+ if is_grayscale:
143
+ new_image = convert_to_grayscale(new_image)
144
+ new_image = limit_colors(
145
+ image=new_image,
146
+ limit=int(number_of_shades),
147
+ quantize=quantize_grayscale,
148
+ dither=dither_grayscale,
149
+ use_k_means=use_k_means_grayscale
150
+ )
151
+
152
+ if enable_color_limit:
153
+ new_image = limit_colors(
154
+ image=new_image,
155
+ limit=int(number_of_colors),
156
+ quantize=quantize,
157
+ dither=dither,
158
+ use_k_means=use_k_means
159
+ )
160
+
161
+ if need_rescale:
162
+ new_image = resize_image(new_image, (original_width, original_height))
163
+
164
+ return new_image.convert('RGBA')
165
+
166
+ pp.image = process_image(pp.image)
sd_webui_pixelart/__init__.py ADDED
File without changes
sd_webui_pixelart/__pycache__/__init__.cpython-310.pyc ADDED
Binary file (205 Bytes). View file
 
sd_webui_pixelart/__pycache__/utils.cpython-310.pyc ADDED
Binary file (2.35 kB). View file
 
sd_webui_pixelart/utils.py ADDED
@@ -0,0 +1,75 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from PIL import Image
2
+
3
+ # https://pillow.readthedocs.io/en/stable/reference/Image.html#dither-modes
4
+ DITHER_METHODS = {
5
+ "None": Image.Dither.NONE,
6
+ "Floyd-Steinberg": Image.Dither.FLOYDSTEINBERG
7
+ }
8
+
9
+ #https://pillow.readthedocs.io/en/stable/reference/Image.html#quantization-methods
10
+ QUANTIZATION_METHODS = {
11
+ "Median cut": Image.Quantize.MEDIANCUT,
12
+ "Maximum coverage": Image.Quantize.MAXCOVERAGE,
13
+ "Fast octree": Image.Quantize.FASTOCTREE,
14
+ "libimagequant": Image.Quantize.LIBIMAGEQUANT
15
+ }
16
+
17
+
18
+ def downscale_image(image: Image, scale: int) -> Image:
19
+ width, height = image.size
20
+ downscaled_image = image.resize((int(width / scale), int(height / scale)), Image.NEAREST)
21
+ return downscaled_image
22
+
23
+
24
+ def resize_image(image: Image, size) -> Image:
25
+ width, height = size
26
+ resized_image = image.resize((width, height), Image.NEAREST)
27
+ return resized_image
28
+
29
+
30
+ def limit_colors(
31
+ image,
32
+ limit: int=16,
33
+ palette=None,
34
+ palette_colors: int=256,
35
+ quantize: Image.Quantize=Image.Quantize.MEDIANCUT,
36
+ dither: Image.Dither=Image.Dither.NONE,
37
+ use_k_means: bool=False
38
+ ):
39
+ if use_k_means:
40
+ k_means_value = limit
41
+ else:
42
+ k_means_value = 0
43
+
44
+ if palette:
45
+ palette_image = palette
46
+ ppalette = palette.getcolors()
47
+ if ppalette:
48
+ color_palette = palette.quantize(colors=len(list(set(ppalette))))
49
+ else:
50
+ colors = len(palette_image.getcolors()) if palette_image.getcolors() else palette_colors
51
+ color_palette = palette_image.quantize(colors, kmeans=colors)
52
+ else:
53
+ # we need to get palette from image, because
54
+ # dither in quantize doesn't work without it
55
+ # https://pillow.readthedocs.io/en/stable/_modules/PIL/Image.html#Image.quantize
56
+ color_palette = image.quantize(colors=limit, kmeans=k_means_value, method=quantize, dither=Image.Dither.NONE)
57
+
58
+ new_image = image.quantize(palette=color_palette, dither=dither)
59
+
60
+ return new_image
61
+
62
+
63
+ def convert_to_grayscale(image):
64
+ new_image = image.convert("L")
65
+ return new_image.convert("RGB")
66
+
67
+
68
+ def convert_to_black_and_white(image: Image, threshold: int=128, is_inversed: bool=False):
69
+ if is_inversed:
70
+ apply_threshold = lambda x : 255 if x < threshold else 0
71
+ else:
72
+ apply_threshold = lambda x : 255 if x > threshold else 0
73
+
74
+ black_and_white_image = image.convert('L', dither=Image.Dither.NONE).point(apply_threshold, mode='1')
75
+ return black_and_white_image.convert("RGB")