├── PUT YOUR IMAGES HERE
└── .gitkeep
├── requirements.txt
├── assets
├── icon.ico
├── icon.png
└── screenshot.png
├── .gitignore
├── kindle_screensaver.spec
├── LICENSE
├── README.md
└── kindle-screensaver-converter-gui.py
/PUT YOUR IMAGES HERE/.gitkeep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/requirements.txt:
--------------------------------------------------------------------------------
1 | Pillow
2 | PyQt6
3 | pyqtdarktheme
4 | numpy
--------------------------------------------------------------------------------
/assets/icon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/neura-neura/kindle-screensaver-converter-gui/HEAD/assets/icon.ico
--------------------------------------------------------------------------------
/assets/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/neura-neura/kindle-screensaver-converter-gui/HEAD/assets/icon.png
--------------------------------------------------------------------------------
/assets/screenshot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/neura-neura/kindle-screensaver-converter-gui/HEAD/assets/screenshot.png
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | venv/
2 | converted_screensavers/
3 | PUT YOUR IMAGES HERE/*
4 | !PUT YOUR IMAGES HERE/.gitkeep
5 | dist/
6 | build/
--------------------------------------------------------------------------------
/kindle_screensaver.spec:
--------------------------------------------------------------------------------
1 | # kindle_screensaver.spec
2 | block_cipher = None
3 |
4 | a = Analysis(['kindle-screensaver-converter-gui.py'],
5 | pathex=['.'],
6 | binaries=[],
7 | datas=[('assets/icon.ico', 'assets')], # Incluir assets
8 | hiddenimports=[],
9 | hookspath=[],
10 | runtime_hooks=[],
11 | excludes=[],
12 | win_no_prefer_redirects=False,
13 | win_private_assemblies=False,
14 | cipher=block_cipher,
15 | noarchive=False)
16 |
17 | pyz = PYZ(a.pure, a.zipped_data,
18 | cipher=block_cipher)
19 |
20 | exe = EXE(pyz,
21 | a.scripts,
22 | a.binaries,
23 | a.zipfiles,
24 | a.datas,
25 | [],
26 | name='KindleScreensaverConverter',
27 | debug=False,
28 | bootloader_ignore_signals=False,
29 | strip=False,
30 | upx=True,
31 | upx_exclude=[],
32 | runtime_tmpdir=None,
33 | console=False,
34 | icon='assets/icon.ico')
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2025 Kindle Screensaver Converter GUI
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |

3 |
4 |
5 | Kindle Screensaver Converter GUI
6 |
7 |
8 | This project provides a graphical user interface (GUI) for converting images into Kindle-compatible screensavers, simplifying the process by leveraging the core functionality of the
original Kindle Screensaver Converter script. The GUI allows users to define target dimensions, resolution, and bit depth while visually interacting with their image collection. A compiled version for Windows is included in the Releases section.
9 |
10 |
11 |
12 |

13 |
14 |
15 | ## Features
16 |
17 | - **User-Friendly GUI:** Intuitive interface for managing the screensaver conversion process.
18 | - **Dimension Control:** Set custom target height and width in pixels.
19 | - **Resolution Adjustment:** Define horizontal and vertical resolution (DPI).
20 | - **Bit Depth Configuration:** Customize the bit depth of the output.
21 | - **Smart Cropping:** Automatically detects and retains the most visually prominent area of each image.
22 | - **Grayscale with Contrast Enhancement:** Applies grayscale and enhances contrast for better visual impact.
23 | - **Batch Processing:** Converts multiple images at once.
24 | - **Dark Theme:** Integrated support for a visually appealing dark mode.
25 | - **Output Folder:** Processed images are saved in a `converted_screensavers` folder, which is automatically created in the program's directory if it does not already exist.
26 | - **Executable Compilation:** Includes a `kindle_screensaver.spec` file for compiling the program into an executable.
27 |
28 | ## Requirements
29 |
30 | - Python 3.x
31 | - Dependencies listed in `requirements.txt`
32 | - Pillow
33 | - PyQt6
34 | - pyqtdarktheme
35 | - numpy
36 |
37 | ## Installation
38 |
39 | ### Setting up the Environment
40 |
41 | 1. **Clone the Repository:**
42 | ```bash
43 | git clone
44 | cd
45 | ```
46 |
47 | 2. **Create a Virtual Environment:**
48 | ```bash
49 | python -m venv venv
50 | ```
51 |
52 | 3. **Activate the Virtual Environment:**
53 | - On **Windows (CMD):**
54 | ```bash
55 | venv\Scripts\activate
56 | ```
57 | - On **Windows (PowerShell):**
58 | ```bash
59 | .\venv\Scripts\Activate.ps1
60 | ```
61 | - On **macOS/Linux:**
62 | ```bash
63 | source venv/bin/activate
64 | ```
65 |
66 | 4. **Install Dependencies:**
67 | ```bash
68 | pip install -r requirements.txt
69 | ```
70 |
71 | ## Usage
72 |
73 | ### Running the GUI
74 |
75 | 1. **Prepare Input Images:** Place the images you want to convert in any folder on your system. Alternatively, you can place them in the `PUT YOUR IMAGES HERE` folder if you want the program to load them automatically at startup (the program reads this folder when it starts).
76 |
77 | >If you have a compiled version of the program and want it to load the images automatically at startup, create a folder named `PUT YOUR IMAGES HERE` in the same directory as the program.
78 | 2. **Launch the GUI:**
79 | ```bash
80 | python kindle-screensaver-converter-gui.py
81 | ```
82 | 3. **Select Input Folder:** Click the `Select Input Folder` button and choose the folder containing your images.
83 | 4. **Set Conversion Parameters:** Use the provided fields to define:
84 | - Target height and width in pixels.
85 | - Horizontal and vertical DPI.
86 | - Bit depth.
87 | 5. **Start Conversion:** Click `Convert Images` to process your images.
88 | 6. **Check Output:** Converted images will be saved in a `converted_screensavers` folder in the program's directory.
89 |
90 | ### Compiling the Program
91 |
92 | The project includes a `kindle_screensaver.spec` file for compiling the program into an executable for your desired operating system using PyInstaller.
93 |
94 | 1. **Install PyInstaller:**
95 | ```bash
96 | pip install pyinstaller
97 | ```
98 |
99 | 2. **Compile the Program:**
100 | ```bash
101 | pyinstaller kindle_screensaver.spec
102 | ```
103 |
104 | 3. The compiled executable will be available in the `dist` folder.
105 |
106 | ### Precompiled Version
107 |
108 | A precompiled executable for Windows is available in the Releases section of this repository. Download and run it directly without needing Python or dependencies.
109 |
110 | ## Example Workflow
111 |
112 | 1. Place your images in a folder.
113 | 2. Run the GUI and select the folder.
114 | 3. Define target dimensions, DPI, and bit depth as needed.
115 | 4. Start the conversion process.
116 | 5. Access the converted images in the `converted_screensavers` folder in the program's directory .
117 |
118 | ## Troubleshooting
119 |
120 | - Ensure that the input folder exists and contains valid image files.
121 | - Verify that Python and the required libraries are installed.
122 | - Check your file permissions for the working directory.
123 | - For compiled versions, ensure compatibility with your operating system.
124 |
125 | ## Releases
126 |
127 | - Precompiled Windows executable available in the Releases section.
128 | - Source code for all platforms is provided.
129 |
130 | ## License
131 |
132 | This project is licensed under the MIT License. See the [LICENSE](./LICENSE) file for details.
133 |
134 |
--------------------------------------------------------------------------------
/kindle-screensaver-converter-gui.py:
--------------------------------------------------------------------------------
1 | import sys
2 | import os
3 | from PyQt6.QtWidgets import (QApplication, QMainWindow, QWidget, QVBoxLayout,
4 | QHBoxLayout, QLabel, QSpinBox, QPushButton, QFileDialog, QScrollArea,
5 | QFrame, QProgressBar, QMessageBox, QGridLayout)
6 | from PyQt6.QtCore import Qt, QThread, pyqtSignal
7 | from PyQt6.QtGui import QPixmap, QImage, QFont, QIcon
8 | from PIL import Image, ImageEnhance
9 | import qdarktheme
10 |
11 | class ImageProcessor(QThread):
12 | progress = pyqtSignal(int)
13 | finished = pyqtSignal()
14 |
15 | def __init__(self, params, input_folder):
16 | super().__init__()
17 | self.params = params
18 | self.input_folder = input_folder
19 |
20 | def enhance_contrast_grayscale(self, image):
21 | image = image.convert("L")
22 | enhancer = ImageEnhance.Contrast(image)
23 | return enhancer.enhance(2.0)
24 |
25 | def adjust_bit_depth(self, image, bit_depth):
26 | if bit_depth == 8:
27 | return image # 8-bit is the default value for grayscale images.
28 |
29 | # Calculate number of gray levels based on bit depth
30 | levels = 2 ** bit_depth - 1
31 |
32 | # Convert to array for pixel manipulation
33 | import numpy as np
34 | img_array = np.array(image)
35 |
36 | # Normalize and adjust to new bit range
37 | normalized = img_array / 255.0 # Normalize to range 0-1
38 | adjusted = np.round(normalized * levels) * (255 / levels) # Adjust to new range and scale back to 8 bits
39 |
40 | # Convert back to PIL image
41 | return Image.fromarray(adjusted.astype(np.uint8))
42 |
43 | def run(self):
44 | output_folder = "converted_screensavers"
45 | os.makedirs(output_folder, exist_ok=True)
46 |
47 | images = [f for f in os.listdir(self.input_folder)
48 | if f.lower().endswith((".jpg", ".jpeg", ".png"))]
49 |
50 | for idx, image_name in enumerate(images):
51 | image_path = os.path.join(self.input_folder, image_name)
52 | with Image.open(image_path) as img:
53 | # Convert and resize
54 | img = img.convert("RGB")
55 | scale_factor = max(self.params['width'] / img.width,
56 | self.params['height'] / img.height)
57 | new_width = int(img.width * scale_factor)
58 | new_height = int(img.height * scale_factor)
59 | img = img.resize((new_width, new_height), Image.LANCZOS)
60 |
61 | # Crop
62 | left = (img.width - self.params['width']) // 2
63 | top = (img.height - self.params['height']) // 2
64 | right = left + self.params['width']
65 | bottom = top + self.params['height']
66 | img = img.crop((left, top, right, bottom))
67 |
68 | # Convert to grayscale and improve contrast
69 | img = self.enhance_contrast_grayscale(img)
70 |
71 | # Adjust bit depth
72 | img = self.adjust_bit_depth(img, self.params['bit_depth'])
73 |
74 | # Save
75 | output_name = f"bg_ss{str(idx + 1).zfill(2)}.png"
76 | output_path = os.path.join(output_folder, output_name)
77 | img.save(output_path, "PNG",
78 | dpi=(self.params['dpi_x'], self.params['dpi_y']))
79 |
80 | self.progress.emit(int((idx + 1) / len(images) * 100))
81 |
82 | self.finished.emit()
83 |
84 | class ImageThumbnail(QFrame):
85 | def __init__(self, image_path):
86 | super().__init__()
87 | self.setFrameStyle(QFrame.Shape.Box | QFrame.Shadow.Raised)
88 | self.setLineWidth(1)
89 | layout = QVBoxLayout()
90 |
91 | # Image
92 | pixmap = QPixmap(image_path)
93 | scaled_pixmap = pixmap.scaled(150, 150, Qt.AspectRatioMode.KeepAspectRatio,
94 | Qt.TransformationMode.SmoothTransformation)
95 | image_label = QLabel()
96 | image_label.setPixmap(scaled_pixmap)
97 | image_label.setAlignment(Qt.AlignmentFlag.AlignCenter)
98 |
99 | # Filename
100 | filename_label = QLabel(os.path.basename(image_path))
101 | filename_label.setAlignment(Qt.AlignmentFlag.AlignCenter)
102 | filename_label.setWordWrap(True)
103 |
104 | layout.addWidget(image_label)
105 | layout.addWidget(filename_label)
106 | self.setLayout(layout)
107 |
108 | class KindleConverterGUI(QMainWindow):
109 | def __init__(self):
110 | super().__init__()
111 | icon_path = os.path.join(os.path.dirname(__file__), 'assets', 'icon.ico')
112 | self.setWindowIcon(QIcon(icon_path))
113 | self.input_folder = "PUT YOUR IMAGES HERE"
114 | self.initUI()
115 |
116 | def initUI(self):
117 | self.setWindowTitle('Kindle Screensaver Converter')
118 | self.setMinimumSize(800, 600)
119 |
120 | # Main widget and layout
121 | main_widget = QWidget()
122 | self.setCentralWidget(main_widget)
123 | layout = QVBoxLayout(main_widget)
124 |
125 | # Title
126 | title_label = QLabel("Kindle Screensaver Converter")
127 | title_label.setFont(QFont('Arial', 16, QFont.Weight.Bold))
128 | title_label.setAlignment(Qt.AlignmentFlag.AlignCenter)
129 | layout.addWidget(title_label)
130 |
131 | # Parameters section
132 | params_frame = QFrame()
133 | params_frame.setFrameStyle(QFrame.Shape.Box | QFrame.Shadow.Raised)
134 | params_layout = QGridLayout(params_frame)
135 |
136 | # Parameter input fields
137 | self.params = {}
138 | param_configs = {
139 | 'height': ('Target Height (pixels):', 800, 1, 2000),
140 | 'width': ('Target Width (pixels):', 600, 1, 2000),
141 | 'dpi_x': ('Horizontal DPI:', 96, 1, 600),
142 | 'dpi_y': ('Vertical DPI:', 96, 1, 600),
143 | 'bit_depth': ('Bit Depth:', 8, 1, 32)
144 | }
145 |
146 | for i, (key, (label, default, min_val, max_val)) in enumerate(param_configs.items()):
147 | params_layout.addWidget(QLabel(label), i, 0)
148 | spinbox = QSpinBox()
149 | spinbox.setRange(min_val, max_val)
150 | spinbox.setValue(default)
151 | self.params[key] = spinbox
152 | params_layout.addWidget(spinbox, i, 1)
153 |
154 | layout.addWidget(params_frame)
155 |
156 | # Image preview section
157 | self.preview_area = QScrollArea()
158 | self.preview_widget = QWidget()
159 | self.preview_layout = QGridLayout(self.preview_widget)
160 | self.preview_area.setWidget(self.preview_widget)
161 | self.preview_area.setWidgetResizable(True)
162 | layout.addWidget(self.preview_area)
163 |
164 | # Progress bar
165 | self.progress_bar = QProgressBar()
166 | self.progress_bar.setVisible(False)
167 | layout.addWidget(self.progress_bar)
168 |
169 | # Buttons
170 | button_layout = QHBoxLayout()
171 |
172 | self.select_folder_btn = QPushButton('Select Input Folder')
173 | self.select_folder_btn.clicked.connect(self.select_input_folder)
174 |
175 | self.convert_btn = QPushButton('Convert Images')
176 | self.convert_btn.clicked.connect(self.start_conversion)
177 |
178 | button_layout.addWidget(self.select_folder_btn)
179 | button_layout.addWidget(self.convert_btn)
180 | layout.addLayout(button_layout)
181 |
182 | # Credits button
183 | self.made_by_neura_btn = QPushButton('Made by neura')
184 | self.made_by_neura_btn.clicked.connect(lambda: os.system('start https://github.com/neura-neura/kindle-screensaver-converter-gui'))
185 | layout.addWidget(self.made_by_neura_btn)
186 |
187 | # Load initial images
188 | self.load_image_previews()
189 |
190 | def load_image_previews(self):
191 | # Clear existing previews
192 | for i in reversed(range(self.preview_layout.count())):
193 | self.preview_layout.itemAt(i).widget().setParent(None)
194 |
195 | if os.path.exists(self.input_folder):
196 | images = [f for f in os.listdir(self.input_folder)
197 | if f.lower().endswith((".jpg", ".jpeg", ".png"))]
198 |
199 | row = 0
200 | col = 0
201 | for image in images:
202 | image_path = os.path.join(self.input_folder, image)
203 | thumbnail = ImageThumbnail(image_path)
204 | self.preview_layout.addWidget(thumbnail, row, col)
205 | col += 1
206 | if col > 3: # 4 thumbnails per row
207 | col = 0
208 | row += 1
209 |
210 | def select_input_folder(self):
211 | folder = QFileDialog.getExistingDirectory(self, "Select Input Folder")
212 | if folder:
213 | self.input_folder = folder
214 | self.load_image_previews()
215 |
216 | def start_conversion(self):
217 | params = {key: spinbox.value() for key, spinbox in self.params.items()}
218 |
219 | self.processor = ImageProcessor(params, self.input_folder)
220 | self.processor.progress.connect(self.update_progress)
221 | self.processor.finished.connect(self.conversion_finished)
222 |
223 | self.progress_bar.setVisible(True)
224 | self.convert_btn.setEnabled(False)
225 | self.select_folder_btn.setEnabled(False)
226 |
227 | self.processor.start()
228 |
229 | def update_progress(self, value):
230 | self.progress_bar.setValue(value)
231 |
232 | def conversion_finished(self):
233 | self.progress_bar.setVisible(False)
234 | self.convert_btn.setEnabled(True)
235 | self.select_folder_btn.setEnabled(True)
236 |
237 | QMessageBox.information(self, "Success",
238 | "Images have been converted successfully!\nCheck the 'converted_screensavers' folder.")
239 |
240 | if __name__ == '__main__':
241 | app = QApplication(sys.argv)
242 | # Aplicar el tema oscuro usando la API correcta
243 | app.setStyleSheet(qdarktheme.load_stylesheet())
244 | window = KindleConverterGUI()
245 | window.show()
246 | sys.exit(app.exec())
--------------------------------------------------------------------------------