pythonimage-editing

How to resize an image keeping the thickness of its border?


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.

Entry widget

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.


Solution

  • 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:

    original image Original image (200 x 30)

    new_img_1 = resizeExceptBorder(PIL_image,(300,90),(5,5,5,5))
    

    resized image 1 Resized image (300 x 90)

    new_img_2 = resizeExceptBorder(PIL_image,(400,150),(5,5,5,5))
    

    resized image 2 Resized (400 x 150)

    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