В Python, Python Image Library 1.1.6, как я могу расширить холст без изменения размера?
Я, вероятно, ищу в руководстве не то, что нужно, но я хочу взять объект изображения и расширить его без изменения размера (растяжения / сжатия) исходного изображения.
Пример с игрушкой: представьте себе синий прямоугольник 200 x 100, затем я выполняю некоторую операцию, и у меня есть новый объект изображения 400 x 300, состоящий из белого фона, на котором лежит синий прямоугольник 200 x 100. Бонус, если я могу контролировать, в каком направлении это расширяется, или новый цвет фона и т. Д.
По сути, у меня есть изображение, к которому я буду добавлять итеративно, и я не знаю, какого размера он будет в самом начале.
Я полагаю, что я мог бы взять оригинальный объект, сделать новый, немного больший объект, вставить туда оригинал, нарисовать немного больше, а затем повторить. Кажется, что это может быть вычислительно дорого. Однако я подумал, что для этого найдется функция, так как я предполагаю, что это обычная операция. Возможно, я ошибся.
3 ответа
Функция ImageOps.expand расширяет изображение, но добавляет одинаковое количество пикселей в каждом направлении.
Лучший способ - просто сделать новое изображение и вставить:
newImage = Image.new(mode, (newWidth,newHeight))
newImage.paste(srcImage, (x1,y1,x1+oldWidth,y1+oldHeight))
Если производительность является проблемой, сделайте ваше оригинальное изображение больше, чем нужно, и обрежьте его после завершения рисования.
На основании промежуточного ответа:
#!/usr/bin/env python
from PIL import Image
import math
def resize_canvas(old_image_path="314.jpg", new_image_path="save.jpg",
canvas_width=500, canvas_height=500):
"""
Resize the canvas of old_image_path.
Store the new image in new_image_path. Center the image on the new canvas.
Parameters
----------
old_image_path : str
new_image_path : str
canvas_width : int
canvas_height : int
"""
im = Image.open(old_image_path)
old_width, old_height = im.size
# Center the image
x1 = int(math.floor((canvas_width - old_width) / 2))
y1 = int(math.floor((canvas_height - old_height) / 2))
mode = im.mode
if len(mode) == 1: # L, 1
new_background = (255)
if len(mode) == 3: # RGB
new_background = (255, 255, 255)
if len(mode) == 4: # RGBA, CMYK
new_background = (255, 255, 255, 255)
newImage = Image.new(mode, (canvas_width, canvas_height), new_background)
newImage.paste(im, (x1, y1, x1 + old_width, y1 + old_height))
newImage.save(new_image_path)
resize_canvas()
Вы можете рассмотреть несколько иной подход к своему изображению... построить его из плиток фиксированного размера. Таким образом, по мере необходимости вы просто добавляете новые плитки изображений. После завершения всех ваших вычислений вы можете определить окончательный размер изображения, создать чистое изображение этого размера и вставить в него плитки. Это должно уменьшить количество копий, которые вы просматриваете для выполнения задачи.
(Вы, вероятно, захотите инкапсулировать такое мозаичное изображение в объект, который, конечно, скрывает аспекты листов от других слоев кода.)
Этот код увеличит изображение меньшего размера с сохранением соотношения сторон, а затем центрирует его на холсте стандартного размера. Также сохраняет прозрачность или по умолчанию используется серый фон.
Протестировано с файлами PNG в режиме P.
Закодированная отладка
final.show()
и
break
для тестирования. Удалить строки и хэштег на
final.save(...)
зациклить и сохранить.
Можно было параметризовать соотношение холста и повысить гибкость, но это послужило моей цели.
"""
Resize ... and reconfigures. images in a specified directory
Use case: Images of varying size, need to be enlarged to exaxtly 1200 x 1200
"""
import os
import glob
from PIL import Image
# Source directory plus Glob file reference (Windows)
source_path = os.path.join('C:', os.sep, 'path', 'to', 'source', '*.png')
# List of UNC Image File paths
images = glob.glob(source_path)
# Destination directory of modified image (Windows)
destination_path = os.path.join('C:', os.sep, 'path', 'to', 'destination')
for image in images:
original = Image.open(image)
# Retain original attributes (ancillary chunks)
info = original.info
# Retain original mode
mode = original.mode
# Retain original palette
if original.palette is not None:
palette = original.palette.getdata()[1]
else:
palette = False
# Match original aspect ratio
dimensions = original.getbbox()
# Identify destination image background color
if 'transparency' in info.keys():
background = original.info['transparency']
else:
# Image does not have transparency set
print(image)
background = (64)
# Get base filename and extension for destination
filename, extension = os.path.basename(image).split('.')
# Calculate matched aspect ratio
if dimensions[2] > dimensions[3]:
width = int(1200)
modifier = width / dimensions[2]
length = int(dimensions[3] * modifier)
elif dimensions[3] > dimensions[2]:
length = int(1200)
modifier = length / dimensions[3]
width = int(dimensions[2] * modifier)
else:
width, length = (1200, 1200)
size = (width, length)
# Set desired final image size
canvas = (1200, 1200)
# Calculate center position
position = (
int((1200 - width)/2),
int((1200 - length)/2),
int((1200 - width)/2) + width,
int((1200 - length)/2) + length
)
# Enlarge original image proportionally
resized = original.resize(size, Image.LANCZOS)
# Then create sized canvas
final = Image.new(mode, canvas, background)
# Replicate original properties
final.info = info
# Replicate original palatte
if palette:
final.putpalette(palette)
# Cemter paste resized image to final canvas
final.paste(resized, position)
# Save final image to destination directory
final.show()
#final.save("{}\\{}.{}".format(destination_path, filename, extension))
break