File indexing completed on 2025-02-02 04:22:25
0001 """ 0002 SPDX-FileCopyrightText: 2017 Wolthera van Hövell tot Westerflier <griffinvalley@gmail.com> 0003 SPDX-FileCopyrightText: 2018 Ragnar Brynúlfsson <me@ragnarb.com> 0004 0005 This file is part of the Comics Project Management Tools(CPMT). 0006 0007 SPDX-License-Identifier: GPL-3.0-or-later 0008 """ 0009 0010 """ 0011 This is a docker that shows your comic pages. 0012 """ 0013 0014 import os 0015 import sys 0016 import json 0017 import zipfile 0018 from PyQt5.QtGui import QImage, QPainter 0019 from PyQt5.QtWidgets import QDialog, QWidget, QHBoxLayout, QVBoxLayout, QPushButton, QSizePolicy, QDialogButtonBox, QShortcut, QLabel 0020 from PyQt5.QtCore import QSize, Qt 0021 0022 # To run standalon 0023 from PyQt5.QtWidgets import QApplication 0024 0025 0026 class page_viewer(QPushButton): 0027 0028 def __init__(self, parent=None, flags=None): 0029 super(page_viewer, self).__init__(parent) 0030 self.alignment = 'left' 0031 self.image = QImage() 0032 self.setSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.MinimumExpanding) 0033 0034 def align_left(self): 0035 self.alignment = 'left' 0036 0037 def align_right(self): 0038 self.alignment = 'right' 0039 0040 def align_center(self): 0041 self.alignment = 'center' 0042 0043 def set_image(self, image=QImage()): 0044 self.image = image 0045 self.update() 0046 0047 def paintEvent(self, event): 0048 painter = QPainter(self) 0049 previewSize = self.size()*self.devicePixelRatioF() 0050 image = "" 0051 0052 if self.image.width() <= previewSize.width() or self.image.height() <= previewSize.height(): 0053 # pixel art 0054 image = self.image.scaled(previewSize, Qt.KeepAspectRatio, Qt.FastTransformation) 0055 else: 0056 image = self.image.scaled(previewSize, Qt.KeepAspectRatio, Qt.SmoothTransformation) 0057 image.setDevicePixelRatio(self.devicePixelRatioF()) 0058 if self.alignment == 'right': 0059 x_offset = int(self.width() - image.width()/self.devicePixelRatioF()) 0060 elif self.alignment == 'center': 0061 x_offset = int((self.width() - image.width()/self.devicePixelRatioF()) / 2) 0062 else: 0063 x_offset = 0 0064 painter.drawImage(x_offset, 0, image) 0065 0066 def sizeHint(self): 0067 return QSize(256, 256) 0068 0069 0070 class comics_project_page_viewer(QDialog): 0071 pageIndex = 0 0072 spread = True 0073 0074 def __init__(self): 0075 super().__init__() 0076 0077 self.setModal(False) 0078 self.setWindowTitle('Untitled') 0079 self.setWindowFlags( 0080 Qt.WindowTitleHint | 0081 Qt.WindowMinimizeButtonHint | 0082 Qt.WindowMaximizeButtonHint | 0083 Qt.WindowCloseButtonHint 0084 ) 0085 self.resize(1024, 768) 0086 self.setLayout(QVBoxLayout()) 0087 0088 self.left_viewer = page_viewer() 0089 self.left_viewer.align_right() 0090 self.left_viewer.clicked.connect(self.prev_page) 0091 self.right_viewer = page_viewer() 0092 self.right_viewer.align_left() 0093 self.right_viewer.clicked.connect(self.next_page) 0094 self.single_viewer = page_viewer() 0095 self.single_viewer.align_center() 0096 self.single_viewer.clicked.connect(self.next_page) 0097 self.single_viewer.hide() 0098 0099 self.page_layout = QHBoxLayout() 0100 self.layout().addLayout(self.page_layout) 0101 self.page_layout.addWidget(self.left_viewer) 0102 self.page_layout.addWidget(self.right_viewer) 0103 self.page_layout.addWidget(self.single_viewer) 0104 0105 # Keyboard shortcuts 0106 self.home_shortcut = QShortcut('Home', self) 0107 self.home_shortcut.activated.connect(self.first_page) 0108 self.left_shortcut = QShortcut('Left', self) 0109 self.left_shortcut.activated.connect(self.prev_page) 0110 self.right_shortcut = QShortcut('Right', self) 0111 self.right_shortcut.activated.connect(self.next_page) 0112 self.space_shortcut = QShortcut('Space', self) 0113 self.space_shortcut.activated.connect(self.next_page) 0114 self.end_shortcut = QShortcut('End', self) 0115 self.end_shortcut.activated.connect(self.last_page) 0116 0117 self.first_btn = QPushButton('First') 0118 self.first_btn.clicked.connect(self.first_page) 0119 self.prev_btn = QPushButton('Previous') 0120 self.prev_btn.clicked.connect(self.prev_page) 0121 self.spread_btn = QPushButton('Single Page') 0122 self.spread_btn.clicked.connect(self.toggle_spread) 0123 self.next_btn = QPushButton('Next') 0124 self.next_btn.clicked.connect(self.next_page) 0125 self.last_btn = QPushButton('Last') 0126 self.last_btn.clicked.connect(self.last_page) 0127 0128 self.buttons_layout = QHBoxLayout() 0129 self.layout().addLayout(self.buttons_layout) 0130 self.buttons_layout.addWidget(self.first_btn) 0131 self.buttons_layout.addWidget(self.prev_btn) 0132 self.buttons_layout.addWidget(self.spread_btn) 0133 self.buttons_layout.addWidget(self.next_btn) 0134 self.buttons_layout.addWidget(self.last_btn) 0135 0136 def load_comic(self, path_to_config): 0137 self.path_to_config = path_to_config 0138 configFile = open(self.path_to_config, "r", newline="", encoding="utf-16") 0139 self.setupDictionary = json.load(configFile) 0140 self.projecturl = os.path.dirname(str(self.path_to_config)) 0141 if 'readingDirection' in self.setupDictionary: 0142 if self.setupDictionary['readingDirection'] == "leftToRight": 0143 self.setLayoutDirection(Qt.LeftToRight) 0144 self.left_shortcut.disconnect() 0145 self.right_shortcut.disconnect() 0146 self.left_shortcut.activated.connect(self.prev_page) 0147 self.right_shortcut.activated.connect(self.next_page) 0148 else: 0149 self.left_shortcut.disconnect() 0150 self.right_shortcut.disconnect() 0151 self.setLayoutDirection(Qt.RightToLeft) 0152 self.left_shortcut.activated.connect(self.next_page) 0153 self.right_shortcut.activated.connect(self.prev_page) 0154 else: 0155 self.left_shortcut.disconnect() 0156 self.right_shortcut.disconnect() 0157 self.setLayoutDirection(Qt.LeftToRight) 0158 self.left_shortcut.activated.connect(self.prev_page) 0159 self.right_shortcut.activated.connect(self.next_page) 0160 configFile.close() 0161 0162 def go_to_page_index(self, index): 0163 if index >= 0 and index < len(self.setupDictionary['pages']): 0164 self.pageIndex = index 0165 else: 0166 self.pageIndex = 0 0167 self.flip_page() 0168 0169 def toggle_spread(self): 0170 if self.spread: 0171 self.spread = False 0172 self.spread_btn.setText('Double Spread') 0173 self.update_single_page(self.pageIndex) 0174 self.left_viewer.hide() 0175 self.right_viewer.hide() 0176 self.single_viewer.show() 0177 self.flip_page() 0178 else: 0179 self.spread = True 0180 self.spread_btn.setText('Single Page') 0181 self.left_viewer.show() 0182 self.right_viewer.show() 0183 self.single_viewer.hide() 0184 self.flip_page() 0185 0186 def update_single_page(self, index): 0187 image = self.get_mergedimage(index) 0188 self.single_viewer.set_image(image) 0189 0190 def update_left_page(self, index): 0191 image = self.get_mergedimage(index) 0192 self.left_viewer.set_image(image) 0193 0194 def update_right_page(self, index): 0195 image = self.get_mergedimage(index) 0196 self.right_viewer.set_image(image) 0197 0198 def first_page(self): 0199 self.pageIndex = 0 0200 self.flip_page() 0201 0202 def prev_page(self): 0203 if self.pageIndex <= 0: 0204 self.pageIndex = len(self.setupDictionary['pages']) - 1 0205 else: 0206 if self.spread: 0207 self.pageIndex -= 2 0208 else: 0209 self.pageIndex -= 1 0210 self.flip_page() 0211 0212 def next_page(self): 0213 if self.pageIndex >= len(self.setupDictionary['pages']) - 1: 0214 self.pageIndex = 0 0215 else: 0216 if self.spread: 0217 self.pageIndex += 2 0218 else: 0219 self.pageIndex += 1 0220 self.flip_page() 0221 0222 def last_page(self): 0223 self.pageIndex = len(self.setupDictionary['pages']) - 1 0224 self.flip_page() 0225 0226 def flip_page(self): 0227 if self.spread: 0228 if self.pageIndex % 2 == 0: # Even/Left 0229 left_page_number = self.pageIndex - 1 0230 right_page_number = self.pageIndex 0231 else: # Odd/Right 0232 left_page_number = self.pageIndex 0233 right_page_number = self.pageIndex + 1 0234 self.update_left_page(left_page_number) 0235 self.update_right_page(right_page_number) 0236 if left_page_number < 0: 0237 page_numbers = str(right_page_number + 1) 0238 elif right_page_number >= len(self.setupDictionary['pages']): 0239 page_numbers = str(left_page_number + 1) 0240 else: 0241 page_numbers = '{left} / {right}'.format( 0242 left = str(left_page_number + 1), 0243 right = str(right_page_number + 1)) 0244 self.setWindowTitle('{name} - {page_numbers}'.format( 0245 name = self.setupDictionary['projectName'], 0246 page_numbers = page_numbers)) 0247 else: 0248 if self.pageIndex >= len(self.setupDictionary['pages']): 0249 self.pageIndex = len(self.setupDictionary['pages']) - 1 0250 if self.pageIndex < 0: 0251 self.pageIndex = 0 0252 self.update_single_page(self.pageIndex) 0253 self.setWindowTitle('{name} - {page_numbers}'.format( 0254 name = self.setupDictionary['projectName'], 0255 page_numbers = str(self.pageIndex + 1))) 0256 0257 0258 def get_mergedimage(self, index): 0259 if index < len(self.setupDictionary['pages']) and index > -1: 0260 image_url = os.path.join(self.projecturl, self.setupDictionary['pages'][index]) 0261 if os.path.exists(image_url): 0262 page = zipfile.ZipFile(image_url, "r") 0263 image = QImage.fromData(page.read("mergedimage.png")) 0264 page.close() 0265 return image 0266 image = QImage(QSize(10, 10), QImage.Format_ARGB32) 0267 image.fill(Qt.GlobalColor(19)) 0268 return image 0269 0270 if __name__ == '__main__': 0271 ''' Run the page viewer outside Krita ''' 0272 app = QApplication(sys.argv) 0273 if sys.argv: 0274 print(sys.argv) 0275 path_to_config = sys.argv[1] 0276 if os.path.exists(path_to_config): 0277 print('Run comics viewer') 0278 page_viewer_dialog = comics_project_page_viewer() 0279 page_viewer_dialog.load_comic(path_to_config) 0280 page_viewer_dialog.go_to_page_index(0) 0281 page_viewer_dialog.show() 0282 else: 0283 print('No comic found in {comic}'.format(comic=comic)) 0284 else: 0285 print('Pass the path to a Krita comicConfig.json file to this script, to view the comic.') 0286 0287 sys.exit(app.exec_()) 0288 0289 0290