Spaces:
Sleeping
Sleeping
| # 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") | |