pdf_to_single_image / ui_components.py
tsphan's picture
breaks away from single file
576a588
# 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")