Python 캡 처 선택 GIF 애니메이션 생 성

전에 단체 에서 어떤 친구 가 오늘 점심 에 무엇 을 먹 어야 하 느 냐 고 물 었 고 다른 친구 가 아래 의 동 도 를 보 냈 다.
截图吃饭
저 는 개인 적 으로 재 밌 어 요.캡 처 는 정말 추첨 처럼 무 작위 로 메뉴 를 고 르 는 것 같 아 요.이 움 직 이 는 그림 의 요리 이름 후 보 를 감안 하면 우리 가 먹 을 수 있 는 요리 만 은 아니다.우 리 는 python 으로 요리 이름 목록 에 따라 이런 동 도 를 만들어 서 놀 수 있다.
이전에 캡 처 해서 프로필 사진 을 고 르 는 것 과 같은 동 도 를 보 았 는데 그림 을 통 해 생 성 된 동 도 는 모두 비교적 간단 하 다.글 에서 언급 한 Imagine 의 애니메이션 작업장 도 구 를 통 해 할 수 있다.그래서 본 고 는 문자 동 도 를 만 드 는 방법 만 보 여 준다.
python 텍스트 다이어그램 생 성
다음 에 우 리 는 한 걸음 한 걸음 이 조작 을 완성 한다.
이모 티 콘 다운로드
이런 이모 티 콘 을 분석 하기 위해 서 는 첫 번 째 단 계 를 먼저 다운로드 해 야 하지만 위 챗 이모 티 콘 에 대해 서 는 테스트 를 통 해 직접 다운로드 할 수 없다.
파일 모니터링 도 구 를 통 해 gif 표정 동 도 는C:\Users\ASUS\Documents\WeChat Files\ ID\FileStorage\CustomEmotion\xx\xxxx위치 에 있 지만 사진 도구 로 볼 수 없습니다.winhex 분석 바 이 너 리 로V1MMWX와 같은 파일 헤드 를 얻 었 다 는 것 은 위 챗 이 표정 을 어느 정도 암호 화 했다 는 것 을 의미한다.비록 비밀 을 해제 할 수 있 지만,이렇게 크게 싸 우 는 것 은 너무 번 거 로 운 일이 다.
뒤에 드디어 간단 한 방안 이 떠 올 랐 습 니 다.그것 은 바로 배경 에 로그 인 할 수 있 는 권한 이 있 는 공중 번호 에 이 표정 을 보 내 고 공중 번호 배경 에 가서 다운로드 하 는 것 입 니 다.
image-20210726163537948
위 챗 이 보 낸 동 도 는 모두 자신 만 의 특유V1MMWX암호 화 형식 으로 저 장 된 것 으로 자신 만 의 독창적 인 압축 알고리즘 을 사용 하기 위해 더 큰 압축 비 를 가 진 것 으로 보인다.그것 은 우리 가 로 컬 위 챗 에 저 장 된 gif 동 도 를 직접 보고 싶 어서 이런 위 챗 형식 을 위 한 디코더 를 자체 개발 할 수 밖 에 없다 는 것 을 의미한다.
분석 동도
다음 에 저 는 작은 도구 인 Imagine 을 사용 하고 애니메이션 작업장 으로 엽 니 다.
image-20210726163518497
이 동 도 는 22 장의 문자 그림 으로 구성 되 어 있 으 며 프레임 전환 시간 은 20 밀리초 이다.
한 장의 그림 생 성
분석 이 완료 되면 PIL 라 이브 러 리 로 한 장의 그림 을 만 드 는 것 을 고려 합 니 다.이 라 이브 러 리 의 어린이 신발 이 설치 되 어 있 지 않 으 면 다음 명령 으로 라 이브 러 리 를 설치 합 니 다.

pip install pillow
다음은 블 루 베이스 로 배경 을 선택 하 였 습 니 다.우 리 는 먼저 중간 에 있 는 요리 이름 문 자 를 그립 니 다.

from PIL import Image, ImageFont, ImageDraw


text = "       "
size = 320
fontsize = (size-20)//len(text)
im = Image.new(mode='RGB', size=(size, size), color="lightblue")

draw = ImageDraw.Draw(im=im)
draw.text(xy=(10, (size-fontsize*1.5)/2),
          text=text, fill=0,
          font=ImageFont.truetype('msyh.ttc', size=fontsize))
im
image-20210726172326328
메뉴 의 이름 과 글자 의 개수 가 일치 하지 않 아 전체 그림 을 채 울 수 있 도록 자동 문자 크기 조정 처 리 를 했다.
글꼴 은 마이크로소프트 블랙 을 선 택 했 습 니 다.물론 마이크로소프트 블랙 에 도 세 개의 피 드 글꼴 이 있 습 니 다.시스템 글꼴 설치 디 렉 터 리 를 통 해 글꼴 파일 의 속성 을 보고 글꼴 에 대응 하 는 파일 이름 을 알 수 있 습 니 다.
image-20210726164518133
아래 에 그림자 가 있 는 문자 가 생 성 되 는 것 은 번 거 로 울 수 있 습 니 다.제 생각 은 먼저 검은색 의 문 자 를 그 리 는 것 입 니 다.검은색 가장자리 에 흰색 으로 채 워 진 문 자 를 그 리 는 데 몇 개의 단 위 를 위로 옮 기 는 것 입 니 다.

def text_border(text, x, y, font, shadowcolor, fillcolor):
    draw.text((x - 1, y), text, font=font, fill=shadowcolor)
    draw.text((x + 1, y), text, font=font, fill=shadowcolor)
    draw.text((x, y - 1), text, font=font, fill=shadowcolor)
    draw.text((x, y + 1), text, font=font, fill=shadowcolor)

    draw.text((x - 1, y - 1), text, font=font, fill=shadowcolor)
    draw.text((x + 1, y - 1), text, font=font, fill=shadowcolor)
    draw.text((x - 1, y + 1), text, font=font, fill=shadowcolor)
    draw.text((x + 1, y + 1), text, font=font, fill=shadowcolor)

    draw.text((x, y), text, font=font, fill=fillcolor)


bottomtext = "      ?    "
bottom_fontsize = 27
bottom_font = ImageFont.truetype('STHUPO.TTF', size=bottom_fontsize)
x, y = (size-bottom_fontsize*len(bottomtext))/2, size-bottom_fontsize*1.2
draw.text(xy=(x, y), text=bottomtext,
          fill=0, font=bottom_font)
text_border(bottomtext, x, y-4,
            bottom_font, 0, (255, 255, 255))
im
image-20210726172847077
상기 코드 는 중국어 호박 을 글씨체 로 선 택 했 습 니 다.개인 적 으로 텍스트 테 두 리 를 그 리 는 방법 은 간단 하고 거 칠 며 더 좋 은 방법 이 있다 면 댓 글 교 류 를 환영 합 니 다.
후속 사진 이 위 챗 에 보 내 는 것 이 모두 작 다 는 것 을 감안 하여 아예 지금 픽 셀 크기 를 압축 하 세 요.

im.thumbnail((128, 128))
im
image-20210726172948959
다음 에 우 리 는 생 성 코드 를 밀봉 하여 후속 호출 에 편리 하도록 한다.

from PIL import Image, ImageFont, ImageDraw


def text_img(text, bgcolor="lightblue", bottomtext="      ?    ", size=360, result_size=(128, 128)):
    def text_border(text, x, y, font, shadowcolor, fillcolor):
        draw.text((x - 1, y), text, font=font, fill=shadowcolor)
        draw.text((x + 1, y), text, font=font, fill=shadowcolor)
        draw.text((x, y - 1), text, font=font, fill=shadowcolor)
        draw.text((x, y + 1), text, font=font, fill=shadowcolor)

        draw.text((x - 1, y - 1), text, font=font, fill=shadowcolor)
        draw.text((x + 1, y - 1), text, font=font, fill=shadowcolor)
        draw.text((x - 1, y + 1), text, font=font, fill=shadowcolor)
        draw.text((x + 1, y + 1), text, font=font, fill=shadowcolor)

        draw.text((x, y), text, font=font, fill=fillcolor)

    im = Image.new(mode='RGB', size=(size, size), color=bgcolor)
    draw = ImageDraw.Draw(im=im)
    fontsize = (size-20)//len(text)
    draw.text(xy=(10, (size-fontsize*1.5)/2),
              text=text, fill=0,
              font=ImageFont.truetype('msyh.ttc', size=fontsize))
    bottom_fontsize = (size-20)//len(bottomtext)
    bottom_font = ImageFont.truetype('STHUPO.TTF', size=bottom_fontsize)
    x, y = (size-bottom_fontsize*len(bottomtext))/2, size-bottom_fontsize*1.2
    draw.text(xy=(x, y), text=bottomtext,
              fill=0, font=bottom_font)
    text_border(bottomtext, x, y-4,
                bottom_font, 0, (255, 255, 255))
    im.thumbnail(result_size)
    return im
테스트 해 보기:

text_img("    ")
image-20210726174000710
ok,이제 우 리 는 모든 요리 에 그림 을 만 들 수 있 습 니 다.근 데 메뉴 이름 이 어디서 났 지?나 는 웹 사 이 트 를 찾 았 다.다음은 그것 을 기어 오 르 는 것 을 고려 해 보 자.
요리 데이터 추출
사이트 주 소 는:https://m.meishij.net/caipu/
이 사이트 의 결 과 는 매우 간단 합 니 다.간단 한 xpath 로 모든 요리 의 이름 을 얻 을 수 있 습 니 다.
image-20210726174726258
다음 다운로드 시작:

from lxml import etree
import requests

req = requests.get("https://m.meishij.net/caipu/")

html = etree.HTML(req.text)
menu = html.xpath("//dl[@class='recipe_list']//a/text()")
menu = list(set([_.strip(".") for _ in menu]))
print(len(menu), menu[:10], menu[-10:])
3744['연근 육 수','토란 원','해물 탕','새 송이 무침','삼 즙 찜 솥','우 윳 옥수수 즙','콩 뿔 볶 음','가지 소스','망고 찹쌀 육 수','만두']['가지 찜','브 로 콜 리 닭 볶 음','구식 케이크','갈비 떡','수세미외 볶 음','토란 갈비찜 갈비','목이버섯 볶 음','굴 소스 오트밀','닭 강 정','연잎 전']
이 요리 들 의 이름 이 있 으 면 우 리 는 이미 동 도 를 만 드 는 데 쓸 수 있다.하지만 앞으로 도 요 리 를 배 울 수 있 도록 요리 이름 을 저장 할 수 있 습 니 다.요 리 를 배 우려 면 홈 페이지 를 열 어 보 세 요.https://so.meishi.cc/?q=요리 이름 을 검색 하 세 요.
메뉴 이름 저장:

with open("meau.csv", "w", encoding="u8") as f:
    f.write("  
") for row in menu: f.write(row) f.write("
")
다음은 메뉴 이름 동 도 를 만 들 기 시작 합 니 다.
메뉴 이름 만 들 기
3767 여 개의 요리 이름 이 너무 많 기 때문에 우 리 는 30 개의 요리 이름 을 마음대로 지어 다음 생 에 동 도 를 만 들 수 있다.

import random

gif_list = random.choices(menu, k=30)
print(gif_list)
['찐 계란','계피 말 이','냉 과 계란 볶 음','치즈 h 고구마','바나나 쿠키','요 거 트 무스','계란 장 가루','붉 은 기름 배 실','옥수수 계란 전','매운두부 수프','무 갈비찜','여주 갈비탕','썩 은 대나무 미나리 무침','토마토 볶 음','마늘 가지 찜','팥소 빵','버섯 볶 음 연근','후추 소고 기 볶 음 연근','호박 전','오이 볶 음','오이 볶 음''잡곡 만두','도산 피 월병','파 고기 튀김','소고 기 볶 음','두 쪽 붕어','새우 두부 찜','소 만두','오이 무침','뚝배기 생선 머리']
PS:자신 이 요리 이름 을 고 르 는 것 이 좋 습 니 다.죽은 목록 을 쓰 는 것 이 좋 습 니 다.😅

import imageio

frames = [text_img(text) for text in gif_list]
imageio.mimsave("meau.gif", frames, 'GIF', duration=0.02)
생 성 결과:
meau-1627295603332
요리 이름 목록 에 따라 움 직 이 는 그림 의 전체 코드 를 생 성 합 니 다.

import imageio
from PIL import Image, ImageFont, ImageDraw


def text_img(text, bgcolor="lightblue", bottomtext="      ?    ", size=360, result_size=(128, 128)):
    def text_border(text, x, y, font, shadowcolor, fillcolor):
        draw.text((x - 1, y), text, font=font, fill=shadowcolor)
        draw.text((x + 1, y), text, font=font, fill=shadowcolor)
        draw.text((x, y - 1), text, font=font, fill=shadowcolor)
        draw.text((x, y + 1), text, font=font, fill=shadowcolor)

        draw.text((x - 1, y - 1), text, font=font, fill=shadowcolor)
        draw.text((x + 1, y - 1), text, font=font, fill=shadowcolor)
        draw.text((x - 1, y + 1), text, font=font, fill=shadowcolor)
        draw.text((x + 1, y + 1), text, font=font, fill=shadowcolor)

        draw.text((x, y), text, font=font, fill=fillcolor)

    im = Image.new(mode='RGB', size=(size, size), color=bgcolor)
    draw = ImageDraw.Draw(im=im)
    fontsize = (size-20)//len(text)
    draw.text(xy=(10, (size-fontsize*1.5)/2),
              text=text, fill=0,
              font=ImageFont.truetype('msyh.ttc', size=fontsize))
    bottom_fontsize = (size-20)//len(bottomtext)
    bottom_font = ImageFont.truetype('STHUPO.TTF', size=bottom_fontsize)
    x, y = (size-bottom_fontsize*len(bottomtext))/2, size-bottom_fontsize*1.2
    draw.text(xy=(x, y), text=bottomtext,
              fill=0, font=bottom_font)
    text_border(bottomtext, x, y-4,
                bottom_font, 0, (255, 255, 255))
    im.thumbnail(result_size)
    return im


def save_meau_gif(savename, meau):
    frames = [text_img(text) for text in meau]
    imageio.mimsave(savename, frames, 'GIF', duration=0.02)
사용 예시:

meau = [
    "     ", "   ", "    ", "     ", "    ",
    "     ", "     ", "     ", "    ", "     ",
    "    ", "    ", "    ", "    ", "   ",
    "     ", "    ", "    ", "    ", "     ",
    "     ", "     ", "     ", "    ", "     ",
    "     ", "     ", "  h  ", "     ", "     ",
]
save_meau_gif("meau.gif", meau)
생 성 결과:
meau
우리 의 움 직 이 는 그림 부터 생 성 되 었 다!뭐 먹 을 지 모 르 겠 을 때 다 꺼 내 서 캡 처 하고 놀아 요.🐶
😆맛 있 게 드 세 요~
PIL 조작 gif 의 기타 조작
실 용적 인 전문 그래 픽 처리 소프트웨어 를 사용 하면 조작 할 수 있 습 니 다.다음은 python 의 조작 API 기록 을 보충 하 는 것 입 니 다.
Gif 분할
예 를 들 어 우 리 는 이 그림 을 나 누 었 다.
功夫熊

from PIL import Image, ImageSequence

img = Image.open('   .gif')
for i, f in enumerate(ImageSequence.Iterator(img), 1):
    f.save(f'  /   -{i}.png')
분할 결과:
image-20210726191539826
GIF 재생
아래 에 우 리 는 위의 이 동 도 를 다시 한 번 거꾸로 놓 았 다.

from PIL import Image, ImageSequence
import imageio

im = Image.open('   .gif')
sequence = [f.copy() for f in ImageSequence.Iterator(im)]
sequence.reverse()  #         reverse()      
sequence[0].save('     .gif', save_all=True, append_images=sequence[1:])
倒放功夫熊
파 이 썬 의 캡 처 선택 GIF 애니메이션 생 성에 관 한 이 글 은 여기까지 소개 되 었 습 니 다.더 많은 파 이 썬 생 성 캡 처 GIF 애니메이션 내용 은 저희 의 이전 글 을 검색 하거나 아래 의 관련 글 을 계속 읽 어 주시 기 바 랍 니 다.앞으로 도 많은 응원 부 탁 드 리 겠 습 니 다!

좋은 웹페이지 즐겨찾기