No styles for cover?
dajames-mk1 opened this issue · 5 comments
I'm trying to create ePub versions of a periodical using ebooklib. I want to set a style for the cover page, and to do that I've set a cover template like this (it's based on the default cover template):
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:epub="http://www.idpf.org/2007/ops" lang="en" xml:lang="en">
<head>
<link href="../styles/mystylesheet.css" rel="stylesheet" type="text/css"/>
</head>
<body>
<img class="cover" src="" alt="" />
</body>
</html>
However, when I examine the created ePub file I find this:
<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:epub="http://www.idpf.org/2007/ops" epub:prefix="z3998: http://www.daisy.org/z3998/2012/vocab/structure/#" lang="en-GB" xml:lang="en-GB">
<head>
<title>Cover</title>
</head>
<body><img class="cover" src="Cover169.png" alt="Cover"/>
</body>
</html>
That is, the <link>
tag I put into the <head>
tag is missing.
Looking into this a bit more deeply, I find that the <head>
section of the cover page is always reduced to just the title, even when using the default template (which contains some <style>
tags that are removed).
Is it possible to actually set a style for the cover image?
I worked around this issue by creating my own cover page, using the following code (based on the code in the library)
def add_journal_cover( book, cover_name ):
'''
Add the cover to the journal
book is the ebook
cover_name is the name of the image file on disk for the cover.
We do NOT simply use ebooklib's function for this, as it loses the syle-sheet
reference from the <head> of the page, and sets the cover to be non-linear
in the spine listing (so Calibre shows it at the end!)
'''
# Set the book cover template
cover_template = six.b('''<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:epub="http://www.idpf.org/2007/ops" lang="en" xml:lang="en">
<body>
<div id="cover-image">
<p><img class="cover" src="" alt="" /></p>
</div>
</body>
</html>''')
book.set_template( name='cover', value=cover_template )
# Add the cover itself
# First check that the specified image exists
cover_image_path = Path( cover_name )
if not cover_image_path.exists():
print( '*** Cover image', cover_name, 'does not exist ***')
exit(1)
# internal filename for image - e.g. media/Cover01-2.png
internal_image_name = 'media/'+cover_name
# internal filename for html - e.g. text/Cover01-2.xhtml
internal_html_name = 'text/'+cover_image_path.stem+'.xhtml'
# Add the cover image to the book
cover = epub.EpubCover( uid='cover-img', file_name=internal_image_name )
cover.content = cover_image_path.read_bytes()
book.add_item( cover )
# Add the cover HTML - explicitly but using the template we gave ebooklib
cover_page = epub.EpubCoverHtml(
uid='cover',
file_name=internal_html_name,
image_name='../'+internal_image_name )
cover_page.add_item( doc_style_ref )
cover_page.is_linear = True # default is False
book.add_item( cover_page )
book.add_metadata( None, 'meta', '', epub.OrderedDict([('name', 'cover'), ('content', 'cover-img')]) )
(doc_style_ref is a global EpubItem referencing the CSS at ../style/mystyle.css, used by all the chapters in the journal)
This seems to work, but it feels ... fragile ... in the face of possible future changes to the library.
Hey, boy. I met the same problem before. This problem can be categorized as:
How to declare external css file to link to a certain EpubHtml instance?
The EpubHtml instance can be nav.xhtml
or cover.xhtml
or chapter-xxxx.xhtml
.
Finally I found a workaround. I post it to here, hope thas helps.
- ebooklib 0.17.1
# add navigation files
book.add_item(epub.EpubNcx())
book.add_item(epub.EpubNav())
# add cover css
cover_style = 'body { background-color: #e1e1e1;}'
cover_css = epub.EpubItem(uid="style_cover", file_name="style/cover.css", media_type="text/css", content=cover_style)
cover_html = book.get_item_with_id('cover')
cover_html.add_item(cover_css)
book.add_item(cover_css)
# write book
I think the key step is this line:
cover_html.add_item(cover_css)
It let cover_html instance to add a css item, because cover_html is an EpubHtml instance and each EpubHtml instance has add_item() function.
references
class EpubHtml(EpubItem):
def add_item(self, item):
"""
Add other item to this document. It will create additional links according to the item type.
:Args:
- item: item we want to add defined as instance of EpubItem
"""
if item.get_type() == ebooklib.ITEM_STYLE:
self.add_link(href=item.get_name(), rel='stylesheet', type='text/css')
if item.get_type() == ebooklib.ITEM_SCRIPT:
self.add_link(src=item.get_name(), type='text/javascript')
If you want full control over your cover page then you should just recreate what method set_cover is doing but if you just want to add CSS style then you can do it this way.
EpubCoverHtml
behaves exactly like EpubHtml
and will ignore whatever you have defined in header tag inside your template. To add something to it just use EpubHtml.add_item()
method. So @wdpm 's workaround is the best solution for it.
For example you could also combine .set_cover() and add_item():
# add cover image
book.set_cover("image.jpg", open('cover.jpg', 'rb').read())
# html page with uid=cover is created and added to the book
# just fetch it now
cover = book.get_item_with_id('cover')
# create new CSS file
st = 'BODY { background-color: #ff00ff; }'
cover_css = epub.EpubItem(uid='cover_style', file_name="style/cover.css", media_type="text/css", content=st)
# add that file to the book
book.add_item(cover_css)
# add that file to the Cover page so we can add it as a <link> when generating final html for the cover page
cover.add_item(cover_css)
@aerkalov Thank for you reply.
Although the solution above is a feasible workaround, but at the very start I had a lot of difficulties and tried a lot.
Because I can't find any document about setting cover/nav styles. Wouldn't it be better to add this in the documentation tutorial?
I think that setting styles is a very common functional requirement for using ebooklib.