Python 을 이용 하여 메모지 그림 을 어떻게 만 드 는 지 상세 하 게 설명 합 니 다.
최근 에 문자 로 그림 을 돌 리 는 수요 가 있 지만 앱 을 다운로드 하고 싶 지 않 아 Python Pillow 를 사용 하여 하 나 를 실 현 했 습 니 다.효 과 는 다음 과 같 습 니 다.
PIL 은
PIL.ImageDraw.ImageDraw.text
방법 을 제공 하여 문 자 를 그림 에 편리 하 게 쓸 수 있 습 니 다.간단 한 예 는 다음 과 같 습 니 다.
from PIL import Image, ImageDraw, ImageFont
# get an image
base = Image.open('Pillow/Tests/images/hopper.png').convert('RGBA')
# make a blank image for the text, initialized to transparent text color
txt = Image.new('RGBA', base.size, (255,255,255,0))
# get a font
fnt = ImageFont.truetype('Pillow/Tests/fonts/FreeMono.ttf', 40)
# get a drawing context
d = ImageDraw.Draw(txt)
# draw text, half opacity
d.text((10,10), "Hello", font=fnt, fill=(255,255,255,128))
# draw text, full opacity
d.text((10,60), "World", font=fnt, fill=(255,255,255,255))
out = Image.alpha_composite(base, txt)
out.show()
왜 문자 의 너 비 를 계산 해 야 합 니까?텍스트 를 배경 그림 에 직접 쓰 면 안 됩 니까?Pillow PIL.ImageDraw.ImageDraw.text
문 자 를 쓰 는 것 은 줄 바 꿈 문자 에 따라 줄 을 바 꾸 는 것 입 니 다.문자열 이 너무 길 면 텍스트 부분 이 배경 그림 의 너 비 를 초과 하기 때문에 첫 번 째 단 계 는 텍스트 를 고정된 너비 에 따라 높이 를 계산 해 야 합 니 다.그림 에 적 힌 것 처럼 문자 회전 그림 은 세 단계 로 나 뉜 다.
이 배경 그림 의 너 비 는 고정 되 어 있 기 때문에 문자 의 너 비 는 계산 하지 않 아 도 됩 니 다.
PIL.ImageDraw.ImageDraw.text
줄 을 바 꾸 는 것 을 통 해 우 리 는 문자 의 적당 한 위치 에 덧 붙 이면 된다.첫 번 째 로 생각 나 는 것 은 textwrap 방법 입 니 다.textwrap 은 줄 바 꿈 문자 의 위 치 를 조정 하여 텍스트 를 포맷 할 수 있 습 니 다.그러나 textwrap 의 또 다른 문 제 는 문자 길이 에 따라 구분 되 는 것 입 니 다.그러나 텍스트 의 문 자 는 똑 같은 너비 가 아 닙 니 다.textwrap 을 통 해 포맷 된 문 자 를 그림 에 쓰 면 효과 가 이 럴 수 있 습 니 다.
이 방식 을 사용 하면 글꼴 크기 를 조정 하려 면 줄 마다 길 이 를 다시 조정 해 야 합 니 다.
각 줄 의 너비 가 가능 한 한 일치 하도록 하기 위해 서 는
PIL.ImageDraw.ImageDraw.textsize
문자 의 너비 와 높이 를 가 져 온 다음 에 약 정 된 너비 에 따라 긴 텍스트 를 텍스트 목록 으로 나 눈 다음 에 목록 의 각 줄 의 문 자 를 그림 에 씁 니 다.
def get_paragraph(text, note_width):
#
txt = Image.new('RGBA', (100, 100), (255, 255, 255, 0))
# get a drawing context
draw = ImageDraw.Draw(txt)
paragraph, sum_width = '', 0
line_numbers, line_height = 1, 0
for char in text:
w, h = draw.textsize(char, font)
sum_width += w
if sum_width > note_width:
line_numbers += 1
sum_width = 0
paragraph += '
'
paragraph += char
line_height = max(h, line_height)
if not paragraph.endswith('
'):
paragraph += '
'
return paragraph, line_height, line_numbers
def split_text(text):
#
max_line_height, total_lines = 0, 0
paragraphs = []
for t in text.split('
'):
#
paragraph, line_height, line_numbers = get_paragraph(t)
max_line_height = max(line_height, max_line_height)
total_lines += line_numbers
paragraphs.append((paragraph, line_numbers))
line_height = max_line_height
total_height = total_lines * line_height
# ,
return paragraphs, total_height, line_height
그림 에 쓸 텍스트 를 문자 너비 로 구분 하 는 효과 입 니 다.텍스트 길이 가 고정 되 지 않 기 때문에 생 성 된 텍스트 높이 도 고정 되 지 않 습 니 다.배경 그림 도 동적 으로 생 성 되 어야 합 니 다.
텍스트 높이 에 따라 배경 그림 생 성
그림 을 통 해 우 리 는 머리 와 꼬리 부분 이 고정 되 어 있 고 문자 부분 이 변화 하 는 것 을 볼 수 있다.그러면 배경 그림 의 높이 계산 공식 은?
배경 그림 높이=머리 높이+꼬리 높이+텍스트 높이
구현 코드 는 다음 과 같 습 니 다:
NOTE_HEADER_IMG = path.normpath(path.join(
path.dirname(__file__), 'note_header_660.png'))
NOTE_BODY_IMG = path.normpath(path.join(
path.dirname(__file__), 'note_body_660.png'))
NOTE_FOOTER_IMG = path.normpath(path.join(
path.dirname(__file__), 'note_footer_660.png'))
NOTE_WIDTH = 660
NOTE_TEXT_WIDTH = 460
body_height = NOTE_BODY_HEIGHT = 206
header_height = NOTE_HEADER_HEIGHT = 89
footer_height = NOTE_FOOTER_HEIGHT = 145
font = ImageFont.truetype(NOTE_OTF, 24)
def get_images(note_height):
numbers = note_height // body_height + 1
images = [(NOTE_HEADER_IMG, header_height)]
images.extend([(NOTE_BODY_IMG, body_height)] * numbers)
images.append((NOTE_FOOTER_IMG, footer_height))
return images
def make_backgroud():
#
images = get_images()
total_height = sum([height for _, height in images])
#
backgroud = Image.new('RGB', (body_width, total_height))
left, right = 0, 0
background_img = '/tmp/%s_backgroud.png' % total_height
#
if path.exists(background_img):
return background_img
for image_file, height in images:
image = Image.open(image_file)
# (0, left, self.body_width, right+height)
# 0, left
# self.body_width, right+height
backgroud.paste(image, (0, left, body_width, right+height))
left += height # ,
right += height #
backgroud.save(background_img, quality=85)
return background_img
그림 에 텍스트 쓰기현재 우 리 는 배경 그림 과 분 리 된 텍스트 를 얻 으 면 바로 텍스트 를 그림 에 쓸 수 있다.
def draw_text(paragraphs, height):
background_img = make_backgroud()
note_img = Image.open(background_img).convert("RGBA")
draw = ImageDraw.Draw(note_img)
# ,
x, y = 80, 100
for paragraph, line_numbers in paragraphs:
for line in paragraph.split('
')[:-1]:
draw.text((x, y), line, fill=(110, 99, 87), font=font)
y += line_height
# draw.text((x, y), paragraph, fill=(110, 99, 87), font=font)
# y += self.line_height * line_numbers
note_img.save(filename, "png", quality=1, optimize=True)
return filename
전체 코드 보기[https://github.com/gusibi/momo/blob/master/momo/note.py]실행 후 효 과 는 그림:
닥 친 문제
편리 하 게 사용 할 수 있 도록 나 는 이것 을 공공 번호 의 기능 으로 만 들 었 다.그리고 심각 한 문제 에 부 딪 혔 다.너무 느리다!
line 사용proffler 분석 을 통 해 대부분의 시간 이 그림 저장 에 소모 되 었 음 을 알 수 있 습 니 다.
note_img.save(filename, "png", quality=1, optimize=True)
성능 분석 도구 도 시간 을 차지 합 니 다.테스트 가 완료 되면 분석 을 닫 아야 합 니 다.이 문 제 를 해결 하 는 가능 한 방법:
같은 코드,같은 텍스트,python 3 을 사용 하 는 데 2.3s 만 사 용 했 고 Python 2 를 사용 할 때 5.3 s 로 다른 기능 에서 Python 2 와 Python 3 의 차이 가 이렇게 큰 것 을 본 적 이 없다.
구체 적 인 차 이 는 소스 코드 로 테스트 할 수 있다.
그래도 문제 가 있어 요.
그림 생 성 속 도 를 최적화 한 후에 긴 텍스트 상태 에서 공 호 는 타 임 스 를 초과 할 수 있다 는 것 을 발견 했다.검 사 를 통 해 사진 이 공공 플랫폼 에 올 라 가 는 것 이 너무 느 린 것 으로 밝 혀 졌 다.(서버 는 1M 대역 폭 밖 에 없어 어 쩔 수 없다.)
해결 방법 은 텐 센트 클 라 우 드 에 사진 을 올 리 고(파일 업 로드 는 내부 네트워크 대역 폭 을 사용 하여 제한 을 받 지 않 음)그림 url 로 돌아 갑 니 다.
총결산
이상 은 이 글 의 전체 내용 입 니 다.본 논문 의 내용 이 여러분 의 학습 이나 업무 에 어느 정도 참고 학습 가치 가 있 기 를 바 랍 니 다.궁금 한 점 이 있 으 시 면 댓 글 을 남 겨 주 셔 서 저희 에 대한 지지 에 감 사 드 립 니 다.
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
로마 숫자를 정수로 또는 그 반대로 변환그 중 하나는 로마 숫자를 정수로 변환하는 함수를 만드는 것이었고 두 번째는 그 반대를 수행하는 함수를 만드는 것이었습니다. 문자만 포함합니다'I', 'V', 'X', 'L', 'C', 'D', 'M' ; 문자열이 ...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.