Make GlyphDB store GlyphData objects instead of just text.
This commit is contained in:
parent
a44091b570
commit
9c8de1ce0f
6 changed files with 90 additions and 53 deletions
|
|
@ -18,34 +18,90 @@ import pickle
|
||||||
from collections import OrderedDict
|
from collections import OrderedDict
|
||||||
from os import path
|
from os import path
|
||||||
|
|
||||||
|
from .utils import cached_property
|
||||||
|
from .image import Image
|
||||||
|
|
||||||
|
|
||||||
|
class GlyphData(object):
|
||||||
|
def __init__(self, image_data, elevation, text, bold=False, italic=False):
|
||||||
|
self.image_data = image_data
|
||||||
|
self.elevation = elevation
|
||||||
|
self.text = text
|
||||||
|
self.bold = bold
|
||||||
|
self.italic = italic
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_glyph(cls, glyph, *args, **kwargs):
|
||||||
|
return cls(glyph.image.serialize(), glyph.elevation, *args, **kwargs)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def color(self):
|
||||||
|
return self.image.color
|
||||||
|
|
||||||
|
@cached_property
|
||||||
|
def image(self):
|
||||||
|
return Image.deserialize(self.image_data)
|
||||||
|
|
||||||
|
def serialize(self):
|
||||||
|
return (
|
||||||
|
self.image_data,
|
||||||
|
self.elevation,
|
||||||
|
self.text,
|
||||||
|
self.bold,
|
||||||
|
self.italic,
|
||||||
|
)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def deserialize(cls, args):
|
||||||
|
return cls(*args)
|
||||||
|
|
||||||
|
|
||||||
class GlyphDB(object):
|
class GlyphDB(object):
|
||||||
def __init__(self, filename):
|
def __init__(self, filename):
|
||||||
self.filename = filename
|
self.filename = filename
|
||||||
|
self._dict = OrderedDict()
|
||||||
if path.isfile(self.filename):
|
if path.isfile(self.filename):
|
||||||
with open(self.filename, 'rb') as fileobj:
|
self.load()
|
||||||
self.data = pickle.load(fileobj)
|
|
||||||
else:
|
|
||||||
self.data = OrderedDict()
|
|
||||||
|
|
||||||
def __getitem__(self, key):
|
def _key_from_glyph(self, glyph):
|
||||||
return self.data.__getitem__(key)
|
return (glyph.image.serialize(), glyph.elevation)
|
||||||
|
|
||||||
def __setitem__(self, key, value):
|
def _key_from_data(self, data):
|
||||||
return self.data.__setitem__(key, value)
|
return (data.image_data, data.elevation)
|
||||||
|
|
||||||
def __delitem__(self, key):
|
def __getitem__(self, glyph):
|
||||||
return self.data.__delitem__(key)
|
key = self._key_from_glyph(glyph)
|
||||||
|
return self._dict[key]
|
||||||
|
|
||||||
|
def add_glyph(self, glyph, text, bold=False, italic=False):
|
||||||
|
data = GlyphData.from_glyph(glyph, text, bold=bold, italic=italic)
|
||||||
|
key = self._key_from_glyph(glyph)
|
||||||
|
self._dict[key] = data
|
||||||
|
|
||||||
|
def update(self, data):
|
||||||
|
key = self._key_from_data(data)
|
||||||
|
self._dict[key] = data
|
||||||
|
|
||||||
|
def remove(self, data):
|
||||||
|
key = self._key_from_data(data)
|
||||||
|
del self._dict[key]
|
||||||
|
|
||||||
def keys(self):
|
def keys(self):
|
||||||
return self.data.keys()
|
return self._dict.keys()
|
||||||
|
|
||||||
def items(self):
|
def items(self):
|
||||||
return self.data.items()
|
return self._dict.items()
|
||||||
|
|
||||||
def values(self):
|
def values(self):
|
||||||
return self.data.values()
|
return self._dict.values()
|
||||||
|
|
||||||
|
def load(self):
|
||||||
|
with open(self.filename, 'rb') as fileobj:
|
||||||
|
data = pickle.load(fileobj)
|
||||||
|
for item in data:
|
||||||
|
self.update(GlyphData.deserialize(item))
|
||||||
|
|
||||||
def save(self):
|
def save(self):
|
||||||
|
data = [data.serialize() for data in self.values()]
|
||||||
with open(self.filename, 'wb') as fileobj:
|
with open(self.filename, 'wb') as fileobj:
|
||||||
pickle.dump(self.data, fileobj)
|
pickle.dump(data, fileobj)
|
||||||
|
|
|
||||||
|
|
@ -36,27 +36,14 @@ class GlyphDBModel(QAbstractTableModel):
|
||||||
def __init__(self, glyphdb, parent=None):
|
def __init__(self, glyphdb, parent=None):
|
||||||
super().__init__(parent)
|
super().__init__(parent)
|
||||||
self.glyphdb = glyphdb
|
self.glyphdb = glyphdb
|
||||||
self.keys = list(glyphdb.keys())
|
self.values = list(glyphdb.values())
|
||||||
self.images = {}
|
|
||||||
|
|
||||||
def rowCount(self, parent):
|
def rowCount(self, parent):
|
||||||
return len(self.keys)
|
return len(self.values)
|
||||||
|
|
||||||
def columnCount(self, parent):
|
def columnCount(self, parent):
|
||||||
return 2
|
return 2
|
||||||
|
|
||||||
def _deserialize_image(self, key):
|
|
||||||
elevation_, serialized_image = key
|
|
||||||
return Image.deserialize(serialized_image).toqimage()
|
|
||||||
|
|
||||||
def get_image(self, key):
|
|
||||||
try:
|
|
||||||
image = self.images[key]
|
|
||||||
except KeyError:
|
|
||||||
image = self._deserialize_image(key)
|
|
||||||
self.images[key] = image
|
|
||||||
return image
|
|
||||||
|
|
||||||
def headerData(self, section, orientation, role):
|
def headerData(self, section, orientation, role):
|
||||||
if orientation != Qt.Horizontal or role != Qt.DisplayRole:
|
if orientation != Qt.Horizontal or role != Qt.DisplayRole:
|
||||||
return None
|
return None
|
||||||
|
|
@ -66,24 +53,23 @@ class GlyphDBModel(QAbstractTableModel):
|
||||||
return 'Elevation'
|
return 'Elevation'
|
||||||
|
|
||||||
def data(self, index, role):
|
def data(self, index, role):
|
||||||
|
data = self.values[index.row()]
|
||||||
if index.column() == 0:
|
if index.column() == 0:
|
||||||
key = self.keys[index.row()]
|
|
||||||
if role == Qt.DisplayRole:
|
if role == Qt.DisplayRole:
|
||||||
return self.glyphdb[key]
|
return data.text
|
||||||
elif role == Qt.DecorationRole:
|
elif role == Qt.DecorationRole:
|
||||||
return self.get_image(key)
|
return data.image.qimage
|
||||||
elif index.column() == 1:
|
elif index.column() == 1:
|
||||||
if role == Qt.DisplayRole:
|
if role == Qt.DisplayRole:
|
||||||
elevation, _ = self.keys[index.row()]
|
return str(data.elevation)
|
||||||
return str(elevation)
|
|
||||||
|
|
||||||
def removeRows(self, row, count, parent=None):
|
def removeRows(self, row, count, parent=None):
|
||||||
self.beginRemoveRows(parent, row, row + count - 1)
|
self.beginRemoveRows(parent, row, row + count - 1)
|
||||||
|
|
||||||
keys = self.keys[row: row + count]
|
values = self.values[row: row + count]
|
||||||
for key in keys:
|
for value in values:
|
||||||
del self.glyphdb[key]
|
self.glyphdb.remove(value)
|
||||||
del self.keys[row]
|
del self.values[row]
|
||||||
|
|
||||||
self.endRemoveRows()
|
self.endRemoveRows()
|
||||||
return True
|
return True
|
||||||
|
|
@ -91,16 +77,15 @@ class GlyphDBModel(QAbstractTableModel):
|
||||||
def sort(self, column, order):
|
def sort(self, column, order):
|
||||||
key_func = None
|
key_func = None
|
||||||
if column == 0:
|
if column == 0:
|
||||||
def key_func(key):
|
def key_func(value):
|
||||||
return self.glyphdb[key]
|
return value.text
|
||||||
elif column == 1:
|
elif column == 1:
|
||||||
def key_func(key):
|
def key_func(value):
|
||||||
elevation, *_ = key
|
return value.elevation
|
||||||
return elevation
|
|
||||||
|
|
||||||
if key_func:
|
if key_func:
|
||||||
self.layoutAboutToBeChanged.emit()
|
self.layoutAboutToBeChanged.emit()
|
||||||
self.keys.sort(key=key_func, reverse = (order == Qt.DescendingOrder))
|
self.values.sort(key=key_func, reverse = (order == Qt.DescendingOrder))
|
||||||
self.layoutChanged.emit()
|
self.layoutChanged.emit()
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -75,10 +75,10 @@ class OCREngine(QThread):
|
||||||
if isinstance(glyph, Space):
|
if isinstance(glyph, Space):
|
||||||
return ' '
|
return ' '
|
||||||
try:
|
try:
|
||||||
return self.glyphdb[glyph.key]
|
return self.glyphdb[glyph].text
|
||||||
except KeyError:
|
except KeyError:
|
||||||
text = self.ask_for_help(glyph)
|
text = self.ask_for_help(glyph)
|
||||||
self.glyphdb[glyph.key] = text
|
self.glyphdb.add_glyph(glyph, text)
|
||||||
return text
|
return text
|
||||||
|
|
||||||
def ask_for_help(self, unknown_glyph):
|
def ask_for_help(self, unknown_glyph):
|
||||||
|
|
|
||||||
|
|
@ -84,7 +84,7 @@ class PageScene(QGraphicsScene):
|
||||||
self.addRect(glyph.x - 1, glyph.y - 1, glyph.width + 1, glyph.height + 1, self.spacePen, self.spaceBrush)
|
self.addRect(glyph.x - 1, glyph.y - 1, glyph.width + 1, glyph.height + 1, self.spacePen, self.spaceBrush)
|
||||||
|
|
||||||
def addPage(self, page):
|
def addPage(self, page):
|
||||||
qimage = page.image.toqimage()
|
qimage = page.image.qimage
|
||||||
graphicsitem = self.addPixmap(QPixmap.fromImage(qimage))
|
graphicsitem = self.addPixmap(QPixmap.fromImage(qimage))
|
||||||
return graphicsitem
|
return graphicsitem
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -185,7 +185,8 @@ class Image(object):
|
||||||
array = np.fromstring(data, dtype=np.uint8).reshape(shape)
|
array = np.fromstring(data, dtype=np.uint8).reshape(shape)
|
||||||
return cls(array)
|
return cls(array)
|
||||||
|
|
||||||
def toqimage(self):
|
@cached_property
|
||||||
|
def qimage(self):
|
||||||
from PyQt4.QtGui import QImage
|
from PyQt4.QtGui import QImage
|
||||||
return QImage(
|
return QImage(
|
||||||
self.data.astype(np.uint8).data,
|
self.data.astype(np.uint8).data,
|
||||||
|
|
|
||||||
|
|
@ -251,11 +251,6 @@ class Glyph(PageObject):
|
||||||
self.elevation = elevation
|
self.elevation = elevation
|
||||||
self.line = line
|
self.line = line
|
||||||
|
|
||||||
@property
|
|
||||||
def key(self):
|
|
||||||
"""Return a dictionary key uniquely representing this glyph."""
|
|
||||||
return self.elevation, self.image.serialize()
|
|
||||||
|
|
||||||
def is_body(self):
|
def is_body(self):
|
||||||
"""Return True if the glyph is definitely not diacritic."""
|
"""Return True if the glyph is definitely not diacritic."""
|
||||||
return self.height >= self.MIN_BODY_HEIGHT
|
return self.height >= self.MIN_BODY_HEIGHT
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue