mirror of
https://github.com/gryf/ebook-converter.git
synced 2026-03-04 07:45:48 +01:00
Added support for epub output format.
This commit is contained in:
@@ -52,7 +52,7 @@ Currently, I've tested following input formats:
|
|||||||
- Palm pdb
|
- Palm pdb
|
||||||
- rtf
|
- rtf
|
||||||
- mobi
|
- mobi
|
||||||
|
- fb2
|
||||||
|
|
||||||
Note, that old Microsoft doc format is not supported, although old documents
|
Note, that old Microsoft doc format is not supported, although old documents
|
||||||
can be fairly easy converted using text processors programs, lik Word or
|
can be fairly easy converted using text processors programs, lik Word or
|
||||||
@@ -62,11 +62,10 @@ LibreOffice to supported formats.
|
|||||||
Output formats
|
Output formats
|
||||||
~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~
|
||||||
|
|
||||||
Currenlty, the only format which is supported is BBeB (lrf) mainly because it
|
Currently, following formats are supported:
|
||||||
is the only one I care for now ;) I'm happy user of Sony PRS-505, and I have no
|
|
||||||
zero motivation to change that reader to something more fancy. Or plastic.
|
|
||||||
|
|
||||||
I'm going to enable others pretty soon.
|
- lrf (for Sony readers)
|
||||||
|
- epub
|
||||||
|
|
||||||
|
|
||||||
Installation
|
Installation
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import re, random, unicodedata, numbers
|
|||||||
from collections import namedtuple
|
from collections import namedtuple
|
||||||
from contextlib import contextmanager
|
from contextlib import contextmanager
|
||||||
from math import ceil, sqrt, cos, sin, atan2
|
from math import ceil, sqrt, cos, sin, atan2
|
||||||
from polyglot.builtins import iteritems, itervalues, map, zip, string_or_bytes
|
from ebook_converter.polyglot.builtins import iteritems, itervalues, map, zip, string_or_bytes
|
||||||
from itertools import chain
|
from itertools import chain
|
||||||
|
|
||||||
from PyQt5.Qt import (
|
from PyQt5.Qt import (
|
||||||
@@ -18,14 +18,14 @@ from PyQt5.Qt import (
|
|||||||
QPainterPath, QPen, QRectF, QTransform, QRadialGradient
|
QPainterPath, QPen, QRectF, QTransform, QRadialGradient
|
||||||
)
|
)
|
||||||
|
|
||||||
from calibre import force_unicode, fit_image
|
from ebook_converter import force_unicode, fit_image
|
||||||
from calibre.constants import __appname__, __version__
|
from ebook_converter.constants import __appname__, __version__
|
||||||
from calibre.ebooks.metadata import fmt_sidx
|
from ebook_converter.ebooks.metadata import fmt_sidx
|
||||||
from calibre.ebooks.metadata.book.base import Metadata
|
from ebook_converter.ebooks.metadata.book.base import Metadata
|
||||||
from calibre.ebooks.metadata.book.formatter import SafeFormat
|
from ebook_converter.ebooks.metadata.book.formatter import SafeFormat
|
||||||
from calibre.gui2 import ensure_app, config, load_builtin_fonts, pixmap_to_data
|
from ebook_converter.gui2 import ensure_app, config, load_builtin_fonts, pixmap_to_data
|
||||||
from calibre.utils.cleantext import clean_ascii_chars, clean_xml_chars
|
from ebook_converter.utils.cleantext import clean_ascii_chars, clean_xml_chars
|
||||||
from calibre.utils.config import JSONConfig
|
from ebook_converter.utils.config import JSONConfig
|
||||||
|
|
||||||
# Default settings {{{
|
# Default settings {{{
|
||||||
cprefs = JSONConfig('cover_generation')
|
cprefs = JSONConfig('cover_generation')
|
||||||
@@ -492,7 +492,7 @@ class Ornamental(Style):
|
|||||||
|
|
||||||
def __call__(self, painter, rect, color_theme, title_block, subtitle_block, footer_block):
|
def __call__(self, painter, rect, color_theme, title_block, subtitle_block, footer_block):
|
||||||
if not self.PATH_CACHE:
|
if not self.PATH_CACHE:
|
||||||
from calibre.utils.speedups import svg_path_to_painter_path
|
from ebook_converter.utils.speedups import svg_path_to_painter_path
|
||||||
try:
|
try:
|
||||||
self.__class__.PATH_CACHE['corner'] = svg_path_to_painter_path(self.CORNER_VECTOR)
|
self.__class__.PATH_CACHE['corner'] = svg_path_to_painter_path(self.CORNER_VECTOR)
|
||||||
except Exception:
|
except Exception:
|
||||||
@@ -728,7 +728,7 @@ def generate_masthead(title, output_path=None, width=600, height=60, as_qimage=F
|
|||||||
|
|
||||||
def test(scale=0.25):
|
def test(scale=0.25):
|
||||||
from PyQt5.Qt import QLabel, QPixmap, QMainWindow, QWidget, QScrollArea, QGridLayout
|
from PyQt5.Qt import QLabel, QPixmap, QMainWindow, QWidget, QScrollArea, QGridLayout
|
||||||
from calibre.gui2 import Application
|
from ebook_converter.gui2 import Application
|
||||||
app = Application([])
|
app = Application([])
|
||||||
mi = Metadata('Unknown', ['Kovid Goyal', 'John & Doe', 'Author'])
|
mi = Metadata('Unknown', ['Kovid Goyal', 'John & Doe', 'Author'])
|
||||||
mi.series = 'A series & styles'
|
mi.series = 'A series & styles'
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ __docformat__ = 'restructuredtext en'
|
|||||||
'''
|
'''
|
||||||
Conversion to EPUB.
|
Conversion to EPUB.
|
||||||
'''
|
'''
|
||||||
from calibre.utils.zipfile import ZipFile, ZIP_STORED
|
from ebook_converter.utils.zipfile import ZipFile, ZIP_STORED
|
||||||
|
|
||||||
|
|
||||||
def rules(stylesheets):
|
def rules(stylesheets):
|
||||||
|
|||||||
@@ -9,15 +9,15 @@ from collections import defaultdict
|
|||||||
from functools import partial
|
from functools import partial
|
||||||
|
|
||||||
from css_parser.css import CSSRule, CSSStyleDeclaration
|
from css_parser.css import CSSRule, CSSStyleDeclaration
|
||||||
from css_selectors import parse, SelectorSyntaxError
|
from ebook_converter.css_selectors import parse, SelectorSyntaxError
|
||||||
|
|
||||||
from calibre import force_unicode
|
from ebook_converter import force_unicode
|
||||||
from calibre.ebooks.oeb.base import OEB_STYLES, OEB_DOCS, XHTML, css_text
|
from ebook_converter.ebooks.oeb.base import OEB_STYLES, OEB_DOCS, XHTML, css_text
|
||||||
from calibre.ebooks.oeb.normalize_css import normalize_filter_css, normalizers
|
from ebook_converter.ebooks.oeb.normalize_css import normalize_filter_css, normalizers
|
||||||
from calibre.ebooks.oeb.polish.pretty import pretty_script_or_style, pretty_xml_tree, serialize
|
from ebook_converter.ebooks.oeb.polish.pretty import pretty_script_or_style, pretty_xml_tree, serialize
|
||||||
from calibre.utils.icu import numeric_sort_key
|
from ebook_converter.utils.icu import numeric_sort_key
|
||||||
from css_selectors import Select, SelectorError
|
from ebook_converter.css_selectors import Select, SelectorError
|
||||||
from polyglot.builtins import iteritems, itervalues, unicode_type, filter
|
from ebook_converter.polyglot.builtins import iteritems, itervalues, unicode_type, filter
|
||||||
|
|
||||||
|
|
||||||
def filter_used_rules(rules, log, select):
|
def filter_used_rules(rules, log, select):
|
||||||
|
|||||||
@@ -7,16 +7,16 @@ __copyright__ = '2013, Kovid Goyal <kovid at kovidgoyal.net>'
|
|||||||
__docformat__ = 'restructuredtext en'
|
__docformat__ = 'restructuredtext en'
|
||||||
|
|
||||||
import codecs, shutil, os, posixpath
|
import codecs, shutil, os, posixpath
|
||||||
from polyglot.builtins import iteritems, itervalues, map
|
from ebook_converter.polyglot.builtins import iteritems, itervalues, map
|
||||||
from functools import partial
|
from functools import partial
|
||||||
from collections import Counter, defaultdict
|
from collections import Counter, defaultdict
|
||||||
|
|
||||||
from calibre import sanitize_file_name
|
from ebook_converter import sanitize_file_name
|
||||||
from calibre.ebooks.chardet import strip_encoding_declarations
|
from ebook_converter.ebooks.chardet import strip_encoding_declarations
|
||||||
from calibre.ebooks.oeb.base import css_text
|
from ebook_converter.ebooks.oeb.base import css_text
|
||||||
from calibre.ebooks.oeb.polish.css import iter_declarations, remove_property_value
|
from ebook_converter.ebooks.oeb.polish.css import iter_declarations, remove_property_value
|
||||||
from calibre.ebooks.oeb.polish.utils import extract
|
from ebook_converter.ebooks.oeb.polish.utils import extract
|
||||||
from polyglot.urllib import urlparse, urlunparse
|
from ebook_converter.polyglot.urllib import urlparse, urlunparse
|
||||||
|
|
||||||
|
|
||||||
class LinkReplacer(object):
|
class LinkReplacer(object):
|
||||||
@@ -151,7 +151,7 @@ def replace_ids(container, id_map):
|
|||||||
|
|
||||||
|
|
||||||
def smarten_punctuation(container, report):
|
def smarten_punctuation(container, report):
|
||||||
from calibre.ebooks.conversion.preprocess import smarten_punctuation
|
from ebook_converter.ebooks.conversion.preprocess import smarten_punctuation
|
||||||
smartened = False
|
smartened = False
|
||||||
for path in container.spine_items:
|
for path in container.spine_items:
|
||||||
name = container.abspath_to_name(path)
|
name = container.abspath_to_name(path)
|
||||||
@@ -230,9 +230,9 @@ def replace_file(container, name, path, basename, force_mt=None):
|
|||||||
|
|
||||||
|
|
||||||
def mt_to_category(container, mt):
|
def mt_to_category(container, mt):
|
||||||
from calibre.ebooks.oeb.polish.utils import guess_type
|
from ebook_converter.ebooks.oeb.polish.utils import guess_type
|
||||||
from calibre.ebooks.oeb.polish.container import OEB_FONTS
|
from ebook_converter.ebooks.oeb.polish.container import OEB_FONTS
|
||||||
from calibre.ebooks.oeb.base import OEB_DOCS, OEB_STYLES
|
from ebook_converter.ebooks.oeb.base import OEB_DOCS, OEB_STYLES
|
||||||
if mt in OEB_DOCS:
|
if mt in OEB_DOCS:
|
||||||
category = 'text'
|
category = 'text'
|
||||||
elif mt in OEB_STYLES:
|
elif mt in OEB_STYLES:
|
||||||
@@ -253,7 +253,7 @@ def get_recommended_folders(container, names):
|
|||||||
recommendation is based on where the majority of files of the same type are
|
recommendation is based on where the majority of files of the same type are
|
||||||
located in the container. If no files of a particular type are present, the
|
located in the container. If no files of a particular type are present, the
|
||||||
recommended folder is assumed to be the folder containing the OPF file. '''
|
recommended folder is assumed to be the folder containing the OPF file. '''
|
||||||
from calibre.ebooks.oeb.polish.utils import guess_type
|
from ebook_converter.ebooks.oeb.polish.utils import guess_type
|
||||||
counts = defaultdict(Counter)
|
counts = defaultdict(Counter)
|
||||||
for name, mt in iteritems(container.mime_map):
|
for name, mt in iteritems(container.mime_map):
|
||||||
folder = name.rpartition('/')[0] if '/' in name else ''
|
folder = name.rpartition('/')[0] if '/' in name else ''
|
||||||
@@ -347,7 +347,7 @@ def remove_links_in_declaration(href_to_name, style, predicate):
|
|||||||
def remove_links_to(container, predicate):
|
def remove_links_to(container, predicate):
|
||||||
''' predicate must be a function that takes the arguments (name, href,
|
''' predicate must be a function that takes the arguments (name, href,
|
||||||
fragment=None) and returns True iff the link should be removed '''
|
fragment=None) and returns True iff the link should be removed '''
|
||||||
from calibre.ebooks.oeb.base import iterlinks, OEB_DOCS, OEB_STYLES, XPath, XHTML
|
from ebook_converter.ebooks.oeb.base import iterlinks, OEB_DOCS, OEB_STYLES, XPath, XHTML
|
||||||
stylepath = XPath('//h:style')
|
stylepath = XPath('//h:style')
|
||||||
styleattrpath = XPath('//*[@style]')
|
styleattrpath = XPath('//*[@style]')
|
||||||
changed = set()
|
changed = set()
|
||||||
|
|||||||
@@ -6,14 +6,14 @@ __license__ = 'GPL v3'
|
|||||||
__copyright__ = '2013, Kovid Goyal <kovid at kovidgoyal.net>'
|
__copyright__ = '2013, Kovid Goyal <kovid at kovidgoyal.net>'
|
||||||
|
|
||||||
import copy, os, re
|
import copy, os, re
|
||||||
from polyglot.builtins import map, string_or_bytes, range
|
from ebook_converter.polyglot.builtins import map, string_or_bytes, range
|
||||||
|
|
||||||
from calibre.ebooks.oeb.base import barename, XPNSMAP, XPath, OPF, XHTML, OEB_DOCS
|
from ebook_converter.ebooks.oeb.base import barename, XPNSMAP, XPath, OPF, XHTML, OEB_DOCS
|
||||||
from calibre.ebooks.oeb.polish.errors import MalformedMarkup
|
from ebook_converter.ebooks.oeb.polish.errors import MalformedMarkup
|
||||||
from calibre.ebooks.oeb.polish.toc import node_from_loc
|
from ebook_converter.ebooks.oeb.polish.toc import node_from_loc
|
||||||
from calibre.ebooks.oeb.polish.replace import LinkRebaser
|
from ebook_converter.ebooks.oeb.polish.replace import LinkRebaser
|
||||||
from polyglot.builtins import iteritems, unicode_type
|
from ebook_converter.polyglot.builtins import iteritems, unicode_type
|
||||||
from polyglot.urllib import urlparse
|
from ebook_converter.polyglot.urllib import urlparse
|
||||||
|
|
||||||
|
|
||||||
class AbortError(ValueError):
|
class AbortError(ValueError):
|
||||||
|
|||||||
@@ -8,11 +8,11 @@ __docformat__ = 'restructuredtext en'
|
|||||||
|
|
||||||
import textwrap
|
import textwrap
|
||||||
|
|
||||||
from calibre import guess_type
|
from ebook_converter import guess_type
|
||||||
from calibre.utils.imghdr import identify
|
from ebook_converter.utils.imghdr import identify
|
||||||
from calibre.utils.xml_parse import safe_xml_fromstring
|
from ebook_converter.utils.xml_parse import safe_xml_fromstring
|
||||||
from polyglot.builtins import unicode_type
|
from ebook_converter.polyglot.builtins import unicode_type
|
||||||
from polyglot.urllib import unquote
|
from ebook_converter.polyglot.urllib import unquote
|
||||||
|
|
||||||
|
|
||||||
class CoverManager(object):
|
class CoverManager(object):
|
||||||
@@ -84,39 +84,8 @@ class CoverManager(object):
|
|||||||
self.log = log
|
self.log = log
|
||||||
self.insert_cover()
|
self.insert_cover()
|
||||||
|
|
||||||
def default_cover(self):
|
|
||||||
'''
|
|
||||||
Create a generic cover for books that dont have a cover
|
|
||||||
'''
|
|
||||||
if self.no_default_cover:
|
|
||||||
return None
|
|
||||||
self.log('Generating default cover')
|
|
||||||
m = self.oeb.metadata
|
|
||||||
title = unicode_type(m.title[0])
|
|
||||||
authors = [unicode_type(x) for x in m.creator if x.role == 'aut']
|
|
||||||
try:
|
|
||||||
from calibre.ebooks.covers import create_cover
|
|
||||||
series = series_index = None
|
|
||||||
if m.series:
|
|
||||||
try:
|
|
||||||
series, series_index = unicode_type(m.series[0]), m.series_index[0]
|
|
||||||
except IndexError:
|
|
||||||
pass
|
|
||||||
img_data = create_cover(title, authors, series, series_index)
|
|
||||||
id, href = self.oeb.manifest.generate('cover',
|
|
||||||
'cover_image.jpg')
|
|
||||||
item = self.oeb.manifest.add(id, href, guess_type('t.jpg')[0],
|
|
||||||
data=img_data)
|
|
||||||
m.clear('cover')
|
|
||||||
m.add('cover', item.id)
|
|
||||||
|
|
||||||
return item.href
|
|
||||||
except:
|
|
||||||
self.log.exception('Failed to generate default cover')
|
|
||||||
return None
|
|
||||||
|
|
||||||
def inspect_cover(self, href):
|
def inspect_cover(self, href):
|
||||||
from calibre.ebooks.oeb.base import urlnormalize
|
from ebook_converter.ebooks.oeb.base import urlnormalize
|
||||||
for x in self.oeb.manifest:
|
for x in self.oeb.manifest:
|
||||||
if x.href == urlnormalize(href):
|
if x.href == urlnormalize(href):
|
||||||
try:
|
try:
|
||||||
@@ -127,14 +96,13 @@ class CoverManager(object):
|
|||||||
return -1, -1
|
return -1, -1
|
||||||
|
|
||||||
def insert_cover(self):
|
def insert_cover(self):
|
||||||
from calibre.ebooks.oeb.base import urldefrag
|
from ebook_converter.ebooks.oeb.base import urldefrag
|
||||||
g, m = self.oeb.guide, self.oeb.manifest
|
g, m = self.oeb.guide, self.oeb.manifest
|
||||||
item = None
|
item = None
|
||||||
|
href = None
|
||||||
if 'titlepage' not in g:
|
if 'titlepage' not in g:
|
||||||
if 'cover' in g:
|
if 'cover' in g:
|
||||||
href = g['cover'].href
|
href = g['cover'].href
|
||||||
else:
|
|
||||||
href = self.default_cover()
|
|
||||||
if href is None:
|
if href is None:
|
||||||
return
|
return
|
||||||
width, height = self.inspect_cover(href)
|
width, height = self.inspect_cover(href)
|
||||||
|
|||||||
@@ -10,8 +10,8 @@ import posixpath
|
|||||||
|
|
||||||
from lxml import etree
|
from lxml import etree
|
||||||
|
|
||||||
from calibre.ebooks.oeb.base import rewrite_links, urlnormalize
|
from ebook_converter.ebooks.oeb.base import rewrite_links, urlnormalize
|
||||||
from polyglot.urllib import urldefrag, urlparse
|
from ebook_converter.polyglot.urllib import urldefrag, urlparse
|
||||||
|
|
||||||
|
|
||||||
class RenameFiles(object): # {{{
|
class RenameFiles(object): # {{{
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ __license__ = 'GPL v3'
|
|||||||
__copyright__ = '2009, Kovid Goyal <kovid@kovidgoyal.net>'
|
__copyright__ = '2009, Kovid Goyal <kovid@kovidgoyal.net>'
|
||||||
__docformat__ = 'restructuredtext en'
|
__docformat__ = 'restructuredtext en'
|
||||||
|
|
||||||
from calibre import fit_image
|
from ebook_converter import fit_image
|
||||||
|
|
||||||
|
|
||||||
class RescaleImages(object):
|
class RescaleImages(object):
|
||||||
|
|||||||
@@ -15,14 +15,14 @@ from collections import OrderedDict
|
|||||||
from lxml.etree import XPath as _XPath
|
from lxml.etree import XPath as _XPath
|
||||||
from lxml import etree
|
from lxml import etree
|
||||||
|
|
||||||
from calibre import as_unicode, force_unicode
|
from ebook_converter import as_unicode, force_unicode
|
||||||
from calibre.ebooks.epub import rules
|
from ebook_converter.ebooks.epub import rules
|
||||||
from calibre.ebooks.oeb.base import (OEB_STYLES, XPNSMAP as NAMESPACES,
|
from ebook_converter.ebooks.oeb.base import (OEB_STYLES, XPNSMAP as NAMESPACES,
|
||||||
urldefrag, rewrite_links, XHTML, urlnormalize)
|
urldefrag, rewrite_links, XHTML, urlnormalize)
|
||||||
from calibre.ebooks.oeb.polish.split import do_split
|
from ebook_converter.ebooks.oeb.polish.split import do_split
|
||||||
from polyglot.builtins import iteritems, range, map, unicode_type
|
from ebook_converter.polyglot.builtins import iteritems, range, map, unicode_type
|
||||||
from polyglot.urllib import unquote
|
from ebook_converter.polyglot.urllib import unquote
|
||||||
from css_selectors import Select, SelectorError
|
from ebook_converter.css_selectors import Select, SelectorError
|
||||||
|
|
||||||
XPath = functools.partial(_XPath, namespaces=NAMESPACES)
|
XPath = functools.partial(_XPath, namespaces=NAMESPACES)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user