Skip to content

Commit 28fe841

Browse files
committed
optionally scale initial image to fit box defined by width x height
* This functionality is triggered by the --fit option in the CLI (default false), and by the "fit" checkbox in the WebGUI (default True) * In addition, this commit contains a number of whitespace changes to make the code more readable, as well as an attempt to unify the visual appearance of info and warning messages.
1 parent 4b560b5 commit 28fe841

File tree

8 files changed

+232
-182
lines changed

8 files changed

+232
-182
lines changed

ldm/dream/image_util.py

Lines changed: 19 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -8,51 +8,46 @@ def __init__(self,Image):
88

99
def resize(self,width=None,height=None) -> Image:
1010
"""
11-
Return a copy of the image resized to width x height.
12-
The aspect ratio is maintained, with any excess space
13-
filled using black borders (i.e. letterboxed). If
14-
neither width nor height are provided, then returns
15-
a copy of the original image. If one or the other is
11+
Return a copy of the image resized to fit within
12+
a box width x height. The aspect ratio is
13+
maintained. If neither width nor height are provided,
14+
then returns a copy of the original image. If one or the other is
1615
provided, then the other will be calculated from the
1716
aspect ratio.
1817
1918
Everything is floored to the nearest multiple of 64 so
2019
that it can be passed to img2img()
2120
"""
2221
im = self.image
23-
24-
if not(width or height):
25-
return im.copy()
26-
27-
ar = im.width/im.height
22+
23+
ar = im.width/float(im.height)
2824

2925
# Infer missing values from aspect ratio
30-
if not height: # height missing
26+
if not(width or height): # both missing
27+
width = im.width
28+
height = im.height
29+
elif not height: # height missing
3130
height = int(width/ar)
32-
if not width: # width missing
31+
elif not width: # width missing
3332
width = int(height*ar)
3433

3534
# rw and rh are the resizing width and height for the image
3635
# they maintain the aspect ratio, but may not completelyl fill up
3736
# the requested destination size
38-
(rw,rh) = (width,int(width/ar)) if im.width>=im.height else (int(height*ar),width)
37+
(rw,rh) = (width,int(width/ar)) if im.width>=im.height else (int(height*ar),height)
3938

4039
#round everything to multiples of 64
4140
width,height,rw,rh = map(
4241
lambda x: x-x%64, (width,height,rw,rh)
43-
)
42+
)
4443

45-
# resize the original image so that it fits inside the dest
44+
# no resize necessary, but return a copy
45+
if im.width == width and im.height == height:
46+
return im.copy()
47+
48+
# otherwise resize the original image so that it fits inside the bounding box
4649
resized_image = self.image.resize((rw,rh),resample=Image.Resampling.LANCZOS)
47-
48-
# create new destination image of specified dimensions
49-
# and paste the resized image into it centered appropriately
50-
new_image = Image.new('RGB',(width,height))
51-
new_image.paste(resized_image,((width-rw)//2,(height-rh)//2))
52-
53-
print(f'>> Resized image size to {width}x{height}')
54-
55-
return new_image
50+
return resized_image
5651

5752
def make_grid(image_list, rows=None, cols=None):
5853
image_cnt = len(image_list)

ldm/dream/pngwriter.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,8 @@ def normalize_prompt(self):
6161
switches.append(f'-A{opt.sampler_name or t2i.sampler_name}')
6262
if opt.init_img:
6363
switches.append(f'-I{opt.init_img}')
64+
if opt.fit:
65+
switches.append(f'--fit')
6466
if opt.strength and opt.init_img is not None:
6567
switches.append(f'-f{opt.strength or t2i.strength}')
6668
if opt.gfpgan_strength:

ldm/dream/server.py

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ def do_POST(self):
7070
steps = int(post_data['steps'])
7171
width = int(post_data['width'])
7272
height = int(post_data['height'])
73+
fit = 'fit' in post_data
7374
cfgscale = float(post_data['cfgscale'])
7475
sampler_name = post_data['sampler']
7576
gfpgan_strength = float(post_data['gfpgan_strength']) if gfpgan_model_exists else 0
@@ -80,7 +81,7 @@ def do_POST(self):
8081
seed = self.model.seed if int(post_data['seed']) == -1 else int(post_data['seed'])
8182

8283
self.canceled.clear()
83-
print(f"Request to generate with prompt: {prompt}")
84+
print(f">> Request to generate with prompt: {prompt}")
8485
# In order to handle upscaled images, the PngWriter needs to maintain state
8586
# across images generated by each call to prompt2img(), so we define it in
8687
# the outer scope of image_done()
@@ -177,10 +178,13 @@ def image_progress(sample, step):
177178
init_img = "./img2img-tmp.png",
178179
strength = strength,
179180
iterations = iterations,
180-
cfg_scale = cfgscale,
181-
seed = seed,
182-
steps = steps,
181+
cfg_scale = cfgscale,
182+
seed = seed,
183+
steps = steps,
183184
sampler_name = sampler_name,
185+
width = width,
186+
height = height,
187+
fit = fit,
184188
gfpgan_strength=gfpgan_strength,
185189
upscale = upscale,
186190
step_callback=image_progress,
@@ -192,8 +196,6 @@ def image_progress(sample, step):
192196
print(f"Canceled.")
193197
return
194198

195-
print(f"Prompt generated!")
196-
197199

198200
class ThreadingDreamServer(ThreadingHTTPServer):
199201
def __init__(self, server_address):

ldm/gfpgan/gfpgan_tools.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
gfpgan_model_exists = os.path.isfile(model_path)
1515

1616
def _run_gfpgan(image, strength, prompt, seed, upsampler_scale=4):
17-
print(f'\n* GFPGAN - Restoring Faces: {prompt} : seed:{seed}')
17+
print(f'>> GFPGAN - Restoring Faces: {prompt} : seed:{seed}')
1818
gfpgan = None
1919
with warnings.catch_warnings():
2020
warnings.filterwarnings('ignore', category=DeprecationWarning)
@@ -41,12 +41,12 @@ def _run_gfpgan(image, strength, prompt, seed, upsampler_scale=4):
4141
except Exception:
4242
import traceback
4343

44-
print('Error loading GFPGAN:', file=sys.stderr)
44+
print('>> Error loading GFPGAN:', file=sys.stderr)
4545
print(traceback.format_exc(), file=sys.stderr)
4646

4747
if gfpgan is None:
4848
print(
49-
f'GFPGAN not initialized, it must be loaded via the --gfpgan argument'
49+
f'>> GFPGAN not initialized, it must be loaded via the --gfpgan argument'
5050
)
5151
return image
5252

@@ -129,7 +129,7 @@ def _load_gfpgan_bg_upsampler(bg_upsampler, upsampler_scale, bg_tile=400):
129129

130130
def real_esrgan_upscale(image, strength, upsampler_scale, prompt, seed):
131131
print(
132-
f'\n* Real-ESRGAN Upscaling: {prompt} : seed:{seed} : scale:{upsampler_scale}x'
132+
f'>> Real-ESRGAN Upscaling: {prompt} : seed:{seed} : scale:{upsampler_scale}x'
133133
)
134134

135135
with warnings.catch_warnings():
@@ -143,7 +143,7 @@ def real_esrgan_upscale(image, strength, upsampler_scale, prompt, seed):
143143
except Exception:
144144
import traceback
145145

146-
print('Error loading Real-ESRGAN:', file=sys.stderr)
146+
print('>> Error loading Real-ESRGAN:', file=sys.stderr)
147147
print(traceback.format_exc(), file=sys.stderr)
148148

149149
output, img_mode = upsampler.enhance(

0 commit comments

Comments
 (0)