2023-03-03 06:02:00 +00:00
"""
invokeai . backend . generator . embiggen descends from . generator
and generates with . generator . img2img
"""
2023-02-28 05:37:13 +00:00
import numpy as np
import torch
from PIL import Image
from tqdm import trange
from . base import Generator
from . img2img import Img2Img
class Embiggen ( Generator ) :
def __init__ ( self , model , precision ) :
super ( ) . __init__ ( model , precision )
2023-03-03 06:02:00 +00:00
self . init_latent = None
2023-02-28 05:37:13 +00:00
# Replace generate because Embiggen doesn't need/use most of what it does normallly
2023-03-03 06:02:00 +00:00
def generate (
self ,
prompt ,
iterations = 1 ,
seed = None ,
image_callback = None ,
step_callback = None ,
* * kwargs ,
) :
make_image = self . get_make_image ( prompt , step_callback = step_callback , * * kwargs )
results = [ ]
seed = seed if seed else self . new_seed ( )
2023-02-28 05:37:13 +00:00
# Noise will be generated by the Img2Img generator when called
2023-03-03 06:02:00 +00:00
for _ in trange ( iterations , desc = " Generating " ) :
2023-02-28 05:37:13 +00:00
# make_image will call Img2Img which will do the equivalent of get_noise itself
image = make_image ( )
results . append ( [ image , seed ] )
if image_callback is not None :
image_callback ( image , seed , prompt_in = prompt )
seed = self . new_seed ( )
return results
@torch.no_grad ( )
def get_make_image (
self ,
prompt ,
sampler ,
steps ,
cfg_scale ,
ddim_eta ,
conditioning ,
init_img ,
strength ,
width ,
height ,
embiggen ,
embiggen_tiles ,
step_callback = None ,
2023-03-03 06:02:00 +00:00
* * kwargs ,
2023-02-28 05:37:13 +00:00
) :
"""
Returns a function returning an image derived from the prompt and multi - stage twice - baked potato layering over the img2img on the initial image
Return value depends on the seed at the time you call it
"""
2023-03-03 06:02:00 +00:00
assert (
not sampler . uses_inpainting_model ( )
) , " --embiggen is not supported by inpainting models "
2023-02-28 05:37:13 +00:00
# Construct embiggen arg array, and sanity check arguments
if embiggen == None : # embiggen can also be called with just embiggen_tiles
embiggen = [ 1.0 ] # If not specified, assume no scaling
elif embiggen [ 0 ] < 0 :
embiggen [ 0 ] = 1.0
print (
2023-03-03 06:02:00 +00:00
" >> Embiggen scaling factor cannot be negative, fell back to the default of 1.0 ! "
)
2023-02-28 05:37:13 +00:00
if len ( embiggen ) < 2 :
embiggen . append ( 0.75 )
elif embiggen [ 1 ] > 1.0 or embiggen [ 1 ] < 0 :
embiggen [ 1 ] = 0.75
2023-03-03 06:02:00 +00:00
print (
" >> Embiggen upscaling strength for ESRGAN must be between 0 and 1, fell back to the default of 0.75 ! "
)
2023-02-28 05:37:13 +00:00
if len ( embiggen ) < 3 :
embiggen . append ( 0.25 )
elif embiggen [ 2 ] < 0 :
embiggen [ 2 ] = 0.25
2023-03-03 06:02:00 +00:00
print (
" >> Overlap size for Embiggen must be a positive ratio between 0 and 1 OR a number of pixels, fell back to the default of 0.25 ! "
)
2023-02-28 05:37:13 +00:00
# Convert tiles from their user-freindly count-from-one to count-from-zero, because we need to do modulo math
# and then sort them, because... people.
if embiggen_tiles :
2023-03-03 06:02:00 +00:00
embiggen_tiles = list ( map ( lambda n : n - 1 , embiggen_tiles ) )
2023-02-28 05:37:13 +00:00
embiggen_tiles . sort ( )
if strength > = 0.5 :
2023-03-03 06:02:00 +00:00
print (
f " * WARNING: Embiggen may produce mirror motifs if the strength (-f) is too high (currently { strength } ). Try values between 0.35-0.45. "
)
2023-02-28 05:37:13 +00:00
# Prep img2img generator, since we wrap over it
2023-03-03 06:02:00 +00:00
gen_img2img = Img2Img ( self . model , self . precision )
2023-02-28 05:37:13 +00:00
# Open original init image (not a tensor) to manipulate
initsuperimage = Image . open ( init_img )
with Image . open ( init_img ) as img :
2023-03-03 06:02:00 +00:00
initsuperimage = img . convert ( " RGB " )
2023-02-28 05:37:13 +00:00
# Size of the target super init image in pixels
initsuperwidth , initsuperheight = initsuperimage . size
# Increase by scaling factor if not already resized, using ESRGAN as able
if embiggen [ 0 ] != 1.0 :
2023-03-03 06:02:00 +00:00
initsuperwidth = round ( initsuperwidth * embiggen [ 0 ] )
initsuperheight = round ( initsuperheight * embiggen [ 0 ] )
2023-02-28 05:37:13 +00:00
if embiggen [ 1 ] > 0 : # No point in ESRGAN upscaling if strength is set zero
2023-03-03 06:02:00 +00:00
from . . restoration . realesrgan import ESRGAN
2023-02-28 05:37:13 +00:00
esrgan = ESRGAN ( )
print (
2023-03-03 06:02:00 +00:00
f " >> ESRGAN upscaling init image prior to cutting with Embiggen with strength { embiggen [ 1 ] } "
)
2023-02-28 05:37:13 +00:00
if embiggen [ 0 ] > 2 :
initsuperimage = esrgan . process (
initsuperimage ,
embiggen [ 1 ] , # upscale strength
self . seed ,
4 , # upscale scale
)
else :
initsuperimage = esrgan . process (
initsuperimage ,
embiggen [ 1 ] , # upscale strength
self . seed ,
2 , # upscale scale
)
# We could keep recursively re-running ESRGAN for a requested embiggen[0] larger than 4x
# but from personal experiance it doesn't greatly improve anything after 4x
# Resize to target scaling factor resolution
initsuperimage = initsuperimage . resize (
2023-03-03 06:02:00 +00:00
( initsuperwidth , initsuperheight ) , Image . Resampling . LANCZOS
)
2023-02-28 05:37:13 +00:00
# Use width and height as tile widths and height
# Determine buffer size in pixels
if embiggen [ 2 ] < 1 :
if embiggen [ 2 ] < 0 :
embiggen [ 2 ] = 0
overlap_size_x = round ( embiggen [ 2 ] * width )
overlap_size_y = round ( embiggen [ 2 ] * height )
else :
overlap_size_x = round ( embiggen [ 2 ] )
overlap_size_y = round ( embiggen [ 2 ] )
# With overall image width and height known, determine how many tiles we need
def ceildiv ( a , b ) :
return - 1 * ( - a / / b )
# X and Y needs to be determined independantly (we may have savings on one based on the buffer pixel count)
# (initsuperwidth - width) is the area remaining to the right that we need to layers tiles to fill
# (width - overlap_size_x) is how much new we can fill with a single tile
emb_tiles_x = 1
emb_tiles_y = 1
if ( initsuperwidth - width ) > 0 :
2023-03-03 06:02:00 +00:00
emb_tiles_x = ceildiv ( initsuperwidth - width , width - overlap_size_x ) + 1
2023-02-28 05:37:13 +00:00
if ( initsuperheight - height ) > 0 :
2023-03-03 06:02:00 +00:00
emb_tiles_y = ceildiv ( initsuperheight - height , height - overlap_size_y ) + 1
2023-02-28 05:37:13 +00:00
# Sanity
2023-03-03 06:02:00 +00:00
assert (
emb_tiles_x > 1 or emb_tiles_y > 1
) , f " ERROR: Based on the requested dimensions of { initsuperwidth } x { initsuperheight } and tiles of { width } x { height } you don ' t need to Embiggen! Check your arguments. "
2023-02-28 05:37:13 +00:00
# Prep alpha layers --------------
# https://stackoverflow.com/questions/69321734/how-to-create-different-transparency-like-gradient-with-python-pil
# agradientL is Left-side transparent
2023-03-03 06:02:00 +00:00
agradientL = (
Image . linear_gradient ( " L " ) . rotate ( 90 ) . resize ( ( overlap_size_x , height ) )
)
2023-02-28 05:37:13 +00:00
# agradientT is Top-side transparent
2023-03-03 06:02:00 +00:00
agradientT = Image . linear_gradient ( " L " ) . resize ( ( width , overlap_size_y ) )
2023-02-28 05:37:13 +00:00
# radial corner is the left-top corner, made full circle then cut to just the left-top quadrant
2023-03-03 06:02:00 +00:00
agradientC = Image . new ( " L " , ( 256 , 256 ) )
2023-02-28 05:37:13 +00:00
for y in range ( 256 ) :
for x in range ( 256 ) :
# Find distance to lower right corner (numpy takes arrays)
distanceToLR = np . sqrt ( [ ( 255 - x ) * * 2 + ( 255 - y ) * * 2 ] ) [ 0 ]
# Clamp values to max 255
if distanceToLR > 255 :
distanceToLR = 255
2023-03-03 06:02:00 +00:00
# Place the pixel as invert of distance
2023-02-28 05:37:13 +00:00
agradientC . putpixel ( ( x , y ) , round ( 255 - distanceToLR ) )
# Create alternative asymmetric diagonal corner to use on "tailing" intersections to prevent hard edges
# Fits for a left-fading gradient on the bottom side and full opacity on the right side.
2023-03-03 06:02:00 +00:00
agradientAsymC = Image . new ( " L " , ( 256 , 256 ) )
2023-02-28 05:37:13 +00:00
for y in range ( 256 ) :
for x in range ( 256 ) :
2023-03-03 06:02:00 +00:00
value = round ( max ( 0 , x - ( 255 - y ) ) * ( 255 / max ( 1 , y ) ) )
# Clamp values
2023-02-28 05:37:13 +00:00
value = max ( 0 , value )
value = min ( 255 , value )
agradientAsymC . putpixel ( ( x , y ) , value )
# Create alpha layers default fully white
alphaLayerL = Image . new ( " L " , ( width , height ) , 255 )
alphaLayerT = Image . new ( " L " , ( width , height ) , 255 )
alphaLayerLTC = Image . new ( " L " , ( width , height ) , 255 )
# Paste gradients into alpha layers
alphaLayerL . paste ( agradientL , ( 0 , 0 ) )
alphaLayerT . paste ( agradientT , ( 0 , 0 ) )
alphaLayerLTC . paste ( agradientL , ( 0 , 0 ) )
alphaLayerLTC . paste ( agradientT , ( 0 , 0 ) )
alphaLayerLTC . paste ( agradientC . resize ( ( overlap_size_x , overlap_size_y ) ) , ( 0 , 0 ) )
# make masks with an asymmetric upper-right corner so when the curved transparent corner of the next tile
# to its right is placed it doesn't reveal a hard trailing semi-transparent edge in the overlapping space
alphaLayerTaC = alphaLayerT . copy ( )
2023-03-03 06:02:00 +00:00
alphaLayerTaC . paste (
agradientAsymC . rotate ( 270 ) . resize ( ( overlap_size_x , overlap_size_y ) ) ,
( width - overlap_size_x , 0 ) ,
)
2023-02-28 05:37:13 +00:00
alphaLayerLTaC = alphaLayerLTC . copy ( )
2023-03-03 06:02:00 +00:00
alphaLayerLTaC . paste (
agradientAsymC . rotate ( 270 ) . resize ( ( overlap_size_x , overlap_size_y ) ) ,
( width - overlap_size_x , 0 ) ,
)
2023-02-28 05:37:13 +00:00
if embiggen_tiles :
# Individual unconnected sides
alphaLayerR = Image . new ( " L " , ( width , height ) , 255 )
2023-03-03 06:02:00 +00:00
alphaLayerR . paste ( agradientL . rotate ( 180 ) , ( width - overlap_size_x , 0 ) )
2023-02-28 05:37:13 +00:00
alphaLayerB = Image . new ( " L " , ( width , height ) , 255 )
2023-03-03 06:02:00 +00:00
alphaLayerB . paste ( agradientT . rotate ( 180 ) , ( 0 , height - overlap_size_y ) )
2023-02-28 05:37:13 +00:00
alphaLayerTB = Image . new ( " L " , ( width , height ) , 255 )
alphaLayerTB . paste ( agradientT , ( 0 , 0 ) )
2023-03-03 06:02:00 +00:00
alphaLayerTB . paste ( agradientT . rotate ( 180 ) , ( 0 , height - overlap_size_y ) )
2023-02-28 05:37:13 +00:00
alphaLayerLR = Image . new ( " L " , ( width , height ) , 255 )
alphaLayerLR . paste ( agradientL , ( 0 , 0 ) )
2023-03-03 06:02:00 +00:00
alphaLayerLR . paste ( agradientL . rotate ( 180 ) , ( width - overlap_size_x , 0 ) )
2023-02-28 05:37:13 +00:00
# Sides and corner Layers
alphaLayerRBC = Image . new ( " L " , ( width , height ) , 255 )
2023-03-03 06:02:00 +00:00
alphaLayerRBC . paste ( agradientL . rotate ( 180 ) , ( width - overlap_size_x , 0 ) )
alphaLayerRBC . paste ( agradientT . rotate ( 180 ) , ( 0 , height - overlap_size_y ) )
alphaLayerRBC . paste (
agradientC . rotate ( 180 ) . resize ( ( overlap_size_x , overlap_size_y ) ) ,
( width - overlap_size_x , height - overlap_size_y ) ,
)
2023-02-28 05:37:13 +00:00
alphaLayerLBC = Image . new ( " L " , ( width , height ) , 255 )
alphaLayerLBC . paste ( agradientL , ( 0 , 0 ) )
2023-03-03 06:02:00 +00:00
alphaLayerLBC . paste ( agradientT . rotate ( 180 ) , ( 0 , height - overlap_size_y ) )
alphaLayerLBC . paste (
agradientC . rotate ( 90 ) . resize ( ( overlap_size_x , overlap_size_y ) ) ,
( 0 , height - overlap_size_y ) ,
)
2023-02-28 05:37:13 +00:00
alphaLayerRTC = Image . new ( " L " , ( width , height ) , 255 )
2023-03-03 06:02:00 +00:00
alphaLayerRTC . paste ( agradientL . rotate ( 180 ) , ( width - overlap_size_x , 0 ) )
2023-02-28 05:37:13 +00:00
alphaLayerRTC . paste ( agradientT , ( 0 , 0 ) )
2023-03-03 06:02:00 +00:00
alphaLayerRTC . paste (
agradientC . rotate ( 270 ) . resize ( ( overlap_size_x , overlap_size_y ) ) ,
( width - overlap_size_x , 0 ) ,
)
2023-02-28 05:37:13 +00:00
# All but X layers
alphaLayerABT = Image . new ( " L " , ( width , height ) , 255 )
alphaLayerABT . paste ( alphaLayerLBC , ( 0 , 0 ) )
2023-03-03 06:02:00 +00:00
alphaLayerABT . paste ( agradientL . rotate ( 180 ) , ( width - overlap_size_x , 0 ) )
alphaLayerABT . paste (
agradientC . rotate ( 180 ) . resize ( ( overlap_size_x , overlap_size_y ) ) ,
( width - overlap_size_x , height - overlap_size_y ) ,
)
2023-02-28 05:37:13 +00:00
alphaLayerABL = Image . new ( " L " , ( width , height ) , 255 )
alphaLayerABL . paste ( alphaLayerRTC , ( 0 , 0 ) )
2023-03-03 06:02:00 +00:00
alphaLayerABL . paste ( agradientT . rotate ( 180 ) , ( 0 , height - overlap_size_y ) )
alphaLayerABL . paste (
agradientC . rotate ( 180 ) . resize ( ( overlap_size_x , overlap_size_y ) ) ,
( width - overlap_size_x , height - overlap_size_y ) ,
)
2023-02-28 05:37:13 +00:00
alphaLayerABR = Image . new ( " L " , ( width , height ) , 255 )
alphaLayerABR . paste ( alphaLayerLBC , ( 0 , 0 ) )
alphaLayerABR . paste ( agradientT , ( 0 , 0 ) )
2023-03-03 06:02:00 +00:00
alphaLayerABR . paste (
agradientC . resize ( ( overlap_size_x , overlap_size_y ) ) , ( 0 , 0 )
)
2023-02-28 05:37:13 +00:00
alphaLayerABB = Image . new ( " L " , ( width , height ) , 255 )
alphaLayerABB . paste ( alphaLayerRTC , ( 0 , 0 ) )
alphaLayerABB . paste ( agradientL , ( 0 , 0 ) )
2023-03-03 06:02:00 +00:00
alphaLayerABB . paste (
agradientC . resize ( ( overlap_size_x , overlap_size_y ) ) , ( 0 , 0 )
)
2023-02-28 05:37:13 +00:00
# All-around layer
alphaLayerAA = Image . new ( " L " , ( width , height ) , 255 )
alphaLayerAA . paste ( alphaLayerABT , ( 0 , 0 ) )
alphaLayerAA . paste ( agradientT , ( 0 , 0 ) )
2023-03-03 06:02:00 +00:00
alphaLayerAA . paste (
agradientC . resize ( ( overlap_size_x , overlap_size_y ) ) , ( 0 , 0 )
)
alphaLayerAA . paste (
agradientC . rotate ( 270 ) . resize ( ( overlap_size_x , overlap_size_y ) ) ,
( width - overlap_size_x , 0 ) ,
)
2023-02-28 05:37:13 +00:00
# Clean up temporary gradients
del agradientL
del agradientT
del agradientC
def make_image ( ) :
# Make main tiles -------------------------------------------------
if embiggen_tiles :
2023-03-03 06:02:00 +00:00
print ( f " >> Making { len ( embiggen_tiles ) } Embiggen tiles... " )
2023-02-28 05:37:13 +00:00
else :
print (
2023-03-03 06:02:00 +00:00
f " >> Making { ( emb_tiles_x * emb_tiles_y ) } Embiggen tiles ( { emb_tiles_x } x { emb_tiles_y } )... "
)
2023-02-28 05:37:13 +00:00
emb_tile_store = [ ]
# Although we could use the same seed for every tile for determinism, at higher strengths this may
# produce duplicated structures for each tile and make the tiling effect more obvious
# instead track and iterate a local seed we pass to Img2Img
seed = self . seed
2023-03-03 06:02:00 +00:00
seedintlimit = (
np . iinfo ( np . uint32 ) . max - 1
) # only retreive this one from numpy
2023-02-28 05:37:13 +00:00
for tile in range ( emb_tiles_x * emb_tiles_y ) :
# Don't iterate on first tile
if tile != 0 :
if seed < seedintlimit :
seed + = 1
else :
seed = 0
# Determine if this is a re-run and replace
if embiggen_tiles and not tile in embiggen_tiles :
continue
# Get row and column entries
emb_row_i = tile / / emb_tiles_x
emb_column_i = tile % emb_tiles_x
# Determine bounds to cut up the init image
# Determine upper-left point
if emb_column_i + 1 == emb_tiles_x :
left = initsuperwidth - width
else :
left = round ( emb_column_i * ( width - overlap_size_x ) )
if emb_row_i + 1 == emb_tiles_y :
top = initsuperheight - height
else :
top = round ( emb_row_i * ( height - overlap_size_y ) )
right = left + width
bottom = top + height
# Cropped image of above dimension (does not modify the original)
newinitimage = initsuperimage . crop ( ( left , top , right , bottom ) )
# DEBUG:
# newinitimagepath = init_img[0:-4] + f'_emb_Ti{tile}.png'
# newinitimage.save(newinitimagepath)
if embiggen_tiles :
print (
2023-03-03 06:02:00 +00:00
f " Making tile # { tile + 1 } ( { embiggen_tiles . index ( tile ) + 1 } of { len ( embiggen_tiles ) } requested) "
)
2023-02-28 05:37:13 +00:00
else :
2023-03-03 06:02:00 +00:00
print ( f " Starting { tile + 1 } of { ( emb_tiles_x * emb_tiles_y ) } tiles " )
2023-02-28 05:37:13 +00:00
# create a torch tensor from an Image
2023-03-03 06:02:00 +00:00
newinitimage = np . array ( newinitimage ) . astype ( np . float32 ) / 255.0
2023-02-28 05:37:13 +00:00
newinitimage = newinitimage [ None ] . transpose ( 0 , 3 , 1 , 2 )
newinitimage = torch . from_numpy ( newinitimage )
newinitimage = 2.0 * newinitimage - 1.0
newinitimage = newinitimage . to ( self . model . device )
2023-03-03 06:02:00 +00:00
clear_cuda_cache = (
kwargs [ " clear_cuda_cache " ] if " clear_cuda_cache " in kwargs else None
)
2023-02-28 05:37:13 +00:00
tile_results = gen_img2img . generate (
prompt ,
2023-03-03 06:02:00 +00:00
iterations = 1 ,
seed = seed ,
sampler = sampler ,
steps = steps ,
cfg_scale = cfg_scale ,
conditioning = conditioning ,
ddim_eta = ddim_eta ,
image_callback = None , # called only after the final image is generated
step_callback = step_callback , # called after each intermediate image is generated
width = width ,
height = height ,
init_image = newinitimage , # notice that init_image is different from init_img
mask_image = None ,
strength = strength ,
clear_cuda_cache = clear_cuda_cache ,
2023-02-28 05:37:13 +00:00
)
emb_tile_store . append ( tile_results [ 0 ] [ 0 ] )
# DEBUG (but, also has other uses), worth saving if you want tiles without a transparency overlap to manually composite
# emb_tile_store[-1].save(init_img[0:-4] + f'_emb_To{tile}.png')
del newinitimage
# Sanity check we have them all
2023-03-03 06:02:00 +00:00
if len ( emb_tile_store ) == ( emb_tiles_x * emb_tiles_y ) or (
embiggen_tiles != [ ] and len ( emb_tile_store ) == len ( embiggen_tiles )
) :
outputsuperimage = Image . new ( " RGBA " , ( initsuperwidth , initsuperheight ) )
2023-02-28 05:37:13 +00:00
if embiggen_tiles :
outputsuperimage . alpha_composite (
2023-03-03 06:02:00 +00:00
initsuperimage . convert ( " RGBA " ) , ( 0 , 0 )
)
2023-02-28 05:37:13 +00:00
for tile in range ( emb_tiles_x * emb_tiles_y ) :
if embiggen_tiles :
if tile in embiggen_tiles :
intileimage = emb_tile_store . pop ( 0 )
else :
continue
else :
intileimage = emb_tile_store [ tile ]
2023-03-03 06:02:00 +00:00
intileimage = intileimage . convert ( " RGBA " )
2023-02-28 05:37:13 +00:00
# Get row and column entries
emb_row_i = tile / / emb_tiles_x
emb_column_i = tile % emb_tiles_x
if emb_row_i == 0 and emb_column_i == 0 and not embiggen_tiles :
left = 0
top = 0
else :
# Determine upper-left point
if emb_column_i + 1 == emb_tiles_x :
left = initsuperwidth - width
else :
2023-03-03 06:02:00 +00:00
left = round ( emb_column_i * ( width - overlap_size_x ) )
2023-02-28 05:37:13 +00:00
if emb_row_i + 1 == emb_tiles_y :
top = initsuperheight - height
else :
top = round ( emb_row_i * ( height - overlap_size_y ) )
# Handle gradients for various conditions
# Handle emb_rerun case
if embiggen_tiles :
# top of image
if emb_row_i == 0 :
if emb_column_i == 0 :
2023-03-03 06:02:00 +00:00
if ( tile + 1 ) in embiggen_tiles : # Look-ahead right
if (
tile + emb_tiles_x
) not in embiggen_tiles : # Look-ahead down
2023-02-28 05:37:13 +00:00
intileimage . putalpha ( alphaLayerB )
# Otherwise do nothing on this tile
2023-03-03 06:02:00 +00:00
elif (
tile + emb_tiles_x
) in embiggen_tiles : # Look-ahead down only
2023-02-28 05:37:13 +00:00
intileimage . putalpha ( alphaLayerR )
else :
intileimage . putalpha ( alphaLayerRBC )
elif emb_column_i == emb_tiles_x - 1 :
2023-03-03 06:02:00 +00:00
if (
tile + emb_tiles_x
) in embiggen_tiles : # Look-ahead down
2023-02-28 05:37:13 +00:00
intileimage . putalpha ( alphaLayerL )
else :
intileimage . putalpha ( alphaLayerLBC )
else :
2023-03-03 06:02:00 +00:00
if ( tile + 1 ) in embiggen_tiles : # Look-ahead right
if (
tile + emb_tiles_x
) in embiggen_tiles : # Look-ahead down
2023-02-28 05:37:13 +00:00
intileimage . putalpha ( alphaLayerL )
else :
intileimage . putalpha ( alphaLayerLBC )
2023-03-03 06:02:00 +00:00
elif (
tile + emb_tiles_x
) in embiggen_tiles : # Look-ahead down only
2023-02-28 05:37:13 +00:00
intileimage . putalpha ( alphaLayerLR )
else :
intileimage . putalpha ( alphaLayerABT )
# bottom of image
elif emb_row_i == emb_tiles_y - 1 :
if emb_column_i == 0 :
2023-03-03 06:02:00 +00:00
if ( tile + 1 ) in embiggen_tiles : # Look-ahead right
2023-02-28 05:37:13 +00:00
intileimage . putalpha ( alphaLayerTaC )
else :
intileimage . putalpha ( alphaLayerRTC )
elif emb_column_i == emb_tiles_x - 1 :
# No tiles to look ahead to
intileimage . putalpha ( alphaLayerLTC )
else :
2023-03-03 06:02:00 +00:00
if ( tile + 1 ) in embiggen_tiles : # Look-ahead right
2023-02-28 05:37:13 +00:00
intileimage . putalpha ( alphaLayerLTaC )
else :
intileimage . putalpha ( alphaLayerABB )
# vertical middle of image
else :
if emb_column_i == 0 :
2023-03-03 06:02:00 +00:00
if ( tile + 1 ) in embiggen_tiles : # Look-ahead right
if (
tile + emb_tiles_x
) in embiggen_tiles : # Look-ahead down
2023-02-28 05:37:13 +00:00
intileimage . putalpha ( alphaLayerTaC )
else :
intileimage . putalpha ( alphaLayerTB )
2023-03-03 06:02:00 +00:00
elif (
tile + emb_tiles_x
) in embiggen_tiles : # Look-ahead down only
2023-02-28 05:37:13 +00:00
intileimage . putalpha ( alphaLayerRTC )
else :
intileimage . putalpha ( alphaLayerABL )
elif emb_column_i == emb_tiles_x - 1 :
2023-03-03 06:02:00 +00:00
if (
tile + emb_tiles_x
) in embiggen_tiles : # Look-ahead down
2023-02-28 05:37:13 +00:00
intileimage . putalpha ( alphaLayerLTC )
else :
intileimage . putalpha ( alphaLayerABR )
else :
2023-03-03 06:02:00 +00:00
if ( tile + 1 ) in embiggen_tiles : # Look-ahead right
if (
tile + emb_tiles_x
) in embiggen_tiles : # Look-ahead down
2023-02-28 05:37:13 +00:00
intileimage . putalpha ( alphaLayerLTaC )
else :
intileimage . putalpha ( alphaLayerABR )
2023-03-03 06:02:00 +00:00
elif (
tile + emb_tiles_x
) in embiggen_tiles : # Look-ahead down only
2023-02-28 05:37:13 +00:00
intileimage . putalpha ( alphaLayerABB )
else :
intileimage . putalpha ( alphaLayerAA )
# Handle normal tiling case (much simpler - since we tile left to right, top to bottom)
else :
if emb_row_i == 0 and emb_column_i > = 1 :
intileimage . putalpha ( alphaLayerL )
elif emb_row_i > = 1 and emb_column_i == 0 :
2023-03-03 06:02:00 +00:00
if (
emb_column_i + 1 == emb_tiles_x
) : # If we don't have anything that can be placed to the right
2023-02-28 05:37:13 +00:00
intileimage . putalpha ( alphaLayerT )
else :
intileimage . putalpha ( alphaLayerTaC )
else :
2023-03-03 06:02:00 +00:00
if (
emb_column_i + 1 == emb_tiles_x
) : # If we don't have anything that can be placed to the right
2023-02-28 05:37:13 +00:00
intileimage . putalpha ( alphaLayerLTC )
else :
intileimage . putalpha ( alphaLayerLTaC )
# Layer tile onto final image
outputsuperimage . alpha_composite ( intileimage , ( left , top ) )
else :
2023-03-03 06:02:00 +00:00
print (
" Error: could not find all Embiggen output tiles in memory? Something must have gone wrong with img2img generation. "
)
2023-02-28 05:37:13 +00:00
# after internal loops and patching up return Embiggen image
return outputsuperimage
2023-03-03 06:02:00 +00:00
2023-02-28 05:37:13 +00:00
# end of function declaration
return make_image