07
업무 자동화 ② 사진 (1) — 한 장을 열고 줄인다
폴더를 훑고, 하나씩 열고, 바꿔서, 저장한다. 앞 강의와 틀이 똑같은데 대상이 사진으로 바뀐다. 먼저 한 장을 열어 크기를 재고, 줄여서, 용량이 얼마나 달라지는지 본다.
앞 두 강의에서 폴더를 훑어 엑셀을 만들었다. 이번에도 틀은 똑같다.
폴더를 훑는다 → 하나씩 연다 → 바꾼다 → 저장한다
바뀌는 건 다루는 대상이 글자에서 사진으로 바뀌는 것뿐이다.

이번 강의는 한 장을 제대로 다루고, 다음 강의에서 그걸 폴더째 돌린다.
pip install pillow
파일은 계속 ai-course 폴더에 넣는다. 이번 강의는 71번부터다.
설치는 pillow 인데 코드에서는 from PIL import ... 로 부른다. 원래 PIL 이라는 이름의 도구가 있었고 Pillow 가 그걸 이어받았기 때문이다.
설치 이름과 import 이름이 다른 경우가 종종 있다. pip install pillow 를 했는데 import pillow 가 안 된다고 당황하지 않으면 된다.
1. 실습 재료 — 사진도 코드로 만든다
남의 사진을 받아오지 않는다. 큰 사진을 코드로 그린다. 스마트폰 사진 크기(3000×2000)로 만든다.
import os
from PIL import Image, ImageDraw
os.makedirs("사진", exist_ok=True)
# (하늘색, 해 색) 세 벌
scenes = [
((70, 130, 180), (240, 220, 120)),
((90, 150, 90), (250, 250, 250)),
((160, 90, 110), (255, 200, 90)),
]
for i, (sky, sun) in enumerate(scenes, start=1):
# "RGB" 는 색 방식, (3000, 2000) 은 가로x세로, 마지막이 배경색
img = Image.new("RGB", (3000, 2000), sky)
# ImageDraw 는 그림 위에 도형을 그리는 붓이다
d = ImageDraw.Draw(img)
d.ellipse((2300, 200, 2700, 600), fill=sun) # 해
d.polygon([(0, 2000), (900, 900), (1800, 2000)], fill=(60, 90, 60)) # 산
d.rectangle((0, 1750, 3000, 2000), fill=(80, 70, 55)) # 땅
# quality 는 JPEG 압축 정도다. 높을수록 선명하고 용량이 크다 (1~95)
# f"{i:03d}" 는 3 을 003 으로 만든다. 안 그러면 정렬이 1, 10, 2 순서가 된다
img.save(f"사진/행사_{i:03d}.jpg", quality=92)
print(sorted(os.listdir("사진")))

ai-course/사진 폴더를 열어 확인해본다. 한 장이 3000×2000 이라 화면에 꽉 찬다.
2. 한 장을 열어본다
import glob
from PIL import Image
paths = sorted(glob.glob("사진/*.jpg"))
img = Image.open(paths[0]) # 파일을 여는 것뿐. 아직 아무것도 안 바꿨다
print(img.size) # (가로, 세로)
print(img.width)
print(img.height)
print(img.format)
print(img.mode)


괄호가 없다. img.size 는 함수가 아니라 값이다. 4강에서 본 a.shape 와 같다.
3. 한 장을 줄여본다
import os
import glob
from PIL import Image
paths = sorted(glob.glob("사진/*.jpg"))
img = Image.open(paths[0])
# thumbnail 은 "이 상자 안에 들어가게" 줄인다. 비율은 알아서 지킨다.
# 800x800 상자에 3000x2000 을 넣으면 800x533 이 된다.
img.thumbnail((800, 800))
img.save("한장_작게.jpg", quality=85)
print(img.size)
print(round(os.path.getsize(paths[0]) / 1024, 1)) # 원본 KB
print(round(os.path.getsize("한장_작게.jpg") / 1024, 1)) # 결과 KB

120KB 가 12KB 가 됐다. 가로는 3.75배 줄었는데 용량은 10배 줄었다. 사진은 넓이로 계산되기 때문이다 — 3000×2000 = 600만 점이 800×533 = 42만 점이 되어 점의 개수가 14배 차이다. 거기에 quality=85 로 압축을 조금 더 준 결과가 10배다.
4. 바꾸는 방법은 갈아끼우면 된다
thumbnail 자리에 다른 것을 넣으면 다른 일을 한다. 틀은 그대로다.

표를 자세히 보면 첫 줄만 img = 가 없다. 이게 이 라이브러리에서 가장 자주 걸리는 함정이다.

