|
2 | 2 | Two helper classes for dealing with PNG images and their path names. |
3 | 3 | PngWriter -- Converts Images generated by T2I into PNGs, finds |
4 | 4 | appropriate names for them, and writes prompt metadata |
5 | | - into the PNG. Intended to be subclassable in order to |
6 | | - create more complex naming schemes, including using the |
7 | | - prompt for file/directory names. |
| 5 | + into the PNG. |
8 | 6 | PromptFormatter -- Utility for converting a Namespace of prompt parameters |
9 | 7 | back into a formatted prompt string with command-line switches. |
10 | 8 | """ |
11 | 9 | import os |
12 | 10 | import re |
13 | | -from math import sqrt, floor, ceil |
14 | | -from PIL import Image, PngImagePlugin |
| 11 | +from PIL import PngImagePlugin |
15 | 12 |
|
16 | 13 | # -------------------image generation utils----- |
17 | 14 |
|
18 | 15 |
|
19 | 16 | class PngWriter: |
20 | | - def __init__(self, outdir, prompt=None): |
| 17 | + def __init__(self, outdir): |
21 | 18 | self.outdir = outdir |
22 | | - self.prompt = prompt |
23 | | - self.filepath = None |
24 | | - self.files_written = [] |
25 | 19 | os.makedirs(outdir, exist_ok=True) |
26 | 20 |
|
27 | | - def write_image(self, image, seed, upscaled=False): |
28 | | - self.filepath = self.unique_filename( |
29 | | - seed, upscaled, self.filepath |
30 | | - ) # will increment name in some sensible way |
31 | | - try: |
32 | | - prompt = f'{self.prompt} -S{seed}' |
33 | | - self.save_image_and_prompt_to_png(image, prompt, self.filepath) |
34 | | - except IOError as e: |
35 | | - print(e) |
36 | | - if not upscaled: |
37 | | - self.files_written.append([self.filepath, seed]) |
38 | | - |
39 | | - def unique_filename(self, seed, upscaled=False, previouspath=None): |
40 | | - revision = 1 |
41 | | - |
42 | | - if previouspath is None: |
43 | | - # sort reverse alphabetically until we find max+1 |
44 | | - dirlist = sorted(os.listdir(self.outdir), reverse=True) |
45 | | - # find the first filename that matches our pattern or return 000000.0.png |
46 | | - filename = next( |
47 | | - (f for f in dirlist if re.match('^(\d+)\..*\.png', f)), |
48 | | - '0000000.0.png', |
49 | | - ) |
50 | | - basecount = int(filename.split('.', 1)[0]) |
51 | | - basecount += 1 |
52 | | - filename = f'{basecount:06}.{seed}.png' |
53 | | - return os.path.join(self.outdir, filename) |
54 | | - |
55 | | - else: |
56 | | - basename = os.path.basename(previouspath) |
57 | | - x = re.match('^(\d+)\..*\.png', basename) |
58 | | - if not x: |
59 | | - return self.unique_filename(seed, upscaled, previouspath) |
60 | | - |
61 | | - basecount = int(x.groups()[0]) |
62 | | - series = 0 |
63 | | - finished = False |
64 | | - while not finished: |
65 | | - series += 1 |
66 | | - filename = f'{basecount:06}.{seed}.png' |
67 | | - path = os.path.join(self.outdir, filename) |
68 | | - if os.path.exists(path) and upscaled: |
69 | | - break |
70 | | - finished = not os.path.exists(path) |
71 | | - return os.path.join(self.outdir, filename) |
72 | | - |
73 | | - def save_image_and_prompt_to_png(self, image, prompt, path): |
| 21 | + # gives the next unique prefix in outdir |
| 22 | + def unique_prefix(self): |
| 23 | + # sort reverse alphabetically until we find max+1 |
| 24 | + dirlist = sorted(os.listdir(self.outdir), reverse=True) |
| 25 | + # find the first filename that matches our pattern or return 000000.0.png |
| 26 | + existing_name = next( |
| 27 | + (f for f in dirlist if re.match('^(\d+)\..*\.png', f)), |
| 28 | + '0000000.0.png', |
| 29 | + ) |
| 30 | + basecount = int(existing_name.split('.', 1)[0]) + 1 |
| 31 | + return f'{basecount:06}' |
| 32 | + |
| 33 | + # saves image named _image_ to outdir/name, writing metadata from prompt |
| 34 | + # returns full path of output |
| 35 | + def save_image_and_prompt_to_png(self, image, prompt, name): |
| 36 | + path = os.path.join(self.outdir, name) |
74 | 37 | info = PngImagePlugin.PngInfo() |
75 | 38 | info.add_text('Dream', prompt) |
76 | 39 | image.save(path, 'PNG', pnginfo=info) |
77 | | - |
78 | | - def make_grid(self, image_list, rows=None, cols=None): |
79 | | - image_cnt = len(image_list) |
80 | | - if None in (rows, cols): |
81 | | - rows = floor(sqrt(image_cnt)) # try to make it square |
82 | | - cols = ceil(image_cnt / rows) |
83 | | - width = image_list[0].width |
84 | | - height = image_list[0].height |
85 | | - |
86 | | - grid_img = Image.new('RGB', (width * cols, height * rows)) |
87 | | - i = 0 |
88 | | - for r in range(0, rows): |
89 | | - for c in range(0, cols): |
90 | | - if i>=len(image_list): |
91 | | - break |
92 | | - grid_img.paste(image_list[i], (c * width, r * height)) |
93 | | - i = i + 1 |
94 | | - |
95 | | - return grid_img |
| 40 | + return path |
96 | 41 |
|
97 | 42 |
|
98 | 43 | class PromptFormatter: |
|
0 commit comments