Use double-buffer technology to generate pixmap cache when after finger release.

master
Andy Stewart 8 years ago
parent 715ecea37f
commit 8a11c9c022
  1. 71
      app/pdfviewer/buffer.py
  2. 2
      core/buffer.py

@ -24,7 +24,9 @@ from PyQt5.QtCore import Qt, QRect
from PyQt5.QtGui import QColor, QPixmap, QImage, QFont
from PyQt5.QtGui import QPainter
from PyQt5.QtWidgets import QWidget
from functools import wraps
import fitz
import time
from core.buffer import Buffer
class AppBuffer(Buffer):
@ -67,6 +69,7 @@ class PdfViewerWidget(QWidget):
def __init__(self, url, background_color):
super(PdfViewerWidget, self).__init__()
self.url = url
self.background_color = background_color
# Load document first.
@ -102,6 +105,11 @@ class PdfViewerWidget(QWidget):
self.page_cache_pixmap_dict = {}
self.page_cache_scale = self.scale
self.page_cache_trans = None
self.page_cache_context_delay = 500
self.last_action_time = 0
self.is_page_just_changed = False
def get_page_pixmap(self, index, scale):
# Just return cache pixmap when found match index and scale in cache dict.
@ -122,13 +130,22 @@ class PdfViewerWidget(QWidget):
self.page_cache_pixmap_dict[index] = qpixmap
print("*** New page pixmap: %s %s" % (self.url, index))
return qpixmap
def clean_unused_page_cache_pixmap(self, index_list):
def clean_unused_page_cache_pixmap(self):
# We need expand render index bound that avoid clean cache around current index.
start_page_index = max(0, self.get_start_page_index() - 1)
last_page_index = min(self.page_total_number, self.get_last_page_index() + 1)
index_list = list(range(start_page_index, last_page_index))
# Try to clean unused cache.
cache_index_list = list(self.page_cache_pixmap_dict.keys())
for cache_index in cache_index_list:
if cache_index not in index_list:
print("*** Clean unused page pixmap: %s %s" % (self.url, cache_index))
self.page_cache_pixmap_dict.pop(cache_index)
def resizeEvent(self, event):
@ -148,15 +165,15 @@ class PdfViewerWidget(QWidget):
painter.drawRect(0, 0, self.rect().width(), self.rect().height())
# Get start/last render index.
start_page_index = int(self.scroll_offset * 1.0 / self.scale / self.page_height)
last_page_index = int((self.scroll_offset + self.rect().height()) * 1.0 / self.scale / self.page_height)
start_page_index = self.get_start_page_index()
last_page_index = self.get_last_page_index()
# Translate painter at y coordinate.
translate_y = (start_page_index * self.scale * self.page_height) - self.scroll_offset
painter.translate(0, translate_y)
# Render pages in visible area.
for index in list(range(start_page_index, last_page_index + 1)):
for index in list(range(start_page_index, last_page_index)):
if index < self.page_total_number:
# Get page image.
qpixmap = self.get_page_pixmap(index, self.scale)
@ -175,7 +192,7 @@ class PdfViewerWidget(QWidget):
painter.drawPixmap(QRect(render_x, render_y, render_width, render_height), qpixmap)
# Clean unused pixmap cache that avoid use too much memory.
self.clean_unused_page_cache_pixmap(list(range(start_page_index, last_page_index + 1)))
self.clean_unused_page_cache_pixmap()
painter.restore()
@ -189,10 +206,36 @@ class PdfViewerWidget(QWidget):
Qt.AlignRight,
"{0}% ({1}/{2})".format(int((start_page_index + 1) * 100 / self.page_total_number), start_page_index + 1, self.page_total_number))
def build_context_wrap(f):
def wrapper(*args):
# Get self instance object.
self_obj = args[0]
# Record page before action.
page_before_action = self_obj.get_start_page_index()
# Do action.
ret = f(*args)
# Record page after action.
page_after_action = self_obj.get_start_page_index()
self_obj.is_page_just_changed = (page_before_action != page_after_action)
# Start build context timer.
self_obj.last_action_time = time.time()
QtCore.QTimer().singleShot(self_obj.page_cache_context_delay, self_obj.build_context_cache)
return ret
return wrapper
@build_context_wrap
def wheelEvent(self, event):
self.scroll_offset = max(min(self.scroll_offset - self.scale * event.angleDelta().y() / 120 * self.mouse_scroll_offset, self.max_scroll_offset()), 0)
self.update()
@build_context_wrap
def keyPressEvent(self, event):
if event.key() == Qt.Key_J:
self.scroll_up()
@ -219,6 +262,24 @@ class PdfViewerWidget(QWidget):
elif event.key() == Qt.Key_P:
self.send_input_message("Jump to percent: ", "jump_percent")
def get_start_page_index(self):
return int(self.scroll_offset * 1.0 / self.scale / self.page_height)
def get_last_page_index(self):
return int((self.scroll_offset + self.rect().height()) * 1.0 / self.scale / self.page_height) + 1
def build_context_cache(self):
# Just build context cache when action duration longer than delay
# Don't build contexnt cache when is_page_just_changed is True, avoid flickr when user change page.
last_action_duration = (time.time() - self.last_action_time) * 1000
if last_action_duration > self.page_cache_context_delay and not self.is_page_just_changed:
start_page_index = max(0, self.get_start_page_index() - 1)
last_page_index = min(self.page_total_number, self.get_last_page_index() + 1)
print("*** Try build %s context cache pixmap from %s to %s" % (self.url, start_page_index, last_page_index - 1))
for index in list(range(start_page_index, last_page_index)):
self.get_page_pixmap(index, self.scale)
def scale_to(self, new_scale):
self.scroll_offset = new_scale * 1.0 / self.scale * self.scroll_offset
self.scale = new_scale

@ -84,6 +84,8 @@ class Buffer(QGraphicsScene):
self.buffer_widget.installEventFilter(self)
self.buffer_widget.message_to_emacs = self.message_to_emacs
def handle_destroy(self):
self.before_destroy_hook.emit()

Loading…
Cancel
Save