3P by GN⁺ | ★ favorite | 댓글 1개
  • ASCII Silhouettify는 로고·배너·픽셀아트처럼 평면적이고 고대비인 그래픽을 95개 출력 가능 ASCII 문자만으로 채운 실루엣 ASCII 아트로 바꾸는 브라우저·명령줄 앱임
  • png, svg, jpg, webp, gif, tif, heif, avif, pdf를 입력으로 받지만, 음영·하이라이트·그림자·그라데이션을 렌더링하지 않아 사진 변환에는 적합하지 않음
  • 출력은 ANSI 컬러 텍스트, 일반 텍스트, HTML, Neofetch 커스텀 ASCII 아트 형식을 지원하며, Neofetch 형식은 256색 확장 ANSI 팔레트 중 6색으로 제한됨
  • 변환 알고리듬은 이미지를 색상 평면으로 나눈 뒤 각 9×19 픽셀 영역에서 실루엣 윤곽을 침범하지 않는 ASCII 문자 중 가장 큰 문자를 고름
  • 성능을 위해 95비트 누산기, 171개 비트마스크, leading zeros 계산, 논리 프로세서 병렬 처리를 사용하고, 팔레트 매칭에는 계산 비용이 큰 CIEDE2000 지각 색상 차이 공식을 적용함

ASCII 실루엣 변환 앱

  • ASCII Silhouettify는 이미지를 ASCII 실루엣으로 바꾸는 앱임
    • ASCII 실루엣은 선이나 질감보다 균일하게 채워진 기하학적 형태가 두드러지는 ASCII 아트 스타일임
    • 로고, 배너, 픽셀아트처럼 최소주의적이고 고대비이며 입체 깊이가 없는 평면 그래픽에 잘 맞음
    • 음영, 하이라이트, 그림자, 그라데이션을 렌더링하지 않기 때문에 사진에는 적합하지 않음
  • 문자 집합은 전통적 ASCII 아티스트의 매체인 95개 출력 가능 ASCII 문자로 제한됨
    • ANSI 아트에서 흔한 선·블록 문자나 kaomoji의 많은 Unicode 문자는 사용하지 않음
  • 출력 형식은 설정에 따라 달라짐
    • 단색 일반 텍스트
    • ANSI 이스케이프 시퀀스로 색상이 들어간 텍스트
    • 컬러 포함 또는 미포함 HTML
    • Neofetch ASCII 아트 형식
  • 브라우저와 명령줄에서 사용할 수 있는 데스크톱 앱

Ubuntu 로고와 Neofetch 예시

  • 예시는 Ubuntu 인스턴스에서 Neofetch 출력에 ASCII Silhouettify 결과를 넣는 흐름을 보여줌
  • 최적의 ASCII 아트를 얻기 위해 웹에서 고해상도 Ubuntu 로고 이미지를 가져오고, 콘솔에서 보일 크기로 먼저 스케일링함
  • 명령줄 버전으로 이미지를 변환하면 기본적으로 ANSI 이스케이프 시퀀스 컬러 텍스트가 생성됨
  • -o 플래그로 Neofetch가 표시할 파일에 출력을 보낼 수 있음
  • Neofetch는 ANSI 아트와 OS 지표 사이에 넓은 여백을 넣기 때문에, 예시는 Neofetch 커스텀 ASCII 아트 파일 형식을 사용함
    • 출력 파일의 첫 줄은 색상 인덱스 목록임
    • 이후 줄은 인코딩된 이미지임
    • 텍스트 편집기에서 첫 줄을 클립보드에 복사한 뒤 제거함
    • Neofetch 실행 시 클립보드에 저장한 값을 붙여 넣어 사용함
    • 영구 적용하려면 Neofetch bash 스크립트 일부를 같은 값으로 교체함
  • 원본 로고를 생성 결과 위에 겹쳐 비교하면, 알고리듬이 각 색상 영역의 윤곽 안에 들어가는 가장 큰 문자를 고르는 방식이 드러남

설치와 제거

  • 명령줄 버전은 Node.js 애플리케이션
  • Node.js가 없다면 Node.js 설치 절차를 먼저 따라야 함
  • macOS와 Linux에서는 root 사용자 없이 전역 설치할 수 있도록 npm 설정이 필요함
  • 설치 명령:
    • npm install -g ascii-silhouettify
  • 제거 명령:
    • npm uninstall -g ascii-silhouettify

입력·출력 옵션

  • 브라우저 버전과 명령줄 버전은 같은 옵션 집합을 지원함
    • 명령줄 버전의 -h 플래그는 옵션 요약 메시지를 출력함
  • 여러 이미지를 한 번에 변환할 수 있음
    • 지원 형식은 png, svg, jpg, webp, gif, tif, heif, avif, pdf
    • 명령줄 버전의 -i 플래그는 여러 파일명 패턴 매칭 규칙을 받음
    • 입력 이미지는 검은색 또는 투명 배경이어야 함
  • 출력은 네 가지 계열로 나뉨
    • 일반 텍스트 또는 ANSI 컬러 텍스트
    • HTML 형식의 고정폭 텍스트
    • Neofetch 커스텀 ASCII 아트 형식
    • Neofetch 형식은 256색 확장 ANSI 팔레트 중 6색으로 제한됨
  • 팔레트 기본값은 256색 확장 ANSI 팔레트에서 표준 16색 ANSI 팔레트를 제외한 240색
    • 표준 ANSI 팔레트 16색은 현대 터미널 에뮬레이터에서 재정의되는 경우가 많아 기본값에서 제외됨
    • 사용자는 표준 ANSI 팔레트의 첫 8색, 표준 ANSI 16색 전체, 확장 ANSI 256색 전체, 기본 240색 팔레트를 선택할 수 있음
  • 출력에 나타날 최대 색상 수를 지정할 수 있음
    • 검은색 배경으로 간주되는 색상은 카운트하지 않음
    • 기본값은 255임
    • 단색 모드는 사실상 이 값을 1로 설정함
    • Neofetch 커스텀 ASCII 아트 형식의 기본값은 해당 형식의 최대값인 6임

표시 크기와 변환 품질 조정

  • 터미널 에뮬레이터에서 생성된 ASCII 아트의 종횡비는 글꼴, 글꼴 크기, 줄 높이, 문자 크기 반올림 규칙에 따라 달라짐
  • 최적화를 위해 터미널의 텍스트 이미지를 캡처하고, 줄 사이 공간을 포함한 각 고정폭 문자의 픽셀 크기를 측정함
  • 개발자의 Windows 데스크톱 기준 측정 예시는 다음과 같음
    • IntelliJ Terminal: 문자 8×22, 글꼴 크기 10, 줄 높이 1.65
    • Putty: 문자 8×16, 글꼴 크기 10, 줄 높이 1.2
    • Notepad: 문자 10×18, 글꼴 크기 13, 줄 높이 1.04
    • Notepad++: 문자 9×19, 글꼴 크기 12, 줄 높이 1.2
    • Windows Command Prompt: 문자 8×16, 글꼴 크기 10, 줄 높이 1.2
    • Windows Console Host: 문자 9×20, 글꼴 크기 12, 줄 높이 1.25
    • Windows Terminal: 문자 9×19, 글꼴 크기 12, 줄 높이 1.2
  • 입력 이미지는 터미널에 표시될 원하는 크기로 페인트 프로그램에서 미리 스케일링하는 편이 이상적임
    • 작은 조정을 위해 ASCII Silhouettify는 이미지 스케일링 계수를 받음
    • 기본값은 1임
  • 변환 알고리듬은 밝기 5% 미만 영역을 공백 문자로 바꿔 검은색 배경이 완전히 드러나게 함
    • 사용자는 이 어두움 임계값을 조정할 수 있음
  • 기본적으로 사용 가능한 모든 논리 프로세서에 작업을 분산함
    • 사용자는 할당 프로세서 수를 1개까지 줄일 수 있음
    • 프로세서 수를 줄이면 처리 시간이 길어짐

변환 알고리듬

  • 개발자가 ASCII Silhouettify를 만든 Windows 데스크톱에서 Terminal은 기본 12포인트, 1.2em Cascadia Mono 설정일 때 각 고정폭 문자를 9×19 픽셀 사각형 안에 렌더링함
  • 알고리듬은 95개 출력 가능 ASCII 문자의 이미지를 캡처하고, 50% 강도 기준으로 임계 처리해 흑백 픽셀만 가진 문자 이미지를 만듦
  • 소스 이미지는 고유 색상 평면으로 분리됨
    • 각 평면은 검은 배경 위의 흰색 실루엣임
  • 각 색상 평면은 9×19 픽셀 직사각형 영역 행렬로 나뉨
    • 각 영역은 하나의 ASCII 문자로 대체됨
  • 최적 문자는 영역과 모든 ASCII 문자 이미지를 픽셀 단위로 비교해 선택함
    • 문자 이미지의 흰 픽셀이 영역의 검은 픽셀과 겹치면, 실루엣 윤곽을 왜곡하지 않기 위해 해당 문자를 제외함
    • 남은 문자 중 흰 픽셀 매칭 수가 가장 많은 문자를 선택함
  • 영역을 문자로 대체할 때 매칭된 흰 픽셀 수를 기록함
    • 모든 평면을 변환한 뒤, 가장 높은 매칭 흰 픽셀 수를 가진 문자를 선택해 평면들을 결합함
    • 최종 문자는 해당 문자가 나온 평면의 색상으로 칠해짐

비트마스크 기반 가속

  • 변환 전에 ASCII 문자 이미지를 흰 픽셀 수 기준으로 정렬함
    • 공백 문자는 흰 픽셀이 0개로 가장 적음
    • @ 문자는 흰 픽셀이 가장 많음
  • 알고리듬은 @부터 아래로 내려가며 각 영역과 문자 이미지를 비교함
    • 실루엣 안에 완전히 들어가는 문자를 찾는 즉시 해당 영역을 그 문자로 대체함
    • 정렬 덕분에 그 문자는 흰 픽셀 수가 가장 많은 후보임
  • 속도를 크게 높이기 위해 9×19 영역의 각 픽셀에 대해 171개 비트마스크를 준비함
    • 각 비트마스크는 해당 좌표에 검은 픽셀을 가진 ASCII 문자 이미지 집합을 나타냄
    • 각 비트마스크는 95비트를 포함함
    • bit-0은 공백 문자, bit-94는 @ 문자에 대응함
  • 영역 변환 중에는 95비트 누산기로 사용 가능한 ASCII 문자 후보 집합을 점점 좁힘
    • 시작 시 누산기는 모든 비트가 1로 초기화됨
    • 영역의 각 검은 픽셀에 대해 현재 누산기와 해당 픽셀 비트마스크를 bitwise AND함
    • 이 연산은 영역의 검은 픽셀 위치에 흰 픽셀이 있는 문자 이미지를 제외함
  • 영역 전체를 처리한 뒤 누산기의 set bit는 대체 가능한 문자 후보임
    • 문자가 정렬되어 있으므로, 누산기의 leading zeros 수가 실루엣 안에 완전히 포함되는 가장 흰 픽셀 많은 ASCII 문자 이미지의 인덱스가 됨
    • 라이브러리 도움으로 마이크로프로세서의 leading zeros 계산 명령을 호출해 필요한 값을 빠르게 얻음

원점 최적화와 색상 매칭

  • 소스 이미지를 직사각형 영역 행렬로 나눌 때 행렬의 원점은 결과에 영향을 줌
  • 결과를 최적화하기 위해 알고리듬은 이미지 원점 주변 9×19 픽셀 영역 안의 모든 정수 좌표 원점에 대해 전체 이미지 변환을 반복함
  • 많은 처리량을 감당하기 위해 작업은 사용 가능한 논리 프로세서에 분산됨
  • 색상 팔레트는 사용자 설정에 따라 표준 ANSI 팔레트 첫 8색부터 확장 ANSI 256색 전체까지 제한될 수 있음
  • 소스 이미지를 고유 색상 평면으로 분리할 때, 팔레트 안에서 가장 가까운 색상을 찾기 위해 계산 비용이 큰 CIEDE2000 지각 색상 차이 공식을 사용함

소스 코드

댓글과 토론

Hacker News 의견들
  • 이 사이트에서 제일 멋진 페이지는 컬러 갤러리 같음: https://meatfighter.com/ascii-silhouettify/color-gallery.htm...

    • Wendy's 로고는 살짝 섬뜩함
    • Mastodon 로고가 없으니 이 페이지는 무효임
    • Z 로고는 정말 영리함
      아이콘 그래픽 디자인을 다른 관점에서 보게 해주는 느낌임
  • 코드에 바로 넣을 수 있는 게임 스프라이트를 만들려고 비슷한 도구를 만들었음: https://memalign.github.io/m/pceimage/index.html
    웹에서 동작하고, 색이 들어간 ASCII 출력도 편집 가능함
    다만 결과를 좋게 만들려면 Wobble을 수동으로 끄고 픽셀 샘플링 크기를 조정해야 해서 조금 까다로움

    • 정말 재미있고 마음에 듦
      추천하자면, 흔들림은 없애되 두껍게 만들고 모서리를 둥글게 해서 생기는 귀여운 느낌은 유지하는 모드가 있으면 좋겠음
  • ASCII 관련 아트를 좋아한다면, GIF를 ASCII로 바꿔주는 애니메이션 ASCII 도구도 좋아할 것 같음: https://www.gifcii.fun
    참고로 직접 만들었음

    • GIF를 좋아하는 입장에서는 정말 재미있음
      somehow 저장할 수 있으면 좋겠고, 예를 들면 다시 GIF나 동영상으로 내보내면 멋질 듯함
  • 웹 버전은 Chromium 기반 브라우저에서 끝나지 않지만, CLI 버전은 동작함: https://meatfighter.com/ascii-silhouettify/spa/index.html#/
    덤으로 HN 로고처럼 보이는 큰 ASCII 아트도 만들어 봄

  • 멋진 작업이고, 색이 들어간 Telnet Matrix가 떠오름 :)
    나중에 https://ascii.theater/도 발견했음
    몇 년 전 레트로 컴퓨터 이미지 변환기용으로 비슷한 걸 만들었는데, 그 컴퓨터의 고정폭 글꼴을 사용했고 문자 변환 전에 디더링도 적용했음
    사진에서 더 부드러운 그라데이션이 나왔기 때문임: https://github.com/KodeMunkie/imagetozxspec/blob/master/src/...

  • “이미 있었던 것이 다시 있을 것이며, 이미 한 일이 다시 행해질 것이다. 해 아래 새것은 없다.”
    잘 만들었음
    예전에는 EBCDIC과 ASCII로 문자들의 인쇄 밀도를 이용해 생일 배너와 그림을 연속 용지 밴드 프린터, 이후 도트 매트릭스 프린터로 아주 비슷하게 출력하곤 했음

  • 오늘 /etc/motd/etc/issue를 수정하는 사람이 꽤 많아질 것 같음

  • 실시간으로 움직이는 흔들리는 함수로 비슷한 걸 해봤음: https://piter-genuary2024.netlify.app/genuary9/

    • 표준 로그 tail 출력에서 시작해서 점점 더 눈에 보이는 패턴을 섞다가, 결국 텍스트 사이에서 무서운 얼굴이 나타나는 식으로 기괴한 걸 만들 수 있을지 궁금함
  • 또 npm이라니
    프로젝트는 훌륭하지만 왜 꼭 이렇게 해야 하는지 모르겠음
    평범한 설치 방식은 어디로 간 건가 싶음

    • 어떤 대안을 제안하는지 궁금함
      NPM은 어디서나 같은 방식으로 동작하고, NPM만큼 여러 플랫폼에서 널리 쓰이는 패키지 관리자는 없음
    • 여기서 말하는 “평범한 설치”가 어떤 방식인지 알려주면, 그 방식의 문제를 말해줄 수 있음
    • 설치할 필요도 없음
      그냥 npx로 실행하면 됨
    • 그러게, 평범한 설치 방식은 어떻게 된 건지, 아니면 애초에 된 적이 없는 건지 모르겠음
      다른 방식으로 설정하려면 몇 시간이 걸리고 난장판이 되어서, 내 CLI 저장소들은 여기저기서 npm/yarn link로 연결해 씀
      심지어 Python 스크립트도 nodemon main.py로 개발하는데, 필요한 걸 아는 건 Node 쪽 사람들뿐인 것 같기도 함
  • 그래도 Figma보다 https://asciiflow.com/#를 계속 쓸 것 같음