
    si1&                    Z   U d Z ddlmZ ddlZddlZddlZddlZddlmZ ddl	m
Z
mZ ddZ ee      j                  Zedz  Zedz  Zed	z  Zd
ZdZdZddZeefddZefddZd dZd!dZd"dZd#dZd$dZd%d&dZi Zde d<   d'd(dZ!	 	 	 d)	 	 	 	 	 	 	 	 	 	 	 d*dZ"d Z#e$dk(  r e#        yy)+ud  squircle.py — converte PNG raw em squircle 512×512 com bg color correto.

Pipeline:
1. Resize+pad pra 512×512 (preservando aspect ratio, transparent pad)
2. Detecta bg color: override hex > edge-ring k-means > auto-neutral por luminance
3. Composita logo sobre bg sólido (elimina cantos transparentes)
4. Aplica squircle mask (radius ~22%)
5. Modula saturação *= 0.5
6. Salva 512×512 PNG

Usage as module:
    from squircle import make_squircle
    make_squircle("raw.png", "out.png", override_hex="#fafafa", desat=True)

Usage as CLI:
    python squircle.py <input> <output> [--bg #RRGGBB] [--no-desat]
    )annotationsN)Path)Image
ImageColorc           
        t        |       } | j                  j                         dk(  rt        j                  dddddt        |       gd      }|j                  dk(  rYt        |j                        d	kD  rAt        j                  t        j                  |j                              j                  d
      S 	 ddl}|j                  t        |       ddd      }t        j                  t        j                  |            j                  d
      S t        j                  |       j                  d
      S # t         $ r }t#        d| j$                   d|       d}~ww xY w)z[Open PNG, SVG, or other formats. SVGs rasterized via rsvg-convert (with cairosvg fallback).z.svgzrsvg-convertz-w1024z-hT)capture_outputr   d   RGBANi   )urloutput_widthoutput_heightunsafez*Both rsvg-convert and cairosvg failed for z: )r   suffixlower
subprocessrunstr
returncodelenstdoutr   openioBytesIOconvertcairosvgsvg2png	ExceptionRuntimeErrorname)pathresultr   	png_byteses        >/root/nxt/terminal.net.br/recursos/assets/_scripts/squircle.py
load_imager&      s+   :D{{f$T64TC
 !c&--&83&>::bjj78@@HH
	 ((ID ) I ::bjj34<<VDD
 ::d##F++	  	<TYYKr!M 	s   8AD5 5	E>EEzcircle-mask-85pct-512.pngzcircle-mask-512.pngzsquircle-mask-512.pngi   g{Gz?g333333?c                    | j                  d      } | j                         }|rW| j                  |      }|j                  d   | j                  d   dz  k  s"|j                  d   | j                  d   dz  k  r|S | S )u   Auto-crop borda do logo: remove pixels transparentes/quase-brancos das margens.
    Garante que o CONTEÚDO real (não o frame do raw) seja a unidade de medida.r   r   gffffff?   )r   getbboxcropsize)imgbboxcroppeds      r%   
trim_imager/   @   ss     ++f
C;;=D((4.<<?SXXa[4//7<<?SXXa[SWEW3WN J    c                   | j                  d      } t        |       } | j                  \  }}t        dt	        ||z              }|t        ||      z  }t        dt	        ||z              t        dt	        ||z              f}| j                  |t        j                        } t        j                  d||fd      }|j                  | ||d   z
  dz  ||d   z
  dz  f|        |S )u   Fit img content into (size*content_pct)×(size*content_pct) area, centered on size canvas.
    Trim transparent borders ANTES do resize pra garantir proporção uniforme.r   r(   )r   r   r   r   r      )
r   r/   r+   maxintresizer   LANCZOSnewpaste)	r,   r+   content_pctwhtargetscalenew_sizecanvass	            r%   
resize_padr@   P   s     ++f
C
S/C88DAqC{*+,FSAYEAs1u9~&As1u9~(>?H
**Xu}}
-CYYvd|\:F
LLx{*q04(1+3E!2KLcRMr0   c           	     :   | j                   \  }}t        t        |t        ||      z        d      }| j	                         }g }t        t        |            t        t        ||z
  |            z   D ]:  }t        d|d      D ](  }|||f   \  }	}
}}|dkD  s|j                  |	|
|f       * < t        t        |            t        t        ||z
  |            z   D ]=  }t        |||z
  d      D ](  }|||f   \  }	}
}}|dkD  s|j                  |	|
|f       * ? |S )zESample opaque pixels from outer ring. Returns list of (R,G,B) tuples.   r   r2      )r+   r3   r4   minloadlistrangeappend)r,   
margin_pctr:   r;   marginpxpixelsyxrgbas                r%   edge_pixelsrS   _   s-   88DAqZ#a)+,a0F	BF%- 4a&j!(<#== )q!Q 	)AAqDJAq!Q3wq!Qi(	)) %- 4a&j!(<#== )vq6z1- 	)AAqDJAq!Q3wq!Qi(	))
 Mr0   c                   | sy| D cg c]  }|d   	 }}| D cg c]  }|d   	 }}| D cg c]  }|d   	 }}t        |      t        |      z
  t        |      t        |      z
  t        |      t        |      z
  g}|j                  t        |            t        fd| D              t	        |       dz     }| D cg c]  }|   |k  s| }}| D cg c]  }|   |kD  s| }}t	        |      t	        |      k\  r|n|}	|	s| }	t	        |	      }
t        d |	D              |
z  t        d |	D              |
z  t        d |	D              |
z  f}|S c c}w c c}w c c}w c c}w c c}w )	zJSimple 2-cluster median-cut. Returns dominant cluster centroid as (R,G,B).Nr   r(   r2   c              3  (   K   | ]	  }|     y w)N ).0paxiss     r%   	<genexpr>zmedian_cut_2.<locals>.<genexpr>~   s     +q1T7+s   c              3  &   K   | ]	  }|d      yw)r   NrV   rW   rX   s     r%   rZ   zmedian_cut_2.<locals>.<genexpr>        !QAaD!   c              3  &   K   | ]	  }|d      yw)r(   NrV   r\   s     r%   rZ   zmedian_cut_2.<locals>.<genexpr>   r]   r^   c              3  &   K   | ]	  }|d      yw)r2   NrV   r\   s     r%   rZ   zmedian_cut_2.<locals>.<genexpr>   r]   r^   )r3   rD   indexsortedr   sum)rL   rX   rsgsbsrangespivot	cluster_a	cluster_blargernavgrY   s               @r%   median_cut_2rn   t   sm   	1!A$	B		1!A$	B		1!A$	B	"gBR3r7!2CGc"g4EFF<<F$D+F++CK1,<=E"7qag&67I7"6qago6I6i.C	N:Y	FFA!&!!Q&!&!!Q&!&!!Q&C
 J# 
 		 86s'   EEE  E%E%E*&E*c                L    t        |       }t        |      dk  ryt        |      S )zDetect probable bg color via edge ring sampling + 2-cluster median cut.
    Returns RGB tuple or None if logo is mostly transparent at edges.r
   N)rS   r   rn   )r,   rL   s     r%   	detect_bgrp      s(     F
6{Sr0   c                6    | \  }}}d|z  d|z  z   d|z  z   dz  S )z,Perceptual luminance 0..1 (Rec.709 weights).gz6?g,C?g]m{?g     o@rV   )rgbrO   rP   rQ   s       r%   	luminancers      s.    GAq!QJ!#fqj0E99r0   c                   | j                         }| j                  \  }}d}d}t        d|d      D ]<  }t        d|d      D ]*  }|||f   \  }}	}
}|dkD  s|t        ||	|
f      z  }|dz  }, > |dk(  ry||z  }|dkD  rdS dS )	zNPick contrasting neutral bg based on dominant luminance of opaque logo pixels.g        r      rC   r(   )               ?)
   rz   rz   )rE   r+   rG   rs   )r,   rK   r:   r;   sum_lcountrM   rN   rO   rP   rQ   rR   avg_ls                r%   auto_neutralr~      s    	B88DAqEE1a^ q!Q 	AAqDJAq!Q3wAq!9--
		 zEME 3;<;O;r0   c                2    t        j                  |       dd S )u   #RRGGBB → (R,G,B).N   )r   getrgb)hex_strs    r%   	parse_hexr      s    W%bq))r0   c                J   | j                  d      } | j                         \  }}}}t        j                  d|||f      }|j                  d      j                  d      }t        j                  |||      }|j                         \  }	}
}t        j                  d|	|
||f      S )z;Reduce saturation. factor=1.0 = unchanged, 0.0 = grayscale.r   RGBL)r   splitr   mergeblend)r,   factorrO   rP   rQ   rR   rr   grayblendedrbgbbbs               r%   
desaturater      s    
++f
CJAq!Q
++eaAY
'C;;s##E*Dkk$V,GJBB;;vBA//r0   zdict[str, Image.Image]_mask_cachec                    | t         vr<| dk(  rt        nt        }t        j                  |      j                  d      t         | <   t         |    j                         S )uQ   Load (and cache) alpha mask 512×512 (L mode). shape=circle (default) | squircle.squircler   )r   SQUIRCLE_MASK_PATH	MASK_PATHr   r   r   copy)shaper!   s     r%   squircle_maskr      sK    K%*j%8!i"ZZ-55c:Eu""$$r0   c                   t        |       }t        |t              }|rt        |      }d| }nEt	        |      }|r|}d|d   d|d   d|d   d}n t        |      }d|d   d|d   d|d   d}t        j                  dt        t        f|d	z         }	|	j                  |       t        |      }
|	j                  |
       |rt        |	d
      }	|	j                  |
       t        |      j                  j                  dd       |	j                  |dd       t!        |       t!        |      d|d   d|d   d|d   d||dS )z]Apply full pipeline. shape=circle (default) | squircle. desat=False default (preserve cores).z	override:z
detected:#r   02xr(   r2   z	neutral:#r   )   ry   T)parentsexist_okPNG)optimize#)inputoutputbg	bg_sourcedesat)r&   r@   SIZEr   rp   r~   r   r7   alpha_compositer   putalphar   r   parentmkdirsaver   )raw_pathoutput_pathoverride_hexr   r   r,   r   r   detectedr?   masks              r%   make_squircler      sp    X
C
S$
C |$~.	S>B$RU3K1c{2a5+FIc"B#BqE#;r!uSk"Q%EI YYvd|R&[9F
3 D
OOD FC(""4$"?
KKUTK2 Xk""Q%RU3K1c{3 r0   c            	        t        j                  d      } | j                  dd       | j                  dd       | j                  dd	       | j                  d
ddgd       | j                  ddd       | j                         }t	        |j
                  |j                  |j                  |j                  |j                        }t        d|d    d|d    d|d           y )Nu5   Convert raw PNG/SVG to circle (or squircle) 512×512.)descriptionr   zraw PNG/SVG path)helpr   zoutput PNG pathz--bgzoverride bg hex (#RRGGBB)z--shapecircler   )choicesdefaultz--desat
store_truezapply 50%% desaturation)actionr   )r   r   zOK: bg=r   z (r   u   ) → )argparseArgumentParseradd_argument
parse_argsr   r   r   r   r   r   print)apargsinfos      r%   mainr      s    		 	 -d	eBOOG"4O5OOH#4O5OOF!<O=OOI*'=xOPOOIl9ROS==?DT[[$''SWS]S]^D	GDJ<r${"3!4F4>:J
KLr0   __main__)r!   
str | PathreturnImage.Image)r,   r   r   r   )r,   r   r+   r4   r9   floatr   r   )r,   r   rI   r   r   list[tuple[int, int, int]])rL   r   r   tuple[int, int, int] | None)r,   r   r   r   )rr   tuple[int, int, int]r   r   )r,   r   r   r   )r   r   r   r   )ry   )r,   r   r   r   r   r   )r   )r   r   r   r   )NFr   )r   r   r   r   r   z
str | Noner   boolr   r   r   dict)%__doc__
__future__r   r   r   r   syspathlibr   PILr   r   r&   __file__r   
SCRIPT_DIRr   MASK_FULL_PATHr   r   EDGE_MARGIN_PCTCONTENT_PCTr/   r@   rS   rn   rp   rs   r~   r   r   r   __annotations__r   r   r   __name__rV   r0   r%   <module>r      s  " #  	  
  !,2 (^""
 44	33"99 
  .2  7F *2 :<&*
0 ')# (%  $... . 	.
 . 
.b
M zF r0   