File size: 9,817 Bytes
f7e620e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
"""
Image Visualization Module for EmotionMirror application.

This module contains functions for visualizing images with interactive controls
such as zoom, pan, and reset functionality.
"""
import streamlit as st
import numpy as np
from PIL import Image
import io
import logging
import base64
from typing import Dict, Any, Tuple, Optional

logger = logging.getLogger(__name__)

def get_image_download_link(img, filename="emotion_mirror_image.png", text="Download Image"):
    """
    Generate a download link for an image.
    
    Args:
        img: PIL Image or numpy array
        filename: Name of the file to download
        text: Text to display for the download link
        
    Returns:
        HTML string with download link
    """
    try:
        # Convert numpy array to PIL Image if necessary
        if isinstance(img, np.ndarray):
            img_pil = Image.fromarray(img)
        else:
            img_pil = img
            
        # Create a byte buffer
        buffered = io.BytesIO()
        img_pil.save(buffered, format="PNG")
        
        # Encode the bytes to base64
        img_str = base64.b64encode(buffered.getvalue()).decode()
        
        # Create download link HTML
        href = f'<a href="data:file/png;base64,{img_str}" download="{filename}">{text}</a>'
        return href
    except Exception as e:
        logger.error(f"Error creating image download link: {e}")
        return None

def display_image_with_controls(image, 
                              title: str = "Image Viewer", 
                              allow_zoom: bool = True,
                              allow_download: bool = True) -> Dict[str, Any]:
    """
    Display an image with zoom, pan and reset controls.
    
    Args:
        image: PIL Image or numpy array to display
        title: Title to display above the image
        allow_zoom: Whether to show zoom controls
        allow_download: Whether to show download option
        
    Returns:
        Dict containing the status and any relevant info
    """
    try:
        # Ensure image is not None
        if image is None:
            return {"success": False, "message": "No image provided"}
            
        # Convert numpy array to PIL Image if necessary
        if isinstance(image, np.ndarray):
            pil_image = Image.fromarray(image)
        else:
            pil_image = image
        
        # Store original image dimensions
        original_width, original_height = pil_image.size
        
        # Create container for image display
        st.subheader(title)
        
        # Image controls in columns for better layout
        col1, col2, col3 = st.columns([1, 2, 1])
        
        # Zoom functionality
        zoom_factor = 1.0
        if allow_zoom:
            with col1:
                zoom_factor = st.slider(
                    "Zoom", 
                    min_value=0.5, 
                    max_value=2.0, 
                    value=1.0, 
                    step=0.1,
                    help="Adjust the zoom level of the image"
                )
        
        # Reset button in the third column
        with col3:
            reset_pressed = st.button("Reset View", help="Reset zoom and view settings")
            if reset_pressed:
                zoom_factor = 1.0
                st.session_state.zoom_factor = 1.0  # Store in session state
                
        # Apply zoom if needed
        if zoom_factor != 1.0:
            # Calculate new dimensions
            new_width = int(original_width * zoom_factor)
            new_height = int(original_height * zoom_factor)
            
            # Resize the image
            resized_image = pil_image.resize((new_width, new_height), Image.LANCZOS)
        else:
            resized_image = pil_image
        
        # Display the image
        st.image(resized_image, use_column_width=True)
        
        # Add download option
        if allow_download:
            download_link = get_image_download_link(pil_image)
            if download_link:
                st.markdown(download_link, unsafe_allow_html=True)
                
        return {
            "success": True, 
            "zoom_factor": zoom_factor,
            "image_dimensions": (original_width, original_height),
            "displayed_dimensions": resized_image.size
        }
        
    except Exception as e:
        logger.error(f"Error displaying image with controls: {e}")
        return {"success": False, "message": str(e)}

def handle_image_viewer(image_data, 
                      title: str = "Image Viewer", 
                      description: str = None,
                      allow_zoom: bool = True, 
                      allow_reset: bool = True,
                      allow_download: bool = True) -> Dict[str, Any]:
    """
    Complete image viewer with all controls and options.
    
    Args:
        image_data: PIL Image or numpy array
        title: Title for the image viewer
        description: Optional description text
        allow_zoom: Whether to include zoom controls
        allow_reset: Whether to include reset button
        allow_download: Whether to include download option
        
    Returns:
        Dict containing status and control information
    """
    st.subheader(title)
    
    if description:
        st.markdown(description)
    
    # Create container for the viewer
    viewer_container = st.container()
    
    with viewer_container:
        # Create a two-column layout for controls and image
        control_col, image_col = st.columns([1, 3])
        
        with control_col:
            st.markdown("### Controls")
            
            # Zoom controls
            zoom_factor = 1.0
            if allow_zoom:
                zoom_factor = st.slider(
                    "Zoom", 
                    min_value=0.5, 
                    max_value=3.0, 
                    value=1.0, 
                    step=0.1,
                    help="Adjust the zoom level"
                )
            
            # Reset button
            if allow_reset:
                if st.button("Reset View", key="reset_view"):
                    zoom_factor = 1.0
                    # Reset any other relevant state
            
            # Add some spacing
            st.markdown("<br>", unsafe_allow_html=True)
            
            # Download option
            if allow_download and image_data is not None:
                download_link = get_image_download_link(image_data)
                if download_link:
                    st.markdown("### Download")
                    st.markdown(download_link, unsafe_allow_html=True)
        
        with image_col:
            if image_data is not None:
                # Process the image based on controls
                try:
                    # Convert to PIL if numpy array
                    if isinstance(image_data, np.ndarray):
                        pil_image = Image.fromarray(image_data)
                    else:
                        pil_image = image_data
                    
                    # Apply zoom if needed
                    if zoom_factor != 1.0:
                        original_width, original_height = pil_image.size
                        new_width = int(original_width * zoom_factor)
                        new_height = int(original_height * zoom_factor)
                        displayed_image = pil_image.resize((new_width, new_height), Image.LANCZOS)
                    else:
                        displayed_image = pil_image
                        
                    # Display the image
                    st.image(displayed_image, use_column_width=True)
                    
                    return {
                        "success": True,
                        "zoom_factor": zoom_factor,
                        "image_displayed": True
                    }
                    
                except Exception as e:
                    st.error(f"Error displaying image: {str(e)}")
                    logger.error(f"Error in image viewer: {e}")
                    return {"success": False, "message": str(e)}
            else:
                st.info("No image to display. Please upload an image first.")
                return {"success": False, "message": "No image data provided"}

def create_image_tabs(original_image, processed_image=None):
    """
    Create tabs to display original and processed images side by side.
    
    Args:
        original_image: The original image (PIL or numpy array)
        processed_image: The processed image (PIL or numpy array), optional
        
    Returns:
        Dict with status information
    """
    # Create tabs
    if processed_image is not None:
        tab1, tab2 = st.tabs(["Original Image", "Processed Image"])
        
        with tab1:
            result1 = display_image_with_controls(
                original_image, 
                title="Original Image", 
                allow_zoom=True,
                allow_download=True
            )
            
        with tab2:
            result2 = display_image_with_controls(
                processed_image, 
                title="Processed Image", 
                allow_zoom=True,
                allow_download=True
            )
            
        return {
            "success": result1.get("success", False) and result2.get("success", False),
            "tabs_created": True
        }
    else:
        # Only original image available
        result = display_image_with_controls(
            original_image, 
            title="Uploaded Image", 
            allow_zoom=True,
            allow_download=True
        )
        
        return {
            "success": result.get("success", False),
            "tabs_created": False
        }