o
    @Tj                     @   s2  d Z ddlZddlZddlZddlmZ ddlmZ ddlZddl	m
Z
 ddlmZ eeZdZd$d	ed
edefddZdedejdefddZdedejdefddZdedejdefddZdedefddZdedB ddfddZdejdefddZd%dededefdd Zd&dededefd"d#ZdS )'z0Image save / resize / path management utilities.    N)Path)urlparse)Image)settingsi  @      .@urltimeoutreturnc              
      sZ  t | }|jdvrtd|jpd |jstdz+tj|dd4 I dH }|| I dH }W d  I dH  n1 I dH s@w   Y  W n tjy[ } ztd| |d}~ww |jd	kritd
|j |j	}t
|dkrvtdt
|tkrtdt
| dt d|jdddd   }|r|ds|dkstd| |S )a  Download an image from an HTTP(S) URL and return raw bytes.

    Performs server-side (no browser CORS), with scheme/size/content-type
    guards suitable for untrusted user-supplied URLs in a POC context.
    Raises ``ValueError`` on any failure so the caller can surface a 400.
    )httphttpsu)   지원하지 않는 URL 스킴입니다: z(empty)u,   URL 호스트를 해석할 수 없습니다.T)r   follow_redirectsNu+   이미지를 가져오지 못했습니다: i  u0   이미지를 가져오지 못했습니다: HTTP r   u   빈 이미지 응답입니다.u2   이미지 크기가 제한을 초과했습니다: z > z byteszcontent-type ;zimage/zapplication/octet-streamu5   이미지가 아닌 콘텐츠입니다: content-type=)r   scheme
ValueErrornetlochttpxAsyncClientgetRequestErrorstatus_codecontentlenMAX_IMAGE_FETCH_BYTESheaderssplitstriplower
startswith)r   r   parsedclientresper   ctype r$   //home/ubuntu/htdocs/ootd-api/app/utils/image.pyfetch_image_bytes   s<   
(
 r&   image_bytesuser_idc                 C   V   t dt| }t tj| }|jddd t j d}|| |  t|| S )zDSave original uploaded image and return path relative to UPLOAD_DIR.	originalsTparentsexist_okz.jpg	r   strr   
UPLOAD_DIRmkdiruuiduuid4hexwrite_bytesr'   r(   rel_pathdest_dirfilenamer$   r$   r%   save_original_image:      r:   c                 C   r)   )zBSave ghost mannequin image and return path relative to UPLOAD_DIR.ghost_mannequinTr+   .pngr.   r6   r$   r$   r%   save_ghost_mannequin_imageD   r;   r>   c                 C   r)   )zHSave VTON composite result image and return path relative to UPLOAD_DIR.vtonTr+   r=   r.   r6   r$   r$   r%   save_vton_imageN   r;   r@   c                 C   sN   t d}t tj| }|jddd t j d}|| |  t|| S )zFSave segmentation result image and return path relative to UPLOAD_DIR.segmentationTr+   r=   )	r   r   r0   r1   r2   r3   r4   r5   r/   )r'   r7   r8   r9   r$   r$   r%   save_segmentation_imageX   s   rB   relative_pathc                 C   sZ   | sdS t tj|  }z|jdd td|  W dS  ty,   tjd| dd Y dS w )zDelete an image file by its path relative to UPLOAD_DIR.

    Logs a warning and continues if the file doesn't exist or deletion fails.
    NT)
missing_okzDeleted image: %szFailed to delete image: %sexc_info)r   r   r0   unlinkloggerinfoOSErrorwarning)rC   filepathr$   r$   r%   delete_imageb   s   rM   c              
   C   s   d}t tj}dD ]E}|| t|  }| rN| D ]"}| r=z
|  |d7 }W q ty<   t	j
d|dd Y qw qz|  W q	 tyM   Y q	w q	|S )zmDelete all storage files for a user across all subdirectories.

    Returns the number of files deleted.
    r   )r*   r<   facesr?      zFailed to delete: %sTrE   )r   r   r0   r/   is_diriterdiris_filerG   rJ   rH   rK   rmdir)r(   countbasesubuser_dirfr$   r$   r%   delete_user_storageq   s*   
rY      max_sizec           	      C   s   t t| }|jdv s|jdkr2d|jv r2|d}t d|jd}|j	||
 d d |}n
|jdkr<|d}|j\}}t|||kr`|t|| }|t|| t|| ft j}t }|j|d	d
d | S )uN  Resize image if larger than max_size on any side. Returns JPEG bytes.

    RGBA inputs (e.g., pre-segmented person PNGs) are composited onto white
    before the JPEG encode — a plain ``convert("RGB")`` would drop alpha onto
    a black canvas, which downstream image models then preserve as a black
    backdrop in the result.
    )RGBALAPtransparencyr\   RGB)   ra   ra   )maskJPEGZ   )formatquality)r   openioBytesIOmoderI   convertnewsizepaster   maxresizeintLANCZOSsavegetvalue)	r'   r[   imgrgbabgwhratiobufr$   r$   r%   resize_image_if_needed   s   



"r}      c                 C   s   t t| }|j\}}t|||kr| S |t|| }t|| t|| f}||t j}t }|j	|ddd |
 S )a+  Resize PNG if larger than max_size on any side, preserving transparency.

    Returns the original bytes if no resize needed; otherwise returns re-encoded
    PNG bytes with the alpha channel intact (required for ghost mannequin images
    so the model can distinguish garment from background).
    PNGT)rf   optimize)r   rh   ri   rj   rn   rp   rr   rq   rs   rt   ru   )r'   r[   rv   ry   rz   r{   new_sizer|   r$   r$   r%   resize_png_if_needed   s   
r   )r   )rZ   )r~   )__doc__ri   loggingr2   pathlibr   urllib.parser   r   PILr   
app.configr   	getLogger__name__rH   r   r/   floatbytesr&   UUIDr:   r>   r@   rB   rM   rr   rY   r}   r   r$   r$   r$   r%   <module>   s(    
'



