Как изменить размер изображения, сохраняя толщину его границы?

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

Одно из изображений показано ниже. Вместо того, чтобы использовать PIL, чтобы просто растянуть изображение по ширине и высоте, мне нужно что-то еще. Если просто растянуть ширину и высоту, граница будет выглядеть слишком толстой.

Есть ли простой способ вырезать определенные части изображения, чтобы их можно было легко использовать для расширения? Границы будут выглядеть так. Они будут разделены, чтобы расширить изображение. Некоторые части можно растянуть, а некоторые нет.

Вероятно, вы ищете «резьбу по шву», также известную как «жидкое изменение размера». Можно сделать палочкой, описанной здесь docs.wand-py.org/ru/0.6.5/guide/resizecrop.html

Mark Setchell 01.10.2022 21:14

@MarkSetchell это не работает должным образом в случае тонкой границы, так как ее размер будет изменен, а не распознан как особенный для сохранения в таком виде.

Claudio 02.10.2022 00:23
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
0
2
109
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Кажется, это не простой способ изменения размера (жидкое изменение размера здесь не работает), за исключением (как предлагается в вопросе со вторым изображением) разделения изображения с помощью 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 пиксель, которое я мог пропустить.)

Другие вопросы по теме