#!/usr/bin/env python # -*- coding: utf-8 -*- # vim:ts=4:sw=4:softtabstop=4:smarttab:expandtab from __future__ import unicode_literals, division, absolute_import, print_function from .compatibility_utils import unicode_str from loguru import logger from .unipath import pathof import os import imghdr import struct # note: struct pack, unpack, unpack_from all require bytestring format # data all the way up to at least python 2.7.5, python 3 okay with bytestring USE_SVG_WRAPPER = True """ Set to True to use svg wrapper for default. """ FORCE_DEFAULT_TITLE = False """ Set to True to force to use the default title. """ COVER_PAGE_FINENAME = "cover_page.xhtml" """ The name for the cover page. """ DEFAULT_TITLE = "Cover" """ The default title for the cover page. """ MAX_WIDTH = 4096 """ The max width for the svg cover page. """ MAX_HEIGHT = 4096 """ The max height for the svg cover page. """ def get_image_type(imgname, imgdata=None): imgtype = unicode_str(imghdr.what(pathof(imgname), imgdata)) # imghdr only checks for JFIF or Exif JPEG files. Apparently, there are some # with only the magic JPEG bytes out there... # ImageMagick handles those, so, do it too. if imgtype is None: if imgdata is None: with open(pathof(imgname), "rb") as f: imgdata = f.read() if imgdata[0:2] == b"\xFF\xD8": # Get last non-null bytes last = len(imgdata) while imgdata[last - 1 : last] == b"\x00": last -= 1 # Be extra safe, check the trailing bytes, too. if imgdata[last - 2 : last] == b"\xFF\xD9": imgtype = "jpeg" return imgtype def get_image_size(imgname, imgdata=None): """Determine the image type of imgname (or imgdata) and return its size. Originally, Determine the image type of fhandle and return its size. from draco""" if imgdata is None: fhandle = open(pathof(imgname), "rb") head = fhandle.read(24) else: head = imgdata[0:24] if len(head) != 24: return imgtype = get_image_type(imgname, imgdata) if imgtype == "png": check = struct.unpack(b">i", head[4:8])[0] if check != 0x0D0A1A0A: return width, height = struct.unpack(b">ii", head[16:24]) elif imgtype == "gif": width, height = struct.unpack(b"H", fhandle.read(2))[0] - 2 # We are at a SOFn block fhandle.seek(1, 1) # Skip `precision' byte. height, width = struct.unpack(b">HH", fhandle.read(4)) except Exception: # IGNORE:W0703 return elif imgtype == "jpeg" and imgdata is not None: try: pos = 0 size = 2 ftype = 0 while not 0xC0 <= ftype <= 0xCF: pos += size byte = imgdata[pos : pos + 1] pos += 1 while ord(byte) == 0xFF: byte = imgdata[pos : pos + 1] pos += 1 ftype = ord(byte) size = struct.unpack(b">H", imgdata[pos : pos + 2])[0] - 2 pos += 2 # We are at a SOFn block pos += 1 # Skip `precision' byte. height, width = struct.unpack(b">HH", imgdata[pos : pos + 4]) pos += 4 except Exception: # IGNORE:W0703 return else: return return width, height # XXX experimental class CoverProcessor(object): """Create a cover page. """ def __init__(self, files, metadata, rscnames, imgname=None, imgdata=None): self.files = files self.metadata = metadata self.rscnames = rscnames self.cover_page = COVER_PAGE_FINENAME self.use_svg = USE_SVG_WRAPPER # Use svg wrapper. self.lang = metadata.get("Language", ["en"])[0] # This should ensure that if the methods to find the cover image's # dimensions should fail for any reason, the SVG routine will not be used. [self.width, self.height] = (-1, -1) if FORCE_DEFAULT_TITLE: self.title = DEFAULT_TITLE else: self.title = metadata.get("Title", [DEFAULT_TITLE])[0] self.cover_image = None if imgname is not None: self.cover_image = imgname elif "CoverOffset" in metadata: imageNumber = int(metadata["CoverOffset"][0]) cover_image = self.rscnames[imageNumber] if cover_image is not None: self.cover_image = cover_image else: logger.debug("Warning: Cannot identify the cover image.") if self.use_svg: try: if imgdata is None: fname = os.path.join(files.imgdir, self.cover_image) [self.width, self.height] = get_image_size(fname) else: [self.width, self.height] = get_image_size(None, imgdata) except: self.use_svg = False width = self.width height = self.height if width < 0 or height < 0 or width > MAX_WIDTH or height > MAX_HEIGHT: self.use_svg = False return def getImageName(self): return self.cover_image def getXHTMLName(self): return self.cover_page def buildXHTML(self): logger.debug("Building a cover page.") files = self.files cover_image = self.cover_image title = self.title lang = self.lang image_dir = os.path.normpath(os.path.relpath(files.k8images, files.k8text)) image_path = os.path.join(image_dir, cover_image).replace("\\", "/") if not self.use_svg: data = "" data += '' data += '