1 if not modules then modules = { } end modules ['mtx-epub'] = {
2 version = 1.001,
3 comment = "companion to mtxrun.lua",
4 author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
5 copyright = "PRAGMA ADE / ConTeXt Development Team",
6 license = "see context related readme files"
7}
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77local format, gsub, find = string.format, string.gsub, string.find
78local concat, sortedhash = table.concat, table.sortedhash
79
80local formatters = string.formatters
81local longtostring = string.longtostring
82local replacetemplate = utilities.templates.replace
83
84local addsuffix = file.addsuffix
85local nameonly = file.nameonly
86local basename = file.basename
87local pathpart = file.pathpart
88local joinfile = file.join
89local suffix = file.suffix
90local addsuffix = file.addsuffix
91local removesuffix = file.removesuffix
92local replacesuffix = file.replacesuffix
93
94local copyfile = file.copy
95local removefile = os.remove
96
97local needsupdating = file.needsupdating
98
99local isdir = lfs.isdir
100local isfile = lfs.isfile
101local mkdir = lfs.mkdir
102
103local pushdir = dir.push
104local popdir = dir.pop
105
106local helpinfo = [[
107<?xml version="1.0"?>
108<application>
109 <metadata>
110 <entry name="name">mtx-epub</entry>
111 <entry name="detail">ConTeXt EPUB Helpers</entry>
112 <entry name="version">1.10</entry>
113 </metadata>
114 <flags>
115 <category name="basic">
116 <subcategory>
117 <flag name="make"><short>create epub zip file</short></flag>
118 <flag name="purge"><short>remove obsolete files</short></flag>
119 <flag name="rename"><short>rename images to sane names</short></flag>
120 <flag name="svgmath"><short>convert mathml to svg</short></flag>
121 <flag name="svgstyle"><short>use given tex style for svg generation (overloads style in specification)</short></flag>
122 <flag name="all"><short>assume: --purge --rename --svgmath (for fast testing)</short></flag>
123 <flag name="images"><short>convert images to svg [--fix]</short></flag>
124 </subcategory>
125 </category>
126 </flags>
127 <examples>
128 <category>
129 <title>Example</title>
130 <subcategory>
131 <example><command>mtxrun --script epub --make mydocument</command></example>
132 </subcategory>
133 <subcategory>
134 <example><command>mtxrun --script epub --images mydocument</command></example>
135 <example><command>mtxrun --script epub --images --fix mydocument</command></example>
136 </subcategory>
137 </category>
138 </examples>
139</application>
140]]
141
142local application = logs.application {
143 name = "mtx-epub",
144 banner = "ConTeXt EPUB Helpers 1.10",
145 helpinfo = helpinfo,
146}
147
148local report = application.report
149
150
151
152scripts = scripts or { }
153scripts.epub = scripts.epub or { }
154
155local mimetype = "application/epub+zip"
156
157local t_container = [[
158<?xml version="1.0" encoding="UTF-8"?>
159
160<container version="1.0" xmlns="urn:oasis:names:tc:opendocument:xmlns:container">
161 <rootfiles>
162 <rootfile full-path="OEBPS/%rootfile%" media-type="application/oebps-package+xml"/>
163 </rootfiles>
164</container>
165]]
166
167
168
169
170
171local t_package = [[
172<?xml version="1.0" encoding="UTF-8"?>
173
174<package xmlns="http://www.idpf.org/2007/opf" unique-identifier="%identifier%" version="3.0">
175
176 <metadata xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:opf="http://www.idpf.org/2007/opf">
177 <dc:title>%title%</dc:title>
178 <dc:language>%language%</dc:language>
179 <dc:identifier id="%identifier%">%uuid%</dc:identifier>
180 <dc:creator>%creator%</dc:creator>
181 <dc:date>%date%</dc:date>
182 <!--
183 <dc:subject>%subject%</dc:subject>
184 <dc:description>%description%</dc:description>
185 <dc:publisher>%publisher%</dc:publisher>
186 <dc:source>%source%</dc:source>
187 <dc:relation>%relation%</dc:relation>
188 <dc:coverage>%coverage%</dc:coverage>
189 <dc:rights>%rights%</dc:rights>
190 -->
191 <meta name="cover" content="%coverpage%" />
192 <meta name="generator" content="ConTeXt MkIV" />
193 <meta property="dcterms:modified">%date%</meta>
194 </metadata>
195
196 <manifest>
197%manifest%
198 </manifest>
199
200 <spine toc="ncx">
201 <itemref idref="cover-xhtml" />
202 <itemref idref="%rootfile%" />
203 </spine>
204
205</package>
206]]
207
208
209local t_item = [[ <item id="%id%" href="%filename%" media-type="%mime%" />]]
210local t_prop = [[ <item id="%id%" href="%filename%" media-type="%mime%" properties="%properties%" />]]
211
212
213
214local t_toc = [[
215<?xml version="1.0" encoding="UTF-8"?>
216
217<!-- this is no longer needed in epub 3.0+ -->
218
219<ncx xmlns="http://www.daisy.org/z3986/2005/ncx/" version="2005-1">
220
221 <head>
222 <meta name="generator" content="ConTeXt MkIV" />
223 <meta name="dtb:uid" content="%identifier%" />
224 <meta name="dtb:depth" content="2" />
225 <meta name="dtb:totalPgeCount" content="0" />
226 <meta name="dtb:maxPageNumber" content="0" />
227 </head>
228
229 <docTitle>
230 <text>%title%</text>
231 </docTitle>
232
233 <docAuthor>
234 <text>%author%</text>
235 </docAuthor>
236
237 <navMap>
238 <navPoint id="np-1" playOrder="1">
239 <navLabel>
240 <text>start</text>
241 </navLabel>
242 <content src="%root%"/>
243 </navPoint>
244 </navMap>
245
246</ncx>
247]]
248
249local t_navtoc = [[
250<?xml version="1.0" encoding="UTF-8"?>
251
252<html xmlns="http://www.w3.org/1999/xhtml" xmlns:epub="http://www.idpf.org/2007/ops">
253 <head>
254 <meta charset="utf-8" />
255 <title>navtoc</title>
256 </head>
257 <body>
258 <div class="navtoc">
259 <!-- <nav epub:type="lot"> -->
260 <nav epub:type="toc" id="navtoc">
261 <ol>
262 <li><a href="%root%">document</a></li>
263 </ol>
264 </nav>
265 </div>
266 </body>
267</html>
268]]
269
270
271
272
273local t_coverxhtml = [[
274<?xml version="1.0" encoding="UTF-8"?>
275
276<html xmlns="http://www.w3.org/1999/xhtml">
277 <head>
278 <meta charset="utf-8" />
279 <title>cover page</title>
280 </head>
281 <body>
282 <div class="coverpage">
283 %content%
284 </div>
285 </body>
286</html>
287]]
288
289local t_coverimg = [[
290 <img src="%image%" alt="The cover image" style="max-width: 100%%;" />
291]]
292
293
294
295
296
297
298
299
300local function dumbid(filename)
301
302 return nameonly(filename) .. "-" .. suffix(filename)
303end
304
305local mimetypes = {
306 xhtml = "application/xhtml+xml",
307 xml = "application/xhtml+xml",
308 html = "application/html",
309 css = "text/css",
310 svg = "image/svg+xml",
311 png = "image/png",
312 jpg = "image/jpeg",
313 ncx = "application/x-dtbncx+xml",
314 gif = "image/gif",
315
316}
317
318local idmakers = {
319 ncx = function(filename) return "ncx" end,
320
321 default = function(filename) return dumbid(filename) end,
322}
323
324local function relocateimages(imagedata,oldname,newname,subpath,rename)
325 local data = io.loaddata(oldname)
326 if data then
327 subpath = joinfile("..",subpath)
328 report("relocating images")
329 local n = 0
330 local done = gsub(data,[[(id=")(.-)(".-background%-image *: *url%()(.-)(%))]], function(s1,id,s2,name,s3)
331 local data = imagedata[id]
332 if data then
333 local newname = data[id].newname
334 if newname then
335 if subpath then
336 name = joinfile(subpath,basename(newname))
337 else
338 name = basename(newname)
339 end
340
341 end
342 if newname then
343 n = n + 1
344 if rename then
345 name = joinfile(subpath,addsuffix(id,suffix(name)))
346 end
347 return s1 .. id .. s2 .. name .. s3
348 end
349 end
350 end)
351 report("%s images relocated in %a",n,newname)
352 if newname then
353 io.savedata(newname,done)
354 end
355 end
356 return images
357end
358
359function reportobsolete(oldfiles,newfiles,purge)
360
361 for i=1,#oldfiles do oldfiles[i] = gsub(oldfiles[i],"^[%./]+","") end
362 for i=1,#newfiles do newfiles[i] = gsub(newfiles[i],"^[%./]+","") end
363
364 local old = table.tohash(oldfiles)
365 local new = table.tohash(newfiles)
366 local done = false
367
368 for name in sortedhash(old) do
369 if not new[name] then
370 if not done then
371 report()
372 if purge then
373 report("removing obsolete files:")
374 else
375 report("obsolete files:")
376 end
377 report()
378 done = true
379 end
380 report(" %s",name)
381 if purge then
382 removefile(name)
383 end
384 end
385 end
386
387 if done then
388 report()
389 end
390
391 return done
392
393end
394
395
396local zippers = {
397 {
398 name = "zip",
399 binary = "zip",
400 uncompressed = "zip %s -X -0 %s",
401 compressed = "zip %s -X -9 -r %s",
402 },
403 {
404 name = "7z (7zip)",
405 binary = "7z",
406 uncompressed = "7z a -tzip -mx0 %s %s",
407 compressed = "7z a -tzip %s %s",
408 },
409}
410
411function scripts.epub.make(purge,rename,svgmath,svgstyle)
412
413
414
415
416 local filename = environment.files[1]
417
418 if not filename or filename == "" or type(filename) ~= "string" then
419 report("provide filename")
420 return
421 end
422
423 local specpath, specname, specfull
424
425 if isdir(filename) then
426 specpath = filename
427 specname = addsuffix(specpath,"lua")
428 specfull = joinfile(specpath,specname)
429 end
430
431 if not specfull or not isfile(specfull) then
432 specpath = filename .. "-export"
433 specname = addsuffix(filename .. "-pub","lua")
434 specfull = joinfile(specpath,specname)
435 end
436
437 if not specfull or not isfile(specfull) then
438 report("unknown specificaton file %a for %a",specfull or "?",filename)
439 return
440 end
441
442 local specification = dofile(specfull)
443
444 if not specification or not next(specification) then
445 report("invalid specificaton file %a",specfile)
446 return
447 end
448
449 report("using specification file %a",specfull)
450
451
452
453 local defaultcoverpage = "cover.xhtml"
454
455 local name = specification.name or nameonly(filename)
456 local identifier = specification.identifier or ""
457 local htmlfiles = specification.htmlfiles or { }
458 local styles = specification.styles or { }
459 local images = specification.images or { }
460 local htmlroot = specification.htmlroot or htmlfiles[1] or ""
461 local language = specification.language or "en"
462 local creator = specification.creator or "context mkiv"
463 local author = specification.author or "anonymous"
464 local title = specification.title or name
465 local subtitle = specification.subtitle or ""
466 local imagefile = specification.imagefile or ""
467 local imagepath = specification.imagepath or "images"
468 local stylepath = specification.stylepath or "styles"
469 local coverpage = specification.firstpage or defaultcoverpage
470
471 if type(svgstyle) == "string" and not svgstyle then
472 svgstyle = specification.svgstyle or ""
473 end
474
475 local obsolete = false
476
477 if #htmlfiles == 0 then
478 report("no html files specified")
479 return
480 end
481 if htmlroot == "" then
482 report("no html root file specified")
483 return
484 end
485
486 if subtitle ~= "" then
487 title = format("%s, %s",title,subtitle)
488 end
489
490 local htmlsource = specpath
491 local imagesource = joinfile(specpath,imagepath)
492 local stylesource = joinfile(specpath,stylepath)
493
494
495
496
497
498
499
500
501
502
503
504
505
506 local pdftosvg = os.which("mutool") and formatters[ [[mutool draw -o "%s" "%s" %s]] ]
507
508 local f_svgpage = formatters["%s-page-%s.svg"]
509 local f_svgname = formatters["%s.svg"]
510
511 local notupdated = 0
512 local updated = 0
513 local skipped = 0
514 local oldfiles = dir.glob(file.join(imagesource,"*"))
515 local newfiles = { }
516
517 if not pdftosvg then
518 report("the %a binary is not present","mutool")
519 end
520
521
522
523 if not coverpage then
524 report("no cover page (image) defined")
525 elseif suffix(coverpage) ~= "xhtml" then
526 report("using cover page %a",coverpage)
527 local source = coverpage
528 local target = joinfile(htmlsource,coverpage)
529 htmlfiles[#htmlfiles+1 ] = coverpage
530 report("copying coverpage %a to %a",source,target)
531 copyfile(source,target)
532 elseif isfile(coverpage) then
533 report("using cover page image %a",coverpage)
534 images.cover = {
535 height = "100%",
536 width = "100%",
537 page = "1",
538 name = url.filename(coverpage),
539 used = coverpage,
540 }
541 local data = replacetemplate(t_coverxhtml, {
542 content = replacetemplate(t_coverimg, {
543 image = coverpage,
544 })
545 })
546 coverpage = defaultcoverpage
547 local target = joinfile(htmlsource,coverpage)
548 report("saving coverpage to %a",target)
549 io.savedata(target,data)
550 htmlfiles[#htmlfiles+1 ] = coverpage
551 else
552 report("cover page image %a is not present",coverpage)
553 coverpage = false
554 end
555
556 if not coverpage then
557 local data = replacetemplate(t_coverxhtml, {
558 content = "no cover page"
559 })
560 coverpage = defaultcoverpage
561 local target = joinfile(htmlsource,coverpage)
562 report("saving dummy coverpage to %a",target)
563 io.savedata(target,data)
564 htmlfiles[#htmlfiles+1 ] = coverpage
565 end
566
567 for id, data in sortedhash(images) do
568 local name = url.filename(data.name)
569 local used = url.filename(data.used)
570 local base = basename(used)
571 local page = tonumber(data.page) or 1
572
573 if suffix(used) == "pdf" then
574
575 if page > 1 then
576 name = f_svgpage(nameonly(name),page)
577 else
578 name = f_svgname(nameonly(name))
579 end
580 local source = used
581 local target = joinfile(imagesource,name)
582 if needsupdating(source,target) then
583 if pdftosvg then
584 local command = pdftosvg(target,source,page)
585 report("running command %a",command)
586 os.execute(command)
587 updated = updated + 1
588 else
589 skipped = skipped + 1
590 end
591 else
592 notupdated = notupdated + 1
593 end
594 newfiles[#newfiles+1] = target
595 else
596 name = basename(used)
597 local source = used
598 local target = joinfile(imagesource,name)
599 if needsupdating(source,target) then
600 report("copying %a to %a",source,target)
601 copyfile(source,target)
602 updated = updated + 1
603 else
604 notupdated = notupdated + 1
605
606 end
607 newfiles[#newfiles+1] = target
608 end
609 local target = newfiles[#newfiles]
610 if suffix(target) == "svg" and isfile(target) then
611 local data = io.loaddata(target)
612 if data then
613 local done = gsub(data,"<!(DOCTYPE.-)>","<!-- %1 -->",1)
614 if data ~= done then
615 report("doctype fixed in %a",target)
616 io.savedata(target,data)
617 end
618 end
619 end
620 data.newname = name
621 end
622
623 report("%s images checked, %s updated, %s kept, %s skipped",updated + notupdated + skipped,updated,notupdated,skipped)
624
625 if reportobsolete(oldfiles,newfiles,purge) then
626 obsolete = true
627 end
628
629
630
631 local uuid = format("urn:uuid:%s",os.uuid(true))
632 local identifier = "bookid"
633
634 local epubname = removesuffix(name)
635 local epubpath = name .. "-epub"
636 local epubfile = replacesuffix(name,"epub")
637 local epubroot = replacesuffix(name,"opf")
638 local epubtoc = "toc.ncx"
639 local epubmimetypes = "mimetype"
640 local epubcontainer = "container.xml"
641 local epubnavigator = "nav.xhtml"
642
643 local metapath = "META-INF"
644 local datapath = "OEBPS"
645
646 local oldfiles = dir.glob(file.join(epubpath,"**/*"))
647 local newfiles = { }
648
649 report("creating paths in tree %a",epubpath)
650
651 if not isdir(epubpath) then
652 mkdir(epubpath)
653 end
654 if not isdir(epubpath) then
655 report("unable to create path %a",epubpath)
656 return
657 end
658
659 local metatarget = joinfile(epubpath,metapath)
660 local htmltarget = joinfile(epubpath,datapath)
661 local styletarget = joinfile(epubpath,datapath,stylepath)
662 local imagetarget = joinfile(epubpath,datapath,imagepath)
663
664 mkdir(metatarget)
665 mkdir(htmltarget)
666 mkdir(styletarget)
667 mkdir(imagetarget)
668
669 local used = { }
670 local notupdated = 0
671 local updated = 0
672
673 local oldimagespecification = joinfile(htmlsource,imagefile)
674 local newimagespecification = joinfile(htmltarget,imagefile)
675
676 report("removing %a",newimagespecification)
677
678
679 local function registerone(path,filename,mathml)
680 local suffix = suffix(filename)
681 local mime = mimetypes[suffix]
682 if mime then
683 local idmaker = idmakers[suffix] or idmakers.default
684 local fullname = path and joinfile(path,filename) or filename
685 if mathml then
686 used[#used+1] = replacetemplate(t_prop, {
687 id = idmaker(filename),
688 filename = fullname,
689 mime = mime,
690 properties = "mathml",
691 } )
692 else
693 used[#used+1] = replacetemplate(t_item, {
694 id = idmaker(filename),
695 filename = fullname,
696 mime = mime,
697 } )
698 end
699 return true
700 end
701 end
702
703 local function registerandcopyfile(check,path,name,sourcepath,targetpath,newname,image)
704
705 if name == "" then
706 report("ignoring unknown image")
707 return
708 end
709
710 if newname then
711 newname = replacesuffix(newname,suffix(name))
712 else
713 newname = name
714 end
715
716 local source = joinfile(sourcepath,name)
717 local target = joinfile(targetpath,newname)
718 local mathml = false
719
720 if suffix(source) == "xhtml" then
721 if find(io.loaddata(source),"MathML") then
722 mathml = true
723 end
724 else
725 report("checking image %a -> %a",source,target)
726 end
727 if registerone(path,newname,mathml) then
728 if not check or needsupdating(source,target) or mathml and svgmath then
729 report("copying %a to %a",source,target)
730 copyfile(source,target)
731 updated = updated + 1
732 else
733 notupdated = notupdated + 1
734 end
735 newfiles[#newfiles+1] = target
736 if mathml and svgmath then
737 report()
738 report("converting mathml into svg in %a",target)
739 report()
740 local status, total, unique = moduledata.svgmath.convert(target,svgstyle)
741 report()
742 if status then
743 report("%s formulas converted, %s are unique",total,unique)
744 else
745 report("warning: %a in %a",total,target)
746 end
747 report()
748 end
749 end
750 end
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769 for image, data in sortedhash(images) do
770
771
772
773 registerandcopyfile(true,imagepath,data.newname,imagesource,imagetarget,rename and image,true)
774 end
775 for i=1,#styles do
776 registerandcopyfile(false,stylepath,styles[i],stylesource,styletarget)
777 end
778 for i=1,#htmlfiles do
779 registerandcopyfile(false,false,htmlfiles[i],htmlsource,htmltarget)
780 end
781
782 relocateimages(images,oldimagespecification,oldimagespecification,imagepath,rename)
783 relocateimages(images,oldimagespecification,newimagespecification,imagepath,rename)
784
785 report("%s files registered, %s updated, %s kept",updated + notupdated,updated,notupdated)
786
787 local function saveinfile(what,name,data)
788 report("saving %s in %a",what,name)
789 io.savedata(name,data)
790 newfiles[#newfiles+1] = name
791 end
792
793 used[#used+1] = replacetemplate(t_prop, {
794 id = "nav",
795 filename = epubnavigator,
796 properties = "nav",
797 mime = "application/xhtml+xml",
798 })
799
800 registerone(false,epubtoc)
801
802 saveinfile("navigation data",joinfile(htmltarget,epubnavigator),replacetemplate(t_navtoc, {
803 root = htmlroot,
804 } ) )
805
806 saveinfile("used mimetypes",joinfile(epubpath,epubmimetypes),mimetype)
807
808 saveinfile("version 2.0 container",joinfile(metatarget,epubcontainer),replacetemplate(t_container, {
809 rootfile = epubroot
810 } ) )
811
812 local idmaker = idmakers[suffix(htmlroot)] or idmakers.default
813
814 saveinfile("package specification",joinfile(htmltarget,epubroot),replacetemplate(t_package, {
815 identifier = identifier,
816 title = title,
817 language = language,
818 uuid = uuid,
819 creator = creator,
820 date = os.date("!%Y-%m-%dT%H:%M:%SZ"),
821 coverpage = idmaker(coverpage),
822 manifest = concat(used,"\n"),
823 rootfile = idmaker(htmlroot)
824 } ) )
825
826
827
828 saveinfile("table of contents",joinfile(htmltarget,epubtoc), replacetemplate(t_toc, {
829 identifier = uuid,
830 title = title,
831 author = author,
832 root = htmlroot,
833 } ) )
834
835 report("creating archive\n\n")
836
837 pushdir(epubpath)
838
839 removefile(epubfile)
840
841 local usedzipper = false
842
843 local function zipped(zipper)
844 local ok = os.execute(format(zipper.uncompressed,epubfile,epubmimetypes))
845 if ok == 0 then
846 os.execute(format(zipper.compressed,epubfile,metapath))
847 os.execute(format(zipper.compressed,epubfile,datapath))
848 usedzipper = zipper.name
849 return true
850 end
851 end
852
853
854
855 for i=1,#zippers do
856 if os.which(zippers[i].binary) and zipped(zippers[i]) then
857 break
858 end
859 end
860
861
862
863 if not usedzipper then
864 for i=1,#zippers do
865 if zipped(zippers[i]) then
866 break
867 end
868 end
869 end
870
871 popdir()
872
873 if usedzipper then
874 local treefile = joinfile(epubpath,epubfile)
875 removefile(epubfile)
876 copyfile(treefile,epubfile)
877 if isfile(epubfile) then
878 removefile(treefile)
879 end
880 report("epub archive made using %s: %s",usedzipper,epubfile)
881 else
882 local list = { }
883 for i=1,#zippers do
884 list[#list+1] = zippers[i].name
885 end
886 report("no epub archive made, install one of: % | t",list)
887 end
888
889 if reportobsolete(oldfiles,newfiles,purge) then
890 obsolete = true
891 end
892
893 if obsolete and not purge then
894 report("use --purge to remove obsolete files")
895 end
896
897end
898
899do
900
901 local runimages = sandbox.registerrunner {
902 name = "images",
903 program = "context",
904
905 template = longtostring [[
906 "%fullname%"
907 "--exportimages"
908 "--result=%nameonly%-images"
909 ]],
910 }
911
912 local runconvert = sandbox.registerrunner {
913 name = "convert",
914 program = "mutool",
915
916 template = longtostring [[
917 "convert"
918 "-o%imagepath%/%nameonly%-exported-%%d.svg"
919 "%nameonly%-images.pdf"
920 ]],
921 }
922
923 function scripts.epub.images()
924 local files = environment.globfiles()
925 if files then
926
927 statistics.starttiming("export")
928
929 local fix = environment.argument("fix")
930 local flat = environment.argument("flat")
931 local path = environment.argument("path") or "."
932 local jobs = { }
933 for i=1,#files do
934 local filename = file.basename(files[i])
935 local fullname = file.addsuffix(filename,"tex")
936 local nameonly = file.nameonly(fullname)
937 local pattern = nameonly .. "-exported-*.svg"
938 local target = flat and "." or (nameonly .. "-export")
939 if not lfs.isfile(fullname) then
940 report("no export file %a",fullname)
941 elseif type(path) == "string" and path ~= "" and not lfs.isdir(path) then
942 report("no export root %a",path)
943 else
944 local imagepath = file.join(path,target,"images")
945 dir.makedirs(imagepath)
946 if lfs.isdir(imagepath) then
947 jobs[#jobs+1] = {
948 filename = filename,
949 fullname = fullname,
950 nameonly = nameonly,
951 path = path,
952 target = target,
953 imagepath = imagepath,
954 pattern = file.join(imagepath,pattern),
955 }
956 else
957 report("invalid image path %a",imagepath)
958 end
959 end
960 end
961
962 local images = 0
963
964 for index=1,#jobs do
965
966 local job = jobs[index]
967
968
969
970 local files = dir.glob(job.pattern)
971 for i=1,#files do
972 os.remove(files[i])
973 end
974
975
976
977 runimages {
978 fullname = job.fullname,
979 nameonly = job.nameonly,
980 }
981
982
983
984 runconvert {
985 nameonly = job.nameonly,
986 imagepath = job.imagepath,
987 }
988
989
990
991
992 if fix then
993 local files = dir.glob(job.pattern)
994 for i=1,#files do
995 local name = files[i]
996 local data = io.loaddata(name)
997 if find(data,'"[<>]"') then
998 report("fixing %a",name)
999 data = gsub(data,'"([<>])"', { ["<"] = '"<"', [">"] = '">"' })
1000 io.savedata(name,data)
1001 end
1002 end
1003 end
1004
1005
1006
1007 local files = dir.glob(job.pattern)
1008 if #files > 0 then
1009 images = images + #files
1010 report()
1011 end
1012 for i=1,#files do
1013 local name = files[i]
1014 report("% 7i : %s",file.size(name),file.basename(name))
1015 end
1016
1017 end
1018
1019 statistics.stoptiming("export")
1020
1021 report()
1022 report("%i files, %i images, export time: %s",#jobs,images,statistics.elapsedtime("export"))
1023
1024 end
1025
1026 end
1027
1028end
1029
1030
1031
1032local a_exporthelp = environment.argument("exporthelp")
1033local a_make = environment.argument("make")
1034local a_all = environment.argument("all")
1035local a_purge = a_all or environment.argument("purge")
1036local a_rename = a_all or environment.argument("rename")
1037local a_svgmath = a_all or environment.argument("svgmath")
1038local a_svgstyle = environment.argument("svgstyle")
1039
1040local a_images = environment.argument("images")
1041
1042if a_make and a_svgmath then
1043 require("x-math-svg")
1044end
1045
1046if a_images then
1047 scripts.epub.images()
1048elseif a_make then
1049 scripts.epub.make(a_purge,a_rename,a_svgmath,a_svgstyle)
1050elseif a_exporthelp then
1051 application.export(a_exporthelp,environment.files[1])
1052else
1053 application.help()
1054end
1055
1056
1057 |