X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;f=lib%2Fscripts%2Fdocbook2epub.py;h=0e9d268a473288a361977aeadc47078349bc1d40;hb=940d3ceeb9e6d8ce216afedf18c898ec075cc27d;hp=e60a9d482c9a3d460dff64b2e2248344d2b4cd6e;hpb=6a99e885652ff68f89746ff65772718bd52b812d;p=lyx.git diff --git a/lib/scripts/docbook2epub.py b/lib/scripts/docbook2epub.py index e60a9d482c..0e9d268a47 100644 --- a/lib/scripts/docbook2epub.py +++ b/lib/scripts/docbook2epub.py @@ -9,62 +9,195 @@ # Full author contact details are available in file CREDITS # Usage: -# python docbook2epub.py in.docbook out.epub +# python docbook2epub.py java_binary saxon_path xsltproc_path xslt_path in.docbook in.orig.path out.epub from __future__ import print_function +import glob import os import shutil import sys import tempfile import zipfile -import glob +from io import open # Required for Python 2. -if __name__ == '__main__': - if len(sys.argv) != 4: - sys.exit(1) - own_path, java_path, input, output = sys.argv - script_folder = os.path.dirname(own_path) + '/../' - - print('Generating ePub:') - print(own_path) - print(input) - print(output) - - output_dir = tempfile.mkdtemp().replace('\\', '/') - print('Temporary output directory:') - print(output_dir) - - # Start the XSLT transformation. - xslt = script_folder + 'docbook/epub3/chunk.xsl' - saxon_jar = script_folder + 'scripts/saxon6.5.5.jar' - saxon_params = 'base.dir=%s' % output_dir - command = '"' + java_path + '" -jar "' + saxon_jar + '" ' + input + ' ' + xslt + ' ' + saxon_params - - print('XSLT style sheet to use:') - print(xslt) - print('Command to execute:') - print(command) - - quoted_command = command - if os.name == 'nt': - # On Windows, it is typical to have spaces in folder names, and that requires to wrap the whole command - # in quotes. On Linux, this might create errors when starting the command. - quoted_command = '"' + command + '"' - - if os.system(quoted_command) != 0: - print('docbook2epub fails') - shutil.rmtree(output_dir, ignore_errors=True) + +def _parse_nullable_argument(arg): + return arg if arg != '' and arg != 'none' else None + + +class ImageRename: + def __init__(self, opf_path, local_path, epub_path): + self.opf_path = opf_path + self.local_path = local_path + self.epub_path = epub_path + + +class DocBookToEpub: + def __init__(self, args=None): + if args is None: + args = sys.argv + + if len(args) != 8: + print('Exactly eight arguments are expected, only %s found: %s.' % (len(args), args)) + sys.exit(1) + + self.own_path = sys.argv[0] + self.java_path = _parse_nullable_argument(sys.argv[1]) + self.saxon_path = _parse_nullable_argument(sys.argv[2]) + self.xsltproc_path = _parse_nullable_argument(sys.argv[3]) + self.xslt_path = _parse_nullable_argument(sys.argv[4]) + self.input = sys.argv[5] + self.input_path = sys.argv[6] + self.output = sys.argv[7] + self.script_folder = os.path.dirname(self.own_path) + '/../' + + print('Generating ePub with the following parameters:') + print(self.own_path) + print(self.java_path) + print(self.saxon_path) + print(self.xsltproc_path) + print(self.xslt_path) + print(self.input) + print(self.input_path) + print(self.output) + + # Precompute paths that will be used later. + self.output_dir = tempfile.mkdtemp().replace('\\', '/') + self.package_opf = self.output_dir + '/OEBPS/package.opf' # Does not exist yet, + print('Temporary output directory: %s' % self.output_dir) + + if self.xslt_path is None: + self.xslt = self.script_folder + 'docbook/epub3/chunk.xsl' + else: + self.xslt = self.xslt_path + '/epub3/chunk.xsl' + print('XSLT style sheet to use:') + print(self.xslt) + + if self.saxon_path is None: + self.saxon_path = self.script_folder + 'scripts/saxon6.5.5.jar' + + # These will be filled during the execution of the script. + self.renamed = None + + def gracefully_fail(self, reason): + print('docbook2epub fails: %s' % reason) + shutil.rmtree(self.output_dir, ignore_errors=True) sys.exit(1) - print('Generated ePub contents.') + def start_xslt_transformation(self): + command = None + if self.xsltproc_path is not None: + command = self.start_xslt_transformation_xsltproc() + elif self.java_path is not None: + command = self.start_xslt_transformation_saxon6() + + if command is None: + self.gracefully_fail('no XSLT processor available') + + print('Command to execute:') + print(command) + + quoted_command = command + if os.name == 'nt': + # On Windows, it is typical to have spaces in folder names, and that requires to wrap the whole command + # in quotes. On Linux, this might create errors when starting the command. + quoted_command = '"' + command + '"' + # This could be simplified by using subprocess.run, but this requires Python 3.5. - # TODO: Copy the assets to the OEBPS/images/. + if os.system(quoted_command) != 0: + self.gracefully_fail('error from the XSLT processor') - # Create the actual ePub file. - with zipfile.ZipFile(output, 'w', zipfile.ZIP_DEFLATED) as zip: - for file in glob.glob(output_dir + '/**/*', recursive=True): - zip.write(file, os.path.relpath(file, output_dir), compress_type=zipfile.ZIP_STORED) + print('Generated ePub contents.') - shutil.rmtree(output_dir) - print('Generated ePub.') + def start_xslt_transformation_xsltproc(self): + params = '-stringparam base.dir "' + self.output_dir + '"' + return '"' + self.xsltproc_path + '" ' + params + ' "' + self.xslt + '" "' + self.input + '"' + + def start_xslt_transformation_saxon6(self): + params = 'base.dir=%s' % self.output_dir + executable = '"' + self.java_path + '" -jar "' + self.saxon_path + '"' + return executable + ' "' + self.input + '" "' + self.xslt + '" "' + params + '"' + + def get_images_from_package_opf(self): + images = [] + + # Example in the OPF file: + # + # The XHTML files are also tags: + # + try: + with open(self.package_opf, 'r') as f: + for line in f.readlines(): + if ' file in the ePub archive. + self.renamed = self.get_image_changes() + + # Then, transform all paths (both OPF and XHTML files). + self.change_image_paths(self.output_dir + '/OEBPS/package.opf') + for file in glob.glob(self.output_dir + '/OEBPS/*.xhtml'): + self.change_image_paths(file) + + # Ensure that the destination path exists. OEBPS exists due to the DocBook-to-ePub transformation. + if not os.path.exists(self.output_dir + '/OEBPS/images/'): + os.mkdir(self.output_dir + '/OEBPS/images/') + + # Finally, actually copy the image files. + for change in self.renamed: + shutil.copyfile(change.local_path, self.output_dir + '/OEBPS/' + change.epub_path) + + def create_zip_archive(self): + with zipfile.ZipFile(self.output, 'w', zipfile.ZIP_DEFLATED) as zip: + # Python 3.5 brings the `recursive` argument. For older versions, this trick is required... + # for file in glob.glob(output_dir + '/**/*', recursive=True): + for file in [os.path.join(dp, f) for dp, dn, filenames in os.walk(self.output_dir) for f in filenames]: + zip.write(file, os.path.relpath(file, self.output_dir), compress_type=zipfile.ZIP_STORED) + + shutil.rmtree(self.output_dir) + print('Generated ePub.') + + def transform(self): + self.start_xslt_transformation() + self.copy_images() + self.create_zip_archive() + + +if __name__ == '__main__': + DocBookToEpub(sys.argv).transform()