mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
Checks for raster images
This commit is contained in:
parent
089a76662f
commit
158a168b1d
@ -16,6 +16,7 @@ DEBUG, INFO, WARN, ERROR, CRITICAL = xrange(5)
|
||||
class BaseError(object):
|
||||
|
||||
HELP = ''
|
||||
INDIVIDUAL_FIX = ''
|
||||
|
||||
def __init__(self, msg, name, line=None, col=None):
|
||||
self.msg, self.line, self.col = msg, line, col
|
||||
|
60
src/calibre/ebooks/oeb/polish/check/images.py
Normal file
60
src/calibre/ebooks/oeb/polish/check/images.py
Normal file
@ -0,0 +1,60 @@
|
||||
#!/usr/bin/env python
|
||||
# vim:fileencoding=utf-8
|
||||
from __future__ import (unicode_literals, division, absolute_import,
|
||||
print_function)
|
||||
|
||||
__license__ = 'GPL v3'
|
||||
__copyright__ = '2013, Kovid Goyal <kovid at kovidgoyal.net>'
|
||||
|
||||
from calibre import as_unicode
|
||||
from calibre.utils.magick import Image
|
||||
from calibre.ebooks.oeb.polish.check.base import BaseError
|
||||
|
||||
class InvalidImage(BaseError):
|
||||
|
||||
HELP = _('An invalid image is an image that could not be loaded, typically because'
|
||||
' it is corrupted. You should replace it with a good image or remove it.')
|
||||
|
||||
def __init__(self, msg, *args, **kwargs):
|
||||
BaseError.__init__(self, 'Invalid image: ' + msg, *args, **kwargs)
|
||||
|
||||
class CMYKImage(BaseError):
|
||||
|
||||
HELP = _('Reader devices based on Adobe Digital Editions cannot display images whose'
|
||||
' colors are specified in the CMYK colorspace. You should convert this image'
|
||||
' to the RGB colorspace, for maximum compatibility.')
|
||||
INDIVIDUAL_FIX = _('Convert image to RGB automatically')
|
||||
|
||||
def __call__(self, container):
|
||||
from PyQt4.Qt import QImage
|
||||
from calibre.gui2 import pixmap_to_data
|
||||
ext = container.mime_map[self.name].split('/')[-1].upper()
|
||||
if ext == 'JPG':
|
||||
ext = 'JPEG'
|
||||
if ext not in ('PNG', 'JPEG', 'GIF'):
|
||||
return False
|
||||
with container.open(self.name, 'r+b') as f:
|
||||
raw = f.read()
|
||||
i = QImage()
|
||||
i.loadFromData(raw)
|
||||
if i.isNull():
|
||||
return False
|
||||
raw = pixmap_to_data(i, format=ext, quality=95)
|
||||
f.seek(0)
|
||||
f.truncate()
|
||||
f.write(raw)
|
||||
return True
|
||||
|
||||
def check_raster_images(name, mt, raw):
|
||||
errors = []
|
||||
i = Image()
|
||||
try:
|
||||
i.load(raw)
|
||||
except Exception as e:
|
||||
errors.append(InvalidImage(as_unicode(e.message), name))
|
||||
else:
|
||||
if i.colorspace == 'CMYKColorspace':
|
||||
errors.append(CMYKImage(_('Image is in the CMYK colorspace'), name))
|
||||
|
||||
return errors
|
||||
|
@ -10,8 +10,10 @@ from future_builtins import map
|
||||
|
||||
from calibre.ebooks.oeb.base import OEB_DOCS
|
||||
from calibre.ebooks.oeb.polish.container import guess_type
|
||||
from calibre.ebooks.oeb.polish.cover import is_raster_image
|
||||
from calibre.ebooks.oeb.polish.check.base import run_checkers
|
||||
from calibre.ebooks.oeb.polish.check.parsing import check_xml_parsing
|
||||
from calibre.ebooks.oeb.polish.check.images import check_raster_images
|
||||
|
||||
XML_TYPES = frozenset(map(guess_type, ('a.xml', 'a.svg', 'a.opf', 'a.ncx')))
|
||||
|
||||
@ -20,23 +22,34 @@ def run_checks(container):
|
||||
errors = []
|
||||
|
||||
# Check parsing
|
||||
xml_items, html_items = [], []
|
||||
xml_items, html_items, raster_images = [], [], []
|
||||
for name, mt in container.mime_map.iteritems():
|
||||
items = None
|
||||
if mt in XML_TYPES:
|
||||
items = xml_items
|
||||
elif mt in OEB_DOCS:
|
||||
items = html_items
|
||||
elif is_raster_image(mt):
|
||||
items = raster_images
|
||||
if items is not None:
|
||||
items.append((name, mt, container.open(name, 'rb').read()))
|
||||
errors.extend(run_checkers(check_xml_parsing, xml_items))
|
||||
errors.extend(run_checkers(check_xml_parsing, html_items))
|
||||
errors.extend(run_checkers(check_raster_images, raster_images))
|
||||
|
||||
return errors
|
||||
|
||||
def fix_errors(container, errors):
|
||||
# Fix parsing
|
||||
changed = False
|
||||
for name in {e.name for e in errors if getattr(e, 'is_parsing_error', False)}:
|
||||
container.parsed(name)
|
||||
container.dirty(name)
|
||||
changed = True
|
||||
|
||||
for err in errors:
|
||||
if err.INDIVIDUAL_FIX:
|
||||
if err(container):
|
||||
changed = True
|
||||
return changed
|
||||
|
||||
|
@ -711,9 +711,12 @@ class Boss(QObject):
|
||||
c = self.gui.check_book
|
||||
c.parent().show()
|
||||
c.parent().raise_()
|
||||
c.fix_errors(current_container())
|
||||
self.apply_container_update_to_gui()
|
||||
self.set_modified()
|
||||
changed = c.fix_errors(current_container())
|
||||
if changed:
|
||||
self.apply_container_update_to_gui()
|
||||
self.set_modified()
|
||||
else:
|
||||
self.rewind_savepoint()
|
||||
|
||||
@in_thread_job
|
||||
def merge_requested(self, category, names, master):
|
||||
|
@ -143,8 +143,9 @@ class Check(QSplitter):
|
||||
errors = [self.items.item(i).data(Qt.UserRole).toPyObject() for i in xrange(self.items.count())]
|
||||
self.show_busy(_('Running fixers, please wait...'))
|
||||
QApplication.processEvents()
|
||||
fix_errors(container, errors)
|
||||
changed = fix_errors(container, errors)
|
||||
self.run_checks(container)
|
||||
return changed
|
||||
|
||||
def show_busy(self, msg=_('Running checks, please wait...')):
|
||||
self.help.setText(msg)
|
||||
|
Loading…
x
Reference in New Issue
Block a user