Preliminary DjVu support

SideDock fade in animation
This commit is contained in:
BasioMeusPuga
2019-03-14 22:58:52 -04:00
parent ca57983739
commit bf93c7beab
7 changed files with 157 additions and 8 deletions

2
TODO
View File

@@ -100,8 +100,10 @@ TODO
Search results should ignore punctuation Search results should ignore punctuation
Keep text size for annotations Keep text size for annotations
Sort by new is not working Sort by new is not working
Drag and drop is acting out
Secondary: Secondary:
Navbar
Text to speech Text to speech
Definitions dialog needs to respond to escape Definitions dialog needs to respond to escape
Zoom slider for comics Zoom slider for comics

View File

@@ -891,9 +891,12 @@ class MainUI(QtWidgets.QMainWindow, mainwindow.Ui_MainWindow):
last_accessed_time = QtCore.QDateTime().currentDateTime() last_accessed_time = QtCore.QDateTime().currentDateTime()
position_perc = 1 position_perc = 1
self.lib_ref.libraryModel.setData(i, metadata, QtCore.Qt.UserRole + 3) self.lib_ref.libraryModel.setData(
self.lib_ref.libraryModel.setData(i, position_perc, QtCore.Qt.UserRole + 7) i, metadata, QtCore.Qt.UserRole + 3)
self.lib_ref.libraryModel.setData(i, last_accessed_time, QtCore.Qt.UserRole + 12) self.lib_ref.libraryModel.setData(
i, position_perc, QtCore.Qt.UserRole + 7)
self.lib_ref.libraryModel.setData(
i, last_accessed_time, QtCore.Qt.UserRole + 12)
self.lib_ref.update_proxymodels() self.lib_ref.update_proxymodels()
database_dict = { database_dict = {

View File

@@ -25,6 +25,12 @@ try:
except ImportError: except ImportError:
pass pass
try:
import djvu.decode
from lector.parsers.djvu import render_djvu_page
except ImportError:
pass
from PyQt5 import QtWidgets, QtGui, QtCore from PyQt5 import QtWidgets, QtGui, QtCore
from lector.rarfile import rarfile from lector.rarfile import rarfile
@@ -60,6 +66,11 @@ class PliantQGraphicsView(QtWidgets.QGraphicsView):
elif self.filetype == 'pdf': elif self.filetype == 'pdf':
self.book = fitz.open(self.filepath) self.book = fitz.open(self.filepath)
elif self.filetype == 'djvu':
self.book = djvu.decode.Context().new_document(
djvu.decode.FileURI(self.filepath))
self.book.decoding_job.wait()
self.common_functions = PliantWidgetsCommonFunctions( self.common_functions = PliantWidgetsCommonFunctions(
self, self.main_window) self, self.main_window)
@@ -93,6 +104,10 @@ class PliantQGraphicsView(QtWidgets.QGraphicsView):
page_data = self.book.loadPage(page) page_data = self.book.loadPage(page)
pixmap = render_pdf_page(page_data) pixmap = render_pdf_page(page_data)
elif self.filetype == 'djvu':
page_data = self.book.pages[page]
pixmap = render_djvu_page(page_data, '/tmp')
return pixmap return pixmap
firstPixmap = page_loader(current_page) firstPixmap = page_loader(current_page)
@@ -168,7 +183,15 @@ class PliantQGraphicsView(QtWidgets.QGraphicsView):
# TODO # TODO
# Get caching working for double page view # Get caching working for double page view
if not double_page_mode and self.main_window.settings['caching_enabled']: # Get caching working for DjVu files
# All of these must be True
caching_conditions = (
not double_page_mode,
not self.filetype == 'djvu',
self.main_window.settings['caching_enabled'])
if False not in caching_conditions:
return_pixmap = None return_pixmap = None
while not return_pixmap: while not return_pixmap:
return_pixmap = check_cache(current_page) return_pixmap = check_cache(current_page)

View File

@@ -51,6 +51,12 @@ class PliantDockWidget(QtWidgets.QDockWidget):
# Except this one # Except this one
self.sideDockTabWidget = None self.sideDockTabWidget = None
# Animate appearance
self.animation = QtCore.QPropertyAnimation(self, b'windowOpacity')
self.animation.setStartValue(0)
self.animation.setEndValue(1)
self.animation.setDuration(200)
def showEvent(self, event=None): def showEvent(self, event=None):
viewport_topRight = self.contentView.mapToGlobal( viewport_topRight = self.contentView.mapToGlobal(
self.contentView.viewport().rect().topRight()) self.contentView.viewport().rect().topRight())
@@ -69,6 +75,7 @@ class PliantDockWidget(QtWidgets.QDockWidget):
self.main_window.active_docks.append(self) self.main_window.active_docks.append(self)
self.setGeometry(dock_x, dock_y, dock_width, dock_height) self.setGeometry(dock_x, dock_y, dock_width, dock_height)
self.animation.start()
def hideEvent(self, event=None): def hideEvent(self, event=None):
if self.notes_only: if self.notes_only:

View File

@@ -14,7 +14,7 @@
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
VERSION = '0.5.1' VERSION = '0.5.GittyGittyBangBang'
import os import os
import logging import logging

105
lector/parsers/djvu.py Normal file
View File

@@ -0,0 +1,105 @@
# This file is a part of Lector, a Qt based ebook reader
# Copyright (C) 2017-2019 BasioMeusPuga
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import os
import collections
import numpy
import djvu.decode
from PyQt5 import QtGui
djvu_pixel_format = djvu.decode.PixelFormatRgbMask(0xFF0000, 0xFF00, 0xFF, bpp=32)
djvu_pixel_format.rows_top_to_bottom = 1
djvu_pixel_format.y_top_to_bottom = 0
class ParseDJVU:
def __init__(self, filename, temp_dir, file_md5):
self.book = None
self.filename = filename
# Create the temporary directory where
# rendered pngs will be stored
# This may be skipped in case QImage to QPixmap conversion
# stops segfaulting
self.extract_dir = os.path.join(temp_dir, file_md5)
os.makedirs(self.extract_dir, exist_ok=True)
def read_book(self):
self.book = djvu.decode.Context().new_document(
djvu.decode.FileURI(self.filename))
self.book.decoding_job.wait()
def generate_metadata(self):
title = os.path.basename(self.filename)
author = 'Unknown'
year = 9999
isbn = None
tags = []
cover_page = self.book.pages[0]
cover = render_djvu_page(cover_page, self.extract_dir, True)
Metadata = collections.namedtuple(
'Metadata', ['title', 'author', 'year', 'isbn', 'tags', 'cover'])
return Metadata(title, author, year, isbn, tags, cover)
def generate_content(self):
# TODO
# See if it's possible to generate a more involved ToC
content = list(range(len(self.book.pages)))
toc = [(1, f'Page {i + 1}', i + 1) for i in content]
# Return toc, content, images_only
return toc, content, True
def render_djvu_page(page, extract_dir, for_cover=False):
# TODO
# Figure out how to calculate image stride
bytes_per_line = 13200
# Yes, but why?
mode = 0
page_job = page.decode(wait=True)
width, height = page_job.size
rect = (0, 0, width, height)
color_buffer = numpy.zeros((height, bytes_per_line), dtype=numpy.uint32)
page_job.render(
mode, rect, rect, djvu_pixel_format,
row_alignment=bytes_per_line,
buffer=color_buffer)
color_buffer ^= 0xFF000000
imageFormat = QtGui.QImage.Format_RGB32
pageQImage = QtGui.QImage(color_buffer, width, height, imageFormat)
if for_cover:
return pageQImage
# TODO
# Converting from the QImage to the QPixmap directly
# outright segfaults sometimes.
# This damages caching, speed and my ego
outfile = os.path.join(extract_dir, 'temporaryPNG.png')
pageQImage.save(outfile)
pixmap = QtGui.QPixmap()
pixmap.load(outfile)
return pixmap

View File

@@ -58,7 +58,18 @@ if mupdf_check:
from lector.parsers.pdf import ParsePDF from lector.parsers.pdf import ParsePDF
sorter['pdf'] = ParsePDF sorter['pdf'] = ParsePDF
else: else:
error_string = 'pymupdf is not installed. Will be unable to load PDFs.' error_string = 'pymupdf is not installed. Will be unable to load PDF files.'
print(error_string)
logger.error(error_string)
# numpy and djvu - Optional
numpy_check = importlib.util.find_spec('numpy')
djvu_check = importlib.util.find_spec('djvu.decode')
if numpy_check and djvu_check:
from lector.parsers.djvu import ParseDJVU
sorter['djvu'] = ParseDJVU
else:
error_string = 'numpy / djvulibre is not installed. Will be unable to load Djvu files.'
print(error_string) print(error_string)
logger.error(error_string) logger.error(error_string)
@@ -211,8 +222,6 @@ class BookSorter:
# None of the following have an exception type specified # None of the following have an exception type specified
# This will keep everything from crashing, but will make # This will keep everything from crashing, but will make
# troubleshooting difficult # troubleshooting difficult
# TODO
# In application notifications
try: try:
book_ref.read_book() book_ref.read_book()