File size: 5,733 Bytes
576a588
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
# ui_components.py
"""
Defines functions for creating distinct UI sections of the Streamlit application.
"""

import streamlit as st
from typing import Tuple, Dict, Any, Optional
from PIL import Image
import io

# Constants
MAX_PREVIEW_HEIGHT = 10000 # Maximum height in pixels for full-size preview

def render_sidebar() -> Tuple[int, str]:
    """
    Renders the sidebar UI elements for settings.

    Returns
    -------
    Tuple[int, str]
        A tuple containing:
        - dpi (int): The selected resolution in DPI.
        - output_format (str): The selected output format ('PNG' or 'JPG').
    """
    with st.sidebar:
        st.header("โš™๏ธ Settings")
        # DPI Slider
        dpi = st.slider(
            "Resolution (DPI)",
            min_value=72,
            max_value=600,
            value=300,
            step=1,
            help="Dots Per Inch. Higher DPI means better quality but larger file size and longer processing time."
        )
        # Output Format Radio Buttons
        output_format = st.radio(
            "Output Format",
            ["PNG", "JPG"],
            index=0, # Default to PNG
            help="PNG offers lossless quality (larger file). JPG uses lossy compression (smaller file)."
        )

        st.write("---")
        st.write("### About")
        st.info(
            "This app converts multi-page PDFs into a single, vertically stitched image file. "
            "Useful for sharing or archiving documents as images."
        )
        st.write("Made with โค๏ธ using [Streamlit](https://streamlit.io) & [PyMuPDF](https://pymupdf.readthedocs.io/en/latest/)")
        st.write("Tim might be a ๐Ÿง™")
        # A little fun :)
        # st.write("Tim might be a ๐Ÿง™") # Uncomment if desired

    return dpi, output_format

def display_file_details(uploaded_file: st.runtime.uploaded_file_manager.UploadedFile) -> None:
    """
    Displays details of the uploaded file.

    Parameters
    ----------
    uploaded_file : st.runtime.uploaded_file_manager.UploadedFile
        The file uploaded by the user via st.file_uploader.
    """
    file_details = {
        "Filename": uploaded_file.name,
        "Type": uploaded_file.type,
        "Size": f"{uploaded_file.size / (1024*1024):.2f} MB" # Show size in MB
    }
    st.write("### File Details")
    # Use columns for better layout
    col1, col2 = st.columns(2)
    with col1:
        st.write(f"**Filename:**")
        st.write(f"**Type:**")
        st.write(f"**Size:**")
    with col2:
        st.write(f"{file_details['Filename']}")
        st.write(f"{file_details['Type']}")
        st.write(f"{file_details['Size']}")


def display_results(
    img_buffer: io.BytesIO,
    output_filename: str,
    output_format: str,
    processing_time: float
) -> None:
    """
    Displays the conversion results: success message, download button, and image preview.

    Parameters
    ----------
    img_buffer : io.BytesIO
        The buffer containing the generated image data.
    output_filename : str
        The suggested filename for the downloaded image.
    output_format : str
        The format of the output image ('PNG' or 'JPG').
    processing_time : float
        The time taken for the conversion process in seconds.
    """
    st.success(f"โœ… Conversion completed in {processing_time:.2f} seconds!")

    # Determine MIME type based on format
    mime_type = f"image/{output_format.lower()}"

    # Provide download button
    st.download_button(
        label=f"โฌ‡๏ธ Download {output_format} Image",
        data=img_buffer,
        file_name=output_filename,
        mime=mime_type
    )

    # Image preview section
    st.write("---")
    st.write("### ๐Ÿ–ผ๏ธ Image Preview")
    try:
        # Open image from buffer for preview
        img = Image.open(img_buffer)
        width, height = img.size
        st.write(f"**Image dimensions:** {width}x{height} pixels")

        # Warn and scale down preview if the image is excessively tall
        if height > MAX_PREVIEW_HEIGHT:
            st.warning(f"โš ๏ธ Image is very tall ({height}px). Preview is scaled down.")
            # Calculate width based on a max preview width (e.g., 800px) to maintain aspect ratio
            preview_width = min(width, 800)
            st.image(img, caption=f"Scaled Preview of {output_filename}", width=preview_width)
        else:
            # Show image using Streamlit's default width handling or a fixed width
            st.image(img, caption=f"Preview of {output_filename}", use_column_width='auto')

    except Exception as e:
        st.error(f"Could not display image preview: {e}")
        st.warning("The image file might be corrupted or too large for preview.")


def render_initial_info() -> None:
    """
    Displays the initial instructions and placeholder content when no file is uploaded.
    """
    st.info("๐Ÿ‘† Upload a PDF file using the sidebar to get started.")
    st.write("---")
    # Placeholder or example section (optional)
    # st.write("### Example Output Structure")
    # st.image("https://via.placeholder.com/600x800/ccc/888?text=Page+1", caption="Page 1")
    # st.image("https://via.placeholder.com/600x800/eee/777?text=Page+2", caption="Page 2")
    # st.caption("...(Pages are stitched vertically)")

def display_installation_info() -> None:
    """Displays the installation requirements and run command."""
    st.write("---")
    with st.expander("๐Ÿ› ๏ธ Installation & Usage"):
        st.code("""
# 1. Install required libraries
pip install streamlit Pillow PyMuPDF

# 2. Save the code files (app.py, pdf_processor.py, ui_components.py)
#    in the same directory.

# 3. Run the Streamlit application
streamlit run app.py
        """, language="bash")