
    Ezi                        d Z ddlmZ ddlZddlZddlZddlmZ ddlm	Z	  ed      Z
e
dz  ZdZdd	Zd
dddddd	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 ddZddZddZddZddZddZy)u  Satori 텍스트 오버레이 호출 공통 헬퍼.

이 모듈은 한글 텍스트를 100% 정확하게 렌더링하기 위해 Satori (Node.js)를
서브프로세스로 호출하는 통합 진입점을 제공한다. 외부 API 직접 호출은 절대
허용되지 않는다 — Satori는 로컬 Node.js 프로세스를 통해서만 invoke된다.

한글 폰트 fallback 차단:
- font-family는 'Pretendard', 'Noto Sans KR'만 허용
- system fallback (Arial, Helvetica, sans-serif)은 한글 깨짐을 유발하므로 금지
- font-family는 빌드된 HTML/CSS에서만 사용 (PNG 렌더 자체는 Satori가 임베드한 폰트 사용)

IDS Phase 1 §3.2.1 / §0.2 Hybrid Pattern Standard 준수.
    )annotationsN)Path)Anyz2/home/jay/workspace/tools/ai-image-gen/satori-testzsatori_cli.jsz'Pretendard', 'Noto Sans KR'c                    t        | t              r|S t        | t              r| S t        | t        t        f      r	 t        |       S |S # t
        t        f$ r |cY S w xY w)uH   design_tokens dict에서 안전하게 정수를 추출 (pyright 호환).)
isinstanceboolintfloatstr	TypeError
ValueError)valuedefaults     ;/home/jay/workspace/skills/hybrid-image/patterns/_satori.pyas_intr       s_    %%%%&	u: N :& 	N	s   
A	 	AA z#ffffffz#e5e5e5zrgba(10, 10, 10, 0.55)@   $   )background_layertitle_color
body_color
overlay_bg
title_size	body_sizec               v    d| d| dt          d| d| d| d| dt        |        d	|	 d
| dt        |       dS )u5  Satori가 소비할 HTML 문자열을 생성한다.

    Args:
        title: 한글 헤드라인.
        body: 한글 본문.
        width: 출력 폭(px).
        height: 출력 높이(px).
        background_layer: 배경 div HTML (Gemini/Codex 결과 또는 Satori gradient).
        title_color: 헤드라인 색상.
        body_color: 본문 색상.
        overlay_bg: 가독성용 오버레이 박스 배경.
        title_size: 헤드라인 폰트 크기.
        body_size: 본문 폰트 크기.

    Returns:
        Satori-호환 HTML 문자열.
    z3<div style="display:flex; position:relative; width:zpx; height:zpx; font-family:z4; flex-direction:column; justify-content:flex-end;">zW<div style="display:flex; flex-direction:column; margin:60px; padding:48px; background:zB; border-radius:20px; word-break:keep-all;"><div style="font-size:zpx; font-weight:700; color:z*; line-height:1.375; margin-bottom:20px;">z</div><div style="font-size:zpx; font-weight:400; color:z; line-height:1.5;">z</div></div></div>)KOREAN_FONT_STACK_esc)
titlebodywidthheightr   r   r   r   r   r   s
             r   build_text_overlay_htmlr"   .   s    @ >eW E)*;)< ==
$$.< 0!!+ -GU} U!!* ,0d =	    c          
         t        |      }|j                  j                  dd       t        j                  d      }|t
        j                         ro| ||t        |      d}	 t        j                  |t        t
              gt        j                  |      dddt        t              d       |j                         r|S 	 t!        | |||      S # t        j                  t        j                  t        f$ r Y 9w xY w)u  HTML을 Satori (Node.js)로 PNG 렌더링한다.

    Satori 스크립트가 부재하면 Pillow 기반 minimal fallback (텍스트만 렌더).
    어떤 경우에도 한글은 100% 정확하게 보존된다 — 외부 API 호출 없음.

    Args:
        html: Satori-호환 HTML.
        output_path: 출력 PNG 경로.
        width: 폭.
        height: 높이.

    Returns:
        실제 저장된 PNG 경로.
    T)parentsexist_oknode)htmlr    r!   outputx   )inputtextcheckcapture_outputcwdtimeout)r    r!   )r   parentmkdirshutilwhichSATORI_RENDER_SCRIPTexistsr   
subprocessrunjsondumpsSATORI_SCRIPT_DIRCalledProcessErrorTimeoutExpiredFileNotFoundError_pillow_fallback)r(   output_pathr    r!   node_binpayloads         r   render_html_to_pngrC   ]   s     {#KTD9||F#H 4 ; ; =+&	#
	NN3345jj)#)* !!#"" $ D+U6JJ	 --z/H/HJ[\ 		s   %AC (C=<C=c                  	 ddl m}m} |j                  d||fd      }|j                  |      }t        |       }|j                  d|dd d	
       |j                  |d       |S # t        $ r t	        |||       |cY S w xY w)u   Satori 부재 시 Pillow로 placeholder PNG 생성 (한글 텍스트 보존).

    IDS 표준: 외부 API 호출 0건. 환경 의존 도구 부재 시 graceful degrade.
    r   )Image	ImageDrawRGB)   rH      )color)(   rK   Ni  )   rL   rL   )fillPNG)format)
PILrE   rF   ImportError_write_blank_pngnewDraw_strip_tagsr,   save)	r(   r@   r    r!   rE   rF   imgdrawr,   s	            r   r?   r?      s    
( ))EE6?,)
?C>>#DtDIIhTc
I9HH[H'  eV4s   A( (BBc           
     "  	 ddl ddl	dj                  fdt        |      D              }	j	                  |      }d	fd}d}j                  d|dd	ddd      }| j                  | |d
|      z    |d|      z    |dd      z          y)uh   Pillow 미설치 시 최소 PNG (단색) 작성.

    PNG 헤더만 직접 작성. 외부 의존 0.
    r   Nr#   c              3  .   K   | ]  }d dz  z     yw)    s   N ).0_r    s     r   	<genexpr>z#_write_blank_png.<locals>.<genexpr>   s     L7_u44Ls   c                    j                  | |z         dz  }j                  dt        |            | z   |z   j                  d|      z   S )Nl    z>I)crc32packlen)tagdatacrcstructzlibs      r   chunkz_write_blank_png.<locals>.chunk   sI    jjt$z1{{4T+c1D86;;tS;QQQr#   s   PNG

z>IIBBBBB      s   IHDRs   IDATs   IEND)rd   bytesre   rl   returnrl   )rg   rh   joinrangecompressrb   write_bytes)
r@   r    r!   raw
compressedri   sigihdrrg   rh   s
    `      @@r   rR   rR      s    
 
((LeFmL
LCs#JR C;;z5&!Q1a@DeGT""U7J%??%QTBUUr#   c                    | j                  dd      j                  dd      j                  dd      j                  dd      S )	u%   HTML 이스케이프 (한글 보존).&z&amp;<z&lt;>z&gt;"z&quot;)replace)r,   s    r   r   r      s;     	S'"	f		f		h		r#   c                v    ddl }|j                  dd|       }|j                  dd|      }|j                         S )u(   HTML 태그 제거 (Pillow fallback용).r   Nz<[^>]+> z\s+)resubstrip)r(   r~   r,   s      r   rU   rU      s5    66*c4(D66&#t$D::<r#   )r   objectr   r	   rm   r	   )r   r   r   r   r    r	   r!   r	   r   r   r   r   r   r   r   r   r   r	   r   r	   rm   r   )
r(   r   r@   r   r    r	   r!   r	   rm   r   )r@   r   r    r	   r!   r	   rm   None)r,   r   rm   r   )r(   r   rm   r   )__doc__
__future__r   r9   r3   r7   pathlibr   typingr   r;   r5   r   r   r"   rC   r?   rR   r   rU   r\   r#   r   <module>r      s    #      MN (?:  3 (  .,,
, 	,
 , , , , , , , 	,^*KZ*,r#   