148 lines
		
	
	
	
		
			4.7 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			148 lines
		
	
	
	
		
			4.7 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
| # Melpomene webcomic reader JSON/JS/HTML generator
 | |
| # Version 1.0.0_RC1
 | |
| # CC-BY-NC-SA https://git.aribaud.net/caribaud/melpomene/
 | |
| 
 | |
| import sys
 | |
| import re
 | |
| import xml.etree.ElementTree as ET
 | |
| import argparse
 | |
| 
 | |
| from pathlib import Path
 | |
| 
 | |
| 
 | |
| HTML_TEMPLATE = Path(__file__).parent / "melpomene.html"
 | |
| HTML_TO_REPLACE = "<!-- your img tags here, see documentation -->"
 | |
| 
 | |
| 
 | |
| def extract_zooms(src_folder):
 | |
|     folder = Path(src_folder)
 | |
| 
 | |
|     zooms = {}
 | |
|     
 | |
|     max_width = 0
 | |
|     max_height = 0
 | |
|     
 | |
|     idx = 0
 | |
| 
 | |
|     for svg_path in folder.glob("*.svg"):
 | |
|         
 | |
|         idx += 1
 | |
|     
 | |
|         print(f"page {idx} : {svg_path.name}")
 | |
|     
 | |
|         zooms[idx] = {
 | |
|             "name": svg_path.stem,
 | |
|             "width": 0,
 | |
|             "height": 0,
 | |
|             "zooms": [],
 | |
|         }
 | |
|     
 | |
|         tree = ET.parse(svg_path)
 | |
|         root = tree.getroot()
 | |
| 
 | |
|         if "." in root.get("width"):
 | |
|             print(f"WARNING: file {svg_path} has a floating width, it will be rounded", file=sys.stderr)
 | |
|         zooms[idx]["width"] = round(float(root.get("width")))
 | |
|         if "." in root.get("height"):
 | |
|             print(f"WARNING: file {svg_path} has a floating height, it will be rounded", file=sys.stderr)
 | |
|         zooms[idx]["height"] = round(float(root.get("height")))
 | |
|         
 | |
|         for area in root.findall('.//{*}rect'):
 | |
|             zooms[idx]["zooms"].append([
 | |
|                 float(area.get("width")),
 | |
|                 float(area.get("height")),
 | |
|                 float(area.get("x")),
 | |
|                 float(area.get("y")),
 | |
|             ])
 | |
| 
 | |
|     return zooms, max_width, max_height
 | |
| 
 | |
| 
 | |
| def write_json_or_js(zooms, dest_file, is_js):
 | |
| 
 | |
|     with open(dest_file, "w") as data_file:
 | |
|     
 | |
|         if is_js:
 | |
|             data_file.write("PAGES_ZOOMS = ")
 | |
|         data_file.write("[\n")
 | |
|         first_coma_skiped = False
 | |
|         for page_idx in sorted(zooms.keys()):
 | |
|             for zoom in zooms[page_idx]["zooms"]:
 | |
|             
 | |
|                 if zoom[2] < 0 or zoom[3] < 0 :
 | |
|                     print(f"WARNING: negative pos x / pos y in page {page_idx} for zoom {zoom} (is the rectangle flipped?)")
 | |
|             
 | |
|                 if first_coma_skiped:
 | |
|                     data_file.write(",\n")
 | |
|                 else:
 | |
|                     first_coma_skiped = True
 | |
|                 data_file.write(f"    {[page_idx] + zoom}")
 | |
|         data_file.write("\n]\n")
 | |
| 
 | |
| 
 | |
| def write_html(zooms, dest_file, pages_width, pages_height, prefix, extention):
 | |
|     
 | |
|     img_tags = ""
 | |
|     for page_idx in sorted(zooms.keys()):
 | |
|         img_url = f"{prefix}{zooms[page_idx]['name']}.{extention}"
 | |
|         zoom_html_data = [','.join([str(zoom) for zoom in page_zooms]) for page_zooms in zooms[page_idx]["zooms"]]
 | |
|         zoom_html_str = ';'.join(zoom_html_data)
 | |
|         img_tags = img_tags + f'            <img loading="lazy" height="{zooms[page_idx]["height"]}" width="{zooms[page_idx]["width"]}" src="{img_url}" data-zooms="{zoom_html_str}"/>\n'
 | |
|     
 | |
|     img_tags = img_tags.strip()
 | |
|     
 | |
|     with open(HTML_TEMPLATE) as template_file, open(dest_file, "w") as data_file:
 | |
|         
 | |
|         data = template_file.read().replace(HTML_TO_REPLACE, img_tags)
 | |
|     
 | |
|         data_file.write(data)
 | |
| 
 | |
| 
 | |
| def generate_argparse():
 | |
|     """ Generate Melpomene's generator input parser"""
 | |
|     
 | |
|     parser = argparse.ArgumentParser(
 | |
|         description="Helper that can generate JSON / JS / HTML files for Melpomene webcomic reader"
 | |
|     )
 | |
|     
 | |
|     parser.add_argument("output_format", choices=["html", "json", "js"], help="The type of output to generate")
 | |
|     parser.add_argument("svg_folders", help="Path of the folder containing the SVGs")
 | |
|     parser.add_argument("-o", metavar="dest_file", help="Where to write the generator output to")
 | |
|     parser.add_argument("-p", default="", metavar="img_url_prefix", help="What to prefix the URL of the images when using HTML format.")
 | |
|     parser.add_argument("-e", default="png", metavar="img_ext", help="What extention to use in the URL of the images when using HTML format.")
 | |
|     
 | |
|     return parser
 | |
| 
 | |
| 
 | |
| if __name__ == "__main__":
 | |
| 
 | |
|     args = generate_argparse().parse_args()
 | |
|     
 | |
|     
 | |
|     # Get the final outout name
 | |
|     output = None
 | |
|     
 | |
|     if not args.o:
 | |
|         output = "melpomene_data"
 | |
|     else:
 | |
|         output = args.o
 | |
|     
 | |
|     if args.output_format == "html" and not output.endswith(".html"):
 | |
|         output += ".html"
 | |
|     
 | |
|     elif args.output_format == "json" and not output.endswith(".json"):
 | |
|         output += ".json"
 | |
|     
 | |
|     elif args.output_format == "js" and not output.endswith(".js"):
 | |
|         output += ".js"
 | |
|     
 | |
|     zooms, max_width, max_height = extract_zooms(args.svg_folders)
 | |
| 
 | |
|     if args.output_format == "html":
 | |
|         write_html(zooms, output, max_width, max_height, args.p, args.e)
 | |
|     
 | |
|     elif args.output_format == "json":
 | |
|         write_json_or_js(zooms, output, False)
 | |
|     
 | |
|     elif args.output_format == "js":
 | |
|         write_json_or_js(zooms, output, True)
 |