iOS 13.3 pythonista3 ver. 3.2
When I was making an iOS home screen-like app with pythonista, I wanted to crop the icon image to rounded corners, so I researched various things.
It is assumed that you are executing with the following structure.
root/ ├ icons/ └ exe/ └ iconEditor.py
iconEditor.py
from PIL import Image, ImageDraw, ImageFilter
import photos
import pathlib
def crop_center(pil_img, crop_width, crop_height):
img_width, img_height = pil_img.size
return pil_img.crop((
(img_width - crop_width) // 2,
(img_height - crop_height) // 2,
(img_width + crop_width) // 2,
(img_height + crop_height) // 2
))
def crop_max_square(pil_img):
return crop_center(pil_img, min(pil_img.size), min(pil_img.size))
def make(pil_img, r=100, fil=True):
mask = DrawBack(pil_img, r)
if fil:
mask = mask.filter(ImageFilter.SMOOTH)
result = pil_img.copy()
result.putalpha(mask)
return result
def DrawBack(img, r=100):
#Draw a rounded square[3]Refer to. Rather, it's almost a copy.
mask = Image.new("L", img.size, 0)
draw = ImageDraw.Draw(mask)
rx = r
ry = r
fillcolor = "#ffffff"
draw.rectangle((0,ry)+(mask.size[0]-1,mask.size[1]-1-ry), fill=fillcolor)
draw.rectangle((rx,0)+(mask.size[0]-1-rx,mask.size[1]-1), fill=fillcolor)
draw.pieslice((0,0)+(rx*2,ry*2), 180, 270, fill=fillcolor)
draw.pieslice((0,mask.size[1]-1-ry*2)+(rx*2,mask.size[1]-1), 90, 180, fill=fillcolor)
draw.pieslice((mask.size[0]-1-rx*2,mask.size[1]-1-ry*2)+
(mask.size[0]-1,mask.size[1]-1), 0, 180, fill=fillcolor)
draw.pieslice((mask.size[0]-1-rx*2,0)+
(mask.size[0]-1,ry*2), 270, 360, fill=fillcolor)
return mask
def iconGenerate(iconpath, r=100):
im = Image.open(iconpath)
newname = ''.join(['../icons/', str(pathlib.Path(iconpath).stem), '.PNG'])
thumb_width = 300
im_square = crop_max_square(im).resize((thumb_width, thumb_width), Image.LANCZOS)
im_thumb = make(im_square, r, False)
im_thumb.save(newname)
return im_thumb
if __name__ == '__main__':
temp = pathlib.Path('../icons')
for p in temp.iterdir():
print('・' + p.name)
isfin = False
while not(isfin):
print('which file?(if new, input new)')
fname = input()
if fname == 'new':
asset = photos.pick_asset(title='Pick a image', multi=False)
try:
image = asset.get_image()
print('Input new name with .png or .PNG')
newname = input('newname : ')
image.save('../icons/'+newname)
fname = newname
except AttributeError:
#This error occurs because it is none if no selection is made
print('Nothing chosen.')
continue
try:
r = int(input('r : '))
im = iconGenerate('../icons/'+fname, r)
print('Success!')
im.show()
isfin = True
except Exception as e:
print(e)
print('Some Error Occored')
print('Exit?(y / n)')
ans = input()
isfin = False if ans == 'n' else True
## End while
print('Exit this file.')
crop_center(pil_img, crop_width, crop_height) crop_max_square(pil_img)
Copy and paste from Site in reference [1].
make(pil_img, r=100, fil=True)
pil_img: PIL image object r: Radius of the rounded circle part? ?? fil: Presence or absence of filter. You may not need it.
Based on the mask_circle_transparent function of Site in Reference [2], the mask is simplified and rounded.
DrawBack(img, r=100) img: PIL image object r: Radius of the rounded circle part?
This is a functionalized version of the program of Site in Reference [3]. For the convenience of creating a square image called an icon image, radii rx and ry use r with equal values.
iconGenerate(iconpath, r=100) iconpath: Path to the storage location of the image you want to use r: Radius of the rounded circle part?
The main part of this program.
im = Image.open(iconpath)
newname = ''.join(['../icons/', str(pathlib.Path(iconpath).stem), '.PNG'])
thumb_width = 300
First, create a PIL image object from the path and decide on a save name. Creating a Path object with pathlib.Path (iconpath), stem extracts only the filename (without the extension) from the path. I cast it with str and join it with join.
thumb_width determines the length of one side of the square. The variable names used on the sites [1] and [2] are used as they are.
im_square = crop_max_square(im).resize((thumb_width, thumb_width), Image.LANCZOS)
im_thumb = make(im_square, r, False)
im_thumb.save(newname)
return im_thumb
im_square crops the image to a square. See [1] and [2]. The corners are covered with im_thumb. Then I save it and return the image.
I think it's a slapstick, but I will explain the behavior when the entire program is copied and operated.
temp = pathlib.Path('../icons')
for p in temp.iterdir():
print('・' + p.name)
The path of the file in the save location is generated by the Path object, and the files in that folder are listed. isfin is a variable that terminates the while loop if True.
if fname == 'new':
asset = photos.pick_asset(title='Pick a image', multi=False)
try:
image = asset.get_image()
print('Input new name with .png or .PNG')
newname = input('newname : ')
image.save('../icons/'+newname)
fname = newname
except AttributeError:
#This error occurs because it is none if no selection is made
print('Nothing chosen.')
continue
Select the image to be applied next by referring to the list.
If you choose directly from the photo app, type new.
If you enter new, the photo will be displayed. It may not be displayed unless it is a recently saved photo. In general
asset = photos.pick_asset(title='Pick a image', multi=False)
try:
image = asset.get_image()
except AttributeError:
print('Nothing chosen.')
image.save(path)
By doing so, you can save the image in the path specified by the program.
r = int(input('r : '))
im = iconGenerate('../icons/'+fname, r)
print('Success!')
im.show()
isfin = True
print('Exit?(y / n)')
ans = input()
isfin = False if ans == 'n' else True
Converts the image with the entered file name and saves it. It will be displayed after conversion to the console with im.show (). (Verification) After that, ask if you want to convert again, and if you answer something other than n, you will enter the while loop again.
If you have any bugs that occurred using this program, please leave a comment. Isn't it better to do this in terms of readability? Please also actively comment such as! I'm not very good at it, so I'd love to hear your feedback.
[1] Crop a part of the image with Python, Pillow (crop / crop) [2] Create square and circular thumbnail images at once with Python and Pillow [3] About image processing: Draw rounded squares using Pillow
Recommended Posts