Improve DjVu support

This commit is contained in:
BasioMeusPuga
2019-03-15 19:07:07 -04:00
parent eb49ca92a4
commit 38de0dcd13
7 changed files with 45 additions and 44 deletions

View File

@@ -30,7 +30,6 @@ Bitcoin: 17jaxj26vFJNqQ2hEVerbBV5fpTusfqFro
| Package | Version tested | Required for |
| --- | --- | --- |
| python-pymupdf | 1.14.5 | PDF support |
| python-numpy | 1.16.2 | DjVu support |
| python-djvulibre | 0.8.4 | DjVu support |
## Support

4
TODO
View File

@@ -89,6 +89,7 @@ TODO
Have them save to memory
✓ fb2 support
✓ Images need to show up in their placeholders
✓ djvu support
Other:
✓ Define every widget in code
Bugs:
@@ -121,10 +122,11 @@ TODO
Goodreads API: Ratings, Read, Recommendations
Get ISBN using python-isbnlib
Use embedded fonts + CSS
txt, doc, chm, djvu support
txt, doc, chm, markdown support
Include icons for filetype emblems
Comic view modes
Continuous paging
Image rotation
Ignore a / the / numbers for sorting purposes
? Add only one file type if multiple are present
? Create emblem per filetype

View File

@@ -106,7 +106,7 @@ class PliantQGraphicsView(QtWidgets.QGraphicsView):
elif self.filetype == 'djvu':
page_data = self.book.pages[page]
pixmap = render_djvu_page(page_data, '/tmp')
pixmap = render_djvu_page(page_data)
return pixmap
@@ -183,12 +183,10 @@ class PliantQGraphicsView(QtWidgets.QGraphicsView):
# TODO
# Get caching working for double page view
# 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:

View File

@@ -17,33 +17,23 @@
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):
def __init__(self, filename, *args):
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):
# TODO
# What even is this?
title = os.path.basename(self.filename)
author = 'Unknown'
year = 9999
@@ -51,7 +41,7 @@ class ParseDJVU:
tags = []
cover_page = self.book.pages[0]
cover = render_djvu_page(cover_page, self.extract_dir, True)
cover = render_djvu_page(cover_page, True)
Metadata = collections.namedtuple(
'Metadata', ['title', 'author', 'year', 'isbn', 'tags', 'cover'])
@@ -60,46 +50,49 @@ class ParseDJVU:
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):
def render_djvu_page(page, for_cover=False):
# TODO
# Figure out how to calculate image stride
bytes_per_line = 13200
# and if it impacts row_alignment in the render
# method below
# bytes_per_line = 13200
# Yes, but why?
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
# ¯\_(ツ)_/¯
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
output = page_job.render(
mode, rect, rect, djvu_pixel_format)
# row_alignment=bytes_per_line)
imageFormat = QtGui.QImage.Format_RGB32
pageQImage = QtGui.QImage(color_buffer, width, height, imageFormat)
pageQImage = QtGui.QImage(output, width, height, imageFormat)
# Format conversion not only keeps the damn thing from
# segfaulting when converting from QImage to QPixmap,
# but it also allows for the double page mode to keep
# working properly. We like format conversion.
pageQImage = pageQImage.convertToFormat(
QtGui.QImage.Format_ARGB32_Premultiplied)
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)
pixmap.convertFromImage(pageQImage)
return pixmap

View File

@@ -89,7 +89,7 @@ class EPUB:
return i
# If the file isn't found
logger.error(filename + ' not found in ' + self.book_filename)
logger.warning(filename + ' not found in ' + self.book_filename)
return False
def generate_toc(self):
@@ -109,7 +109,7 @@ class EPUB:
if not toc_filename:
if not toc_filename_alternative:
logger.error('No ToC found for: ' + self.book_filename)
logger.warning('No ToC found for: ' + self.book_filename)
else:
toc_filename = toc_filename_alternative

View File

@@ -62,14 +62,13 @@ else:
print(error_string)
logger.error(error_string)
# numpy and djvu - Optional
numpy_check = importlib.util.find_spec('numpy')
# djvu - Optional
djvu_check = importlib.util.find_spec('djvu.decode')
if numpy_check and djvu_check:
if 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.'
error_string = 'djvulibre is not installed. Will be unable to load Djvu files.'
print(error_string)
logger.error(error_string)

View File

@@ -25,11 +25,17 @@ from PyQt5 import QtCore, QtGui
from lector import sorter
from lector import database
# The following have to be separate
try:
from lector.parsers.pdf import render_pdf_page
except ImportError:
pass
try:
from lector.parsers.djvu import render_djvu_page
except ImportError:
pass
logger = logging.getLogger(__name__)
@@ -165,6 +171,10 @@ class BackGroundCacheRefill(QtCore.QThread):
page_data = self.book.loadPage(current_page)
pixmap = render_pdf_page(page_data)
elif self.filetype == 'djvu':
page_data = self.book.pages[current_page]
pixmap = render_djvu_page(page_data)
return pixmap
remove_index = self.image_cache.index(self.remove_value)