Я делаю набор инструментов с графическим интерфейсом для библиотеки Python Arcade, но у меня возникла проблема. Я хочу, чтобы пользователь мог настраивать размеры виджетов и графики графического интерфейса в пикселях (ширина, высота). Но в настоящее время графика — это изображения. У меня есть изображения, но я хочу, чтобы пользователь мог настроить их размер.
Одно из изображений показано ниже. Вместо того, чтобы использовать PIL, чтобы просто растянуть изображение по ширине и высоте, мне нужно что-то еще. Если просто растянуть ширину и высоту, граница будет выглядеть слишком толстой.
Есть ли простой способ вырезать определенные части изображения, чтобы их можно было легко использовать для расширения? Границы будут выглядеть так. Они будут разделены, чтобы расширить изображение. Некоторые части можно растянуть, а некоторые нет.
@MarkSetchell это не работает должным образом в случае тонкой границы, так как ее размер будет изменен, а не распознан как особенный для сохранения в таком виде.






Кажется, это не простой способ изменения размера (жидкое изменение размера здесь не работает), за исключением (как предлагается в вопросе со вторым изображением) разделения изображения с помощью PIL crop() на девять (9) подизображений и изменение их размера по отдельности (кроме угловые части изображения, размер которых не изменится). Части с измененным размером затем объединяются в новое изображение с запрошенным новым размером, вставляя их с помощью PIL paste() на него. Границы растягиваются только по длине, а не по толщине. Вот как это выглядит, если исходное изображение изменяется с помощью функции resizeExceptBorder(), расположенной ниже:
Исходное изображение (200 х 30)
new_img_1 = resizeExceptBorder(PIL_image,(300,90),(5,5,5,5))
Изображение с измененным размером (300 x 90)
new_img_2 = resizeExceptBorder(PIL_image,(400,150),(5,5,5,5))
Изменено (400 x 150)
А вот код функции, которую я собрал для этой цели:
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
В вашем примере используется простой стиль, поэтому для него также можно использовать упрощенное решение.
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
Этот ответ предполагает, что ваши границы полностью однородны, в том смысле, что нет никакой разницы между любым фрагментом границы (без узоров/текстур).
Если вы хотите учесть это, вы можете ознакомиться с подходом RenPy к проблеме. Я бы тоже отследил исходный код, но предложенное мной решение является минимальным решением для вашего конкретного примера с простым стилем графического интерфейса.
(Обратите внимание, что я не запускал этот код, поэтому где-то может быть смещение в 1 пиксель, которое я мог пропустить.)
Вероятно, вы ищете «резьбу по шву», также известную как «жидкое изменение размера». Можно сделать палочкой, описанной здесь docs.wand-py.org/ru/0.6.5/guide/resizecrop.html