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):
|
class BaseError(object):
|
||||||
|
|
||||||
HELP = ''
|
HELP = ''
|
||||||
|
INDIVIDUAL_FIX = ''
|
||||||
|
|
||||||
def __init__(self, msg, name, line=None, col=None):
|
def __init__(self, msg, name, line=None, col=None):
|
||||||
self.msg, self.line, self.col = msg, line, col
|
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.base import OEB_DOCS
|
||||||
from calibre.ebooks.oeb.polish.container import guess_type
|
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.base import run_checkers
|
||||||
from calibre.ebooks.oeb.polish.check.parsing import check_xml_parsing
|
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')))
|
XML_TYPES = frozenset(map(guess_type, ('a.xml', 'a.svg', 'a.opf', 'a.ncx')))
|
||||||
|
|
||||||
@ -20,23 +22,34 @@ def run_checks(container):
|
|||||||
errors = []
|
errors = []
|
||||||
|
|
||||||
# Check parsing
|
# Check parsing
|
||||||
xml_items, html_items = [], []
|
xml_items, html_items, raster_images = [], [], []
|
||||||
for name, mt in container.mime_map.iteritems():
|
for name, mt in container.mime_map.iteritems():
|
||||||
items = None
|
items = None
|
||||||
if mt in XML_TYPES:
|
if mt in XML_TYPES:
|
||||||
items = xml_items
|
items = xml_items
|
||||||
elif mt in OEB_DOCS:
|
elif mt in OEB_DOCS:
|
||||||
items = html_items
|
items = html_items
|
||||||
|
elif is_raster_image(mt):
|
||||||
|
items = raster_images
|
||||||
if items is not None:
|
if items is not None:
|
||||||
items.append((name, mt, container.open(name, 'rb').read()))
|
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, xml_items))
|
||||||
errors.extend(run_checkers(check_xml_parsing, html_items))
|
errors.extend(run_checkers(check_xml_parsing, html_items))
|
||||||
|
errors.extend(run_checkers(check_raster_images, raster_images))
|
||||||
|
|
||||||
return errors
|
return errors
|
||||||
|
|
||||||
def fix_errors(container, errors):
|
def fix_errors(container, errors):
|
||||||
# Fix parsing
|
# Fix parsing
|
||||||
|
changed = False
|
||||||
for name in {e.name for e in errors if getattr(e, 'is_parsing_error', False)}:
|
for name in {e.name for e in errors if getattr(e, 'is_parsing_error', False)}:
|
||||||
container.parsed(name)
|
container.parsed(name)
|
||||||
container.dirty(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 = self.gui.check_book
|
||||||
c.parent().show()
|
c.parent().show()
|
||||||
c.parent().raise_()
|
c.parent().raise_()
|
||||||
c.fix_errors(current_container())
|
changed = c.fix_errors(current_container())
|
||||||
self.apply_container_update_to_gui()
|
if changed:
|
||||||
self.set_modified()
|
self.apply_container_update_to_gui()
|
||||||
|
self.set_modified()
|
||||||
|
else:
|
||||||
|
self.rewind_savepoint()
|
||||||
|
|
||||||
@in_thread_job
|
@in_thread_job
|
||||||
def merge_requested(self, category, names, master):
|
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())]
|
errors = [self.items.item(i).data(Qt.UserRole).toPyObject() for i in xrange(self.items.count())]
|
||||||
self.show_busy(_('Running fixers, please wait...'))
|
self.show_busy(_('Running fixers, please wait...'))
|
||||||
QApplication.processEvents()
|
QApplication.processEvents()
|
||||||
fix_errors(container, errors)
|
changed = fix_errors(container, errors)
|
||||||
self.run_checks(container)
|
self.run_checks(container)
|
||||||
|
return changed
|
||||||
|
|
||||||
def show_busy(self, msg=_('Running checks, please wait...')):
|
def show_busy(self, msg=_('Running checks, please wait...')):
|
||||||
self.help.setText(msg)
|
self.help.setText(msg)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user