def generate_normal_map_from_alpha(img, strength=1.0, blur_radius=1.0, invert=False):
    pass
    """Generate a normal map from an image's alpha channel using height-based algorithm"""
    try:
        pass
        try:
            pass
            from PIL import Image, ImageFilter
        except ImportError:
            pass
            raise ImportError(
                "PIL (Pillow) is required for normal map generation. "
                "Please install it using: pip install Pillow in Blender's Python environment, "
                "or use Blender's bundled Python if available."
            )
        import numpy as np
        
        
        # Extract alpha channel as height map
        if img.mode != 'RGBA':
            pass
            img = img.convert('RGBA')
        
        # Get alpha channel
        alpha_channel = img.split()[3]  # Alpha is the 4th channel
        width, height = alpha_channel.size
        
        
        # Apply blur if specified
        if blur_radius > 0:
            pass
            alpha_channel = alpha_channel.filter(ImageFilter.GaussianBlur(radius=blur_radius))
        
        # Convert to numpy array for gradient calculations
        height_map = np.array(alpha_channel, dtype=np.float32) / 255.0
        
        # Apply strength multiplier
        height_map *= strength
        
        # Calculate gradients using Sobel operators
        # Sobel X kernel for horizontal gradients
        sobel_x = np.array([[-1, 0, 1], [-2, 0, 2], [-1, 0, 1]], dtype=np.float32)
        # Sobel Y kernel for vertical gradients
        sobel_y = np.array([[-1, -2, -1], [0, 0, 0], [1, 2, 1]], dtype=np.float32)
        
        # Pad the height map to handle edges
        padded_height = np.pad(height_map, ((1, 1), (1, 1)), mode='edge')
        
        # Calculate gradients
        grad_x = np.zeros_like(height_map)
        grad_y = np.zeros_like(height_map)
        
        for i in range(height):
            pass
            for j in range(width):
                pass
                # Extract 3x3 neighborhood
                neighborhood = padded_height[i:i+3, j:j+3]
                # Apply Sobel operators
                grad_x[i, j] = np.sum(neighborhood * sobel_x)
                grad_y[i, j] = np.sum(neighborhood * sobel_y)
        
        
        # Convert gradients to normal vectors
        # Normal map RGB values are calculated as:
        # R = (grad_x + 1) * 0.5  -> maps -1,1 to 0,1
        # G = (-grad_y + 1) * 0.5 -> maps -1,1 to 0,1 (Y is flipped for standard normal maps)
        # B = sqrt(1 - grad_x^2 - grad_y^2) -> Z component, always pointing up
        
        # Clamp gradients to reasonable range
        grad_x = np.clip(grad_x, -1, 1)
        grad_y = np.clip(grad_y, -1, 1)
        
        # Apply invert if specified
        if invert:
            pass
            grad_x = -grad_x
            grad_y = -grad_y
        
        # Calculate normal map channels
        # Red channel: X gradient mapped to 0-1
        normal_r = ((grad_x + 1.0) * 0.5 * 255).astype(np.uint8)
        
        # Green channel: Y gradient mapped to 0-1 (flipped)
        normal_g = ((-grad_y + 1.0) * 0.5 * 255).astype(np.uint8)
        
        # Blue channel: Z component (pointing up)
        # Calculate Z from X and Y to maintain unit length
        grad_magnitude_sq = grad_x**2 + grad_y**2
        grad_z = np.sqrt(np.maximum(0, 1.0 - grad_magnitude_sq))
        normal_b = (grad_z * 255).astype(np.uint8)
        
        
        # Create the normal map image
        normal_map = Image.new('RGB', (width, height))
        
        # Combine channels
        for y in range(height):
            pass
            for x in range(width):
                pass
                r = int(normal_r[y, x])
                g = int(normal_g[y, x])
                b = int(normal_b[y, x])
                normal_map.putpixel((x, y), (r, g, b))
        
        return normal_map
        
    except Exception as e:
        pass
        import traceback
        traceback.print_exc()
        return None