
    7ih              	          d dl mZmZmZ d dlm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 d dlmZ d dlmZ d d	lmZ d d
lmZmZmZmZ  ee      Z e       Zej6                  Zej8                  Zej:                  Zej:                  Zej>                  Z defdZ!defdZ"defdZ#defdZ$defdZ%dee	   ddfdZ&e fdede	de'de	fdZ(dej
                  de'de'dej
                  fdZ)defdZ*y)    )
UploadFileHTTPExceptionstatus)Image)BytesIO)PathN)Optional)PSDImage)setup_logger)get_settings)ERR_IMG_WIDTH_HEIGHTERR_FILE_TOO_LARGEERR_PSD_EXTERR_OVERLAY_EXTfilec                    | j                   j                         }t        j                  t	        |            }|j
                  j                         }ddg}||vrt        ddj                  |       d      t        |      t        kD  rt        dt        dz  dz  dd	      | j                   j                  d
       y )NjpegpngInvalid image format. Only ,  are allowed.(File is too large. Maximum file size is    .2fMB.r   )r   readr   openr   formatlower
ValueErrorjoinlenMAX_PROFILE_IMG_SIZEseekr   
image_dataimageimage_formatallowed_formatss        A/var/www/html/story-book/Story-Book-python-api/app/utils/image.pyvalidate_profile_imager+      s    !JJJwz*+E<<%%'LuoO?*6tyy7Q6RR_`aa
:--CDX[_D_bfDfgjCkknoppIINN1    c                    | j                   j                         }t        j                  t	        |            }|j
                  j                         }g d}||vrt        ddj                  |       d      t        |      t        kD  rt        dt        dz  dz  dd      | j                   j                  d	       y )
N)psdr   jpgr   r   r   r   r   r   r   r   r   )r   r   r   r   r   r   r   r    r!   r"   MAX_PRODUCT_IMG_SIZEr$   r%   s        r*   validate_product_imagesr1   )   s    !JJJwz*+E<<%%'L3O?*6tyy7Q6RR_`aa
:--CDX[_D_bfDfgjCkknoppIINN1r,   c                     dg}| j                   j                  d      d   j                         }||vrt        t              | j
                  j                  d       y )Nr.   .r   )filenamesplitr   r    r   r   r$   r   allowedexts      r*   validate_base_filer:   4   sN    gG
--

c
"2
&
,
,
.C
'%%IINN1r,   c                     g d}| j                   j                  d      d   j                         }||vrt        t              | j
                  j                  d       y )Nr   r/   r   r3   r4   r   )r5   r6   r   r    r   r   r$   r7   s      r*   validate_overlay_filer=   ;   sL    $G
--

c
"2
&
,
,
.C
'))IINN1r,   c                     g d}| j                   j                  d      d   j                         }||vrt        d      | j                  j                  d       y )Nr<   r3   r4   z/Invalid logo/stamp image. Must be PNG/JPG only.r   )r5   r6   r   r    r   r$   r7   s      r*   validate_logo_filer?   B   sM    $G
--

c
"2
&
,
,
.C
'JKKIINN1r,   pathreturnc                     | sy	 | j                         r| j                          yy# t        $ r t        j	                  d|        Y yw xY w)aV  
    Safely delete a file from disk.

    This helper removes files while silently ignoring missing paths
    and logging any unexpected exceptions.

    Args:
        path (Optional[Path]): Path to delete. No action if None.
    Notes:
        - Used for cleanup during partial failures.
        - Never raises exceptions to the caller.
    NzFailed to delete file: %s)existsunlink	Exceptionlogger	exception)r@   s    r*   safe_deleterH   I   sF     <;;=KKM  <4d;<s    ' A	A	upload	directory	max_bytesc                   K   t        |        t        | j                  xs d      j                  }t	        j
                         j                   d| }||z  }d}	 |j                  d      5 }	 | j                  t               d{   }|sn_|j                  |       |t        |      z  }||kD  r:|j                          t        |       t        t        j                   t"              	 ddd       	 | j                          d{    |S 7 # 1 sw Y   &xY w7 # t$        $ r Y |S w xY w# 	 | j                          d{  7   w # t$        $ r Y w w xY wxY ww)aq  
    Save an uploaded file to disk using streaming I/O.

    This prevents loading large files fully into RAM, making it safe
    for high-volume uploads.

    Args:
        upload (UploadFile): File uploaded by the client.
        directory (Path): Directory where the file should be saved.
        max_bytes (int): Maximum allowed upload size in bytes.
    Returns:
        Path: Full path to the saved file.
    Raises:
        HTTPException: 413 if the file exceeds the maximum allowed size.
    Notes:
        - Uses CHUNK_SIZE to read file incrementally.
        - Filename is sanitized and made unique using UUID.
    rI   _r   wbN)status_codedetail)r1   r   r5   nameuuiduuid4hexr   r   
CHUNK_SIZEwriter"   closerH   r   r   !HTTP_413_REQUEST_ENTITY_TOO_LARGEr   rE   )	rI   rJ   rK   r5   unique_filename	file_pathbytes_writtenbufferchunks	            r*   save_upload_file_streamedr^   ^   sE    . F#FOO/x055H))*!H:6OO+IM^^D!V$kk*55U#U+ 9,LLN	*'F4\4\ewxx  	 "	,,.   # 6 "! ! 			,,.   		s   AE D2 -DDA&D/D2 8D" D D" E DDD2  D" "	D/+E .D//E 2E4EE
EE	EEEEE imgtarget_wtarget_hc                 \   | j                   \  }}|dk(  s|dk(  rt        t              t        ||z  ||z        }t	        ||z        t	        ||z        }}| j                  ||ft        j                  j                        }||z
  dz  }	||z
  dz  }
|j                  |	|
|	|z   |
|z   f      S )a-  
    Resize an image while maintaining aspect ratio, then center-crop it.

    Ensures the output completely fills the target size
    without letterboxing.

    Args:
        img (Image.Image): Input PIL image.
        target_w (int): Output width.
        target_h (int): Output height.
    Returns:
        Image.Image: Resized + cropped PIL image.
    Raises:
        ValueError: If image has zero width/height.
    Notes:
        - Uses LANCZOS for high-quality resampling.
        - Commonly used for fitting overlay images into PSD placeholders.
    r      )
sizer    r   maxintresizer   
ResamplingLANCZOScrop)r_   r`   ra   owohscalenew_wnew_himg_resizedleftuppers              r*   resize_and_crop_to_fillrs      s    & XXFB	Qw"'-..2x"}-ErEz?CU
O5E**eU^U-=-=-E-EFKH"DX!#ET5$/58;KLMMr,   r.   c           	      d   	 | j                         D cg c]  }|t        |dd      f }}|D ]  \  }}	 d|_         	 d|_        | j	                         j                  d      }|j                         d   }|D ]  \  }}	 ||_         |j                  |k7  r*|j                  |t        j                  j                        }|S c c}w # t        $ r Y w xY w# t        $ r Y w xY w# t        $ r Y yw xY w# t        $ r/ t        j                  d       t        j                  d|d      cY S w xY w)	a\  
    Render the full-size alpha mask of a given PSD layer.

    This isolates a single layer by temporarily hiding all others,
    composites the PSD, extracts the alpha channel, and restores visibility.

    Args:
        psd (PSDImage): Loaded PSD object.
        target_layer: PSD layer whose alpha mask is required.
        canvas_size (tuple): Target (width, height) output resolution.
    Returns:
        Image.Image: Grayscale ("L") alpha mask for the layer.
    Notes:
        - Always returns an image even if rendering fails.
        - Non-blocking, used heavily during overlay placement.
    visibleTFRGBAr4   z"Failed to compute layer alpha maskL   )descendantsgetattrru   rE   	compositeconvertr6   rd   rg   r   rh   ri   rF   rG   new)	r.   target_layercanvas_sizelayer	vis_staterM   renderedalphaoriginal_viss	            r*   render_layer_alpha_fullsizer      sN   "&0 *
* GE9d34* 	 
 "HE1 % "	#'L  ==?**62 $ $-E< , $- ::$LLe.>.>.F.FGEA
    		    0=>yyk3//0s   C7 C
C7 C
C7 C :C7 C(<C7 C7 
	CC7 CC7 	C%"C7 $C%%C7 (	C41C7 3C44C7 75D/.D/)+fastapir   r   r   PILr   ior   pathlibr   rR   typingr	   	psd_toolsr
   app.core.loggingr   app.core.configr   app.core.constantsr   r   r   r   __name__rF   settingsrU   r#   r0   MAX_PSD_SIZEMAX_PRODUCT_UPLOAD_BYTESMAX_UPLOAD_BYTESr+   r1   r:   r=   r?   rH   rf   r^   rs   r    r,   r*   <module>r      s<   5 5        ) (  
h	>   
44 ,,44 44 	 		* 	Z 
 Z <htn < <0 &333 3 
	3jN N Ns Nu{{ NB70X 70r,   