Reputation: 141
I'm making a GUI toolkit for the Python Arcade library, but I am stuck on a problem. I want the user to be able to customize sizes for the GUI widgets and graphics in pixels (width, height). But currently, the graphics are images. I have the images, but I want the user to be able to customize their sizing.
One of the images is shown below. Instead of using PIL to just stretch the width and height of the image, I need something else. Just stretching the width and height will make the border look too thick.
Is there an easy way to cut certain parts of the image to enable easy use for extending it? Borders would look like this. They would be split to extend the image. Some of the parts can be stretched, but some can not.
Upvotes: 0
Views: 470
Reputation: 170
Your example seems to use a simple style, so a simplified solution could be used for it as well.
from PIL import Image
def resizeImage(im, corner, new_size):
'''
corner_size and new_size are 2-element tuples of xy sizes for the corner size and target size.
'''
# Get corners from image
tl = im.crop(0, 0, corner[0], corner[1])
tr = im.crop(im.size[0] - corner[0], 0, size[0], corner[1])
bl = im.crop(0, im.size[1] - corner[1], corner[0], size[1])
br = im.crop(im.size[0] - corner[0], im.size[1] - corner[1], size[0], size[1])
# Get 1-pixel slices of midsections, then scale them up as needed
h_slice = im.crop(corner[0] + 1, 0, corner[0] + 2, im.size[1])
h_slice = h_slice.resize((new_size[0] - 2 * corner[0], im.size[1]))
v_slice = im.crop(0, corner[1] + 1, im.size[0], corner[1] + 2)
v_slice = v_slice.resize((im.size[0], new_size[1] - 2 * corner[1]))
# create new image
new_im = Image.new('RGBA', new_size)
# paste on segments and corners
new_im.paste(tl, (0, 0))
new_im.paste(tr, (new_size[0] - corner[0], 0))
new_im.paste(tl, (0, new_size[1] - corner[1]))
new_im.paste(tl, (new_size[0] - corner[0], new_size[1] - corner[1]))
return im
This answer assumes that your borders are completely homogenous, in that there's no difference between any slice of the border (no patterns/textures).
If you do want to account for this, you can check out RenPy's approach to the problem. I'd track down the source code too, but the solution I proposed is a minimal solution for your specific example with a simple GUI style.
(Note that I have not run this code, so there may be a 1-pixel offset somewhere that I could have missed.)
Upvotes: 2
Reputation:
It seems to be no easy way for resizing ( liquid resizing doesn't work here ) except (as suggested in the question with the second image) dividing the image using PIL crop()
into nine (9) sub-images and resize them separately (except the corner sub-images, which won't become resized). The resized parts are then put together in a new image with the requested new size by pasting them using PIL paste()
onto it. The borders are stretched only along their length and not along their thickness. Here how it looks like if the original image becomes resized with the further down provided resizeExceptBorder()
function:
new_img_1 = resizeExceptBorder(PIL_image,(300,90),(5,5,5,5))
new_img_2 = resizeExceptBorder(PIL_image,(400,150),(5,5,5,5))
And here the code of the function I have put together for this purpose:
def resizeExceptBorder(PIL_image, newSize, borderWidths):
"""
newSize = (new_width, new_height)
borderWidths = (leftWidth, rightWidth, topWidth, bottomWidth)"""
pl_img = PIL_image
sXr, sYr = newSize # ( 800, 120 ) # resized size X, Y
lWx, rWx , tWy, bWy = borderWidths
sX, sY = pl_img.size
sXi, sYi = sXr-(lWx+rWx), sYr-(tWy+bWy)
pl_lft_top = pl_img.crop(( 0, 0, lWx, tWy))
pl_rgt_top = pl_img.crop((sX-rWx, 0, sX, tWy))
pl_lft_btm = pl_img.crop(( 0, sY-bWy, lWx, sY))
pl_rgt_btm = pl_img.crop((sX-rWx, sY-bWy, sX, sY))
# ---
pl_lft_lft = pl_img.crop(( 0, tWy, lWx,sY-bWy)).resize((lWx ,sYi))
pl_rgt_rgt = pl_img.crop((sX-rWx, tWy, sX,sY-bWy)).resize((rWx ,sYi))
pl_top_top = pl_img.crop(( lWx, 0, sX-rWx, tWy)).resize((sXi ,tWy))
pl_btm_btm = pl_img.crop(( lWx, sY-bWy, sX-rWx, sY)).resize((sXi ,bWy))
# ---
pl_mid_mid = pl_img.crop(( lWx, tWy, sX-rWx,sY-bWy)).resize((sXi,sYi))
# -------
pl_new=Image.new(pl_img.mode, (sXr, sYr))
# ---
pl_new.paste(pl_mid_mid, ( lWx, tWy))
# ---
pl_new.paste(pl_top_top, ( lWx, 0))
pl_new.paste(pl_btm_btm, ( lWx,sYr-bWy))
pl_new.paste(pl_lft_lft, ( 0, tWy))
pl_new.paste(pl_rgt_rgt, (sXr-rWx, tWy))
# ---
pl_new.paste(pl_lft_top, ( 0, 0))
pl_new.paste(pl_rgt_top, (sXr-rWx, 0))
pl_new.paste(pl_lft_btm, ( 0,sYr-bWy))
pl_new.paste(pl_rgt_btm, (sXr-rWx,sYr-bWy))
# ---
return pl_new
#:def
Upvotes: 1