본문 바로가기

Python Markdown 렌더링 결과에 이미지 크기 넣어주기

기술적인 이야기/기타 개발 2025. 7. 13.
반응형

어떤 필요로 인해 마크다운 문서를 HTML로 렌더링 하는 과정에서 문서 안에 포함된 이미지(img)에 이미지의 크기를 넣어야 할 일이 있었다. 이 기능이 Python Markdown에서 기본적으로 제공하면 좋았겠으나 딱히 이런 기능은 없는 듯했다. 그래서 이 기능을 구현해 보기로 했다.

사실 이 부분은 SEO와 연관성이 있다. 이미지의 크기를 명시하지 않은 img 태그가 사용될 경우 HTML 문서가 렌더링 될 때 이미지가 로딩되면서 문서 크기가 바뀌며 다시 렌더링해야 되는 문제가 생기고 이 과정에서 깜빡임이 발생하거나 저사양 기기에서 사용성이 굼뜬 등의 불편함을 유발하기도 한다. 그래서 일부 검색엔진에서는 이미지 태그의 크기 정보 유무가 미묘하게 점수를 낮추거나 높이는 등의 요소로 작용할 수도 있다. 결과적으로 SEO 최적화 중에는 img 태그에 widthheight를 명시하는 것을 권장하고 있다.

크롬 개발자도구의 성능 평가 도구인 Lighthouse에서도 이 부분을 알려준다.

어쨌거나 본론으로 들어가 보자.

필요한 의존성 설치

이 기능은 이미지 파일을 읽어 이미지의 크기를 구해야 하기 때문에 이와 관련된 패키지로 Pillow(구 PIL - Python Imaging Library)를 사용하기로 했다. 간단히 pip로 설치해 주자.

$ pip install Pillow

물론 poetry 등의 다른 프로젝트 관리자를 사용한다면 그에 맞게 설치해 주면 된다.

$ poetry add Pillow

확장 구현

이 기능은 Python Markdown 패키지의 확장 형태로 구현했다. 아래는 실제 코드다.

class _ImageSizeWriter(Treeprocessor):
    def run(self, root):
        for img in root.findall(".//img"):
            src = img.get("src")

            with Image.open(src) as image:
                width, height = image.size
                img.attrib["width"] = str(width)
                img.attrib["height"] = str(height)


class ImageSizeWriterExtension(Extension):
    def extendMarkdown(self, md):
        image_size_writer = _ImageSizeWriter(md)
        md.treeprocessors.register(image_size_writer, "image_size_writer", 17)

ImageSizeWriterExtension 클래스는 확장 규격을 맞추기 위한 감싸기(wrap) 전용 클래스고 실제 일을 하는 클래스는 _ImageSizeWriter다. 이 클래스의 run 메서를 보면 모든 img 태그를 찾아서 여기 경로의 파일을 Pillow를 통해 열어서 가로 및 세로 크기를 구하고 이를 다시 img 태그의 widthheight 속성으로 붙여 넣어준다. 참고로 크기를 str을 써서 굳이 문자열로 바꿔서 넣은 이유는 정확히는 모르지만 정수로 넣게 될 경우 제대로 동작하지 않아서일 뿐이다.

고려해야 할 사항으로 위 코드에서는 이미지 파일의 경로를 그저 img 태그의 src 속성을 그대로 사용하고 있는데 이 부분은 더 가공이 필요할 수도 있다. 예를 들어 상대경로로 이미지 경로를 명시했다면 이 코드가 실행되는 환경에 따라 파일을 못 찾을 수도 있다. 이 부분은 환경이나 요구에 따라 달라지므로 적절히 구현해야 할 것 같다.

참고로 register 과정에서 마지막에 표기된 17은 이 확장의 우선순위로 숫자가 낮을수록 다른 우선순위가 낮은 확장보다 더 빨리 실행된다는 의미다. 더 줄이거나 더 늘려도 상관은 없지만 가장 늦은 우선순위는 20이니 적절히 설정하자.

실제로 사용해 보기

확장 형태로 구현했으니 이제 실제로 마크다운 문서를 렌더링 할 때 해당 확장을 끼워 넣어서 사용할 수 있다.

md = markdown.Markdown(
    extensions=[
        ... 생략 ...
        ImageSizeWriterExtension(),
    ],
)
body = md.convert(text)

이렇게 하면 최종적으로 뽑혀 나오는 HTML 코드에서 각 img 태그에 이미지 크기 속성이 명시되는 것을 확인할 수 있었다.

여담

해결해야 할 과제가 좀 있는 코드인데 예를 들어 로컬이 아닌 웹 상에 존재하는 이미지를 사용했다면 그 크기를 알아내기 위해 먼저 다운로드하는 과정이 필요하다. 하지만 상당히 귀찮은 작업이 될 것 같기에 이 글에서는 일단 제외시켰다.

실제로 이 기능을 붙여서 렌더링 된 정적 사이트가 개인 GitHub Pages에 올려져 있다. 굳이 소스를 확인할 필요는 없을 테고 그냥 잘 돌아간다는 그런 의미다.

이걸로 또 하나의 SEO 권장사항을 만족시키긴 했는데 여전히 Bing은 위 깃헙 페이지 사이트를 차단하고 있다. 도대체 무슨 이유일까 참 곤혹스러울 따름이다.

728x90
반응형

댓글