Blame tools/lenslist/show_lensfun_coverage.py

Packit Service 48484a
#!/usr/bin/env python3
Packit Service 48484a
Packit Service 48484a
#======================================================================
Packit Service 48484a
Packit Service 48484a
import subprocess, os, glob, datetime, tempfile, argparse
Packit Service 48484a
from xml.etree import ElementTree
Packit Service 48484a
import re
Packit Service 48484a
import argparse
Packit Service 48484a
import shutil
Packit Service 48484a
Packit Service 48484a
#======================================================================
Packit Service 48484a
# Function and class definitions
Packit Service 48484a
#----------------------------------------------------------------------
Packit Service 48484a
Packit Service 48484a
#----------------------------------------------------------------------
Packit Service 48484a
def find_best(root, tagname):
Packit Service 48484a
    texts = [(len(element.text), element.text) for element in root.findall(tagname) if element.attrib.get("lang") == "en"]
Packit Service 48484a
    if texts:
Packit Service 48484a
        return sorted(texts)[0][1]
Packit Service 48484a
    texts = [(len(element.text), element.text) for element in root.findall(tagname)]
Packit Service 48484a
    if texts:
Packit Service 48484a
        return sorted(texts)[0][1]
Packit Service 48484a
    else: 
Packit Service 48484a
        return None
Packit Service 48484a
Packit Service 48484a
def print_x(value):
Packit Service 48484a
    return ' class="lenslist-highlight lenslist-check">yes' if value else ' class="lenslist-check">no'
Packit Service 48484a
Packit Service 48484a
#----------------------------------------------------------------------
Packit Service 48484a
# class to hold camera information
Packit Service 48484a
class Camera:
Packit Service 48484a
    camera_makers = {}
Packit Service 48484a
    def __init__(self, element):
Packit Service 48484a
        self.maker = find_best(element, "maker")
Packit Service 48484a
        self.model = find_best(element, "model")
Packit Service 48484a
        variant = find_best(element, "variant");
Packit Service 48484a
        if variant:
Packit Service 48484a
            self.model = self.model + " " + variant
Packit Service 48484a
        self.crop = float(element.find("cropfactor").text)
Packit Service 48484a
        self.camera_makers.setdefault(self.maker, set()).add(self.model)
Packit Service 48484a
    def __lt__(self, other):
Packit Service 48484a
        return (self.maker, self.model) < (other.maker, other.model)
Packit Service 48484a
Packit Service 48484a
#----------------------------------------------------------------------
Packit Service 48484a
# class to hold lens information
Packit Service 48484a
class Lens:
Packit Service 48484a
    def __init__(self, element, root, camtype):
Packit Service 48484a
        self.maker = find_best(element, "maker")
Packit Service 48484a
        self.model = find_best(element, "model")
Packit Service 48484a
        if camtype == "compact":
Packit Service 48484a
            mount = element.find("mount").text
Packit Service 48484a
            for camera in root.findall("camera"):
Packit Service 48484a
                if camera.find("mount").text == mount:
Packit Service 48484a
                    self.maker = find_best(camera, "maker")
Packit Service 48484a
                    camname = find_best(camera, "model") 
Packit Service 48484a
                    variant = find_best(camera, "variant");
Packit Service 48484a
                    if variant:
Packit Service 48484a
                        camname = camname + " " + variant
Packit Service 48484a
                    break
Packit Service 48484a
            self.model = "Fixed lens {}".format(camname)
Packit Service 48484a
        try:
Packit Service 48484a
            self.crop = float(element.find("cropfactor").text)
Packit Service 48484a
        except:
Packit Service 48484a
            self.crop = None
Packit Service 48484a
        self.distortion = element.find("calibration/distortion") is not None
Packit Service 48484a
        self.tca = element.find("calibration/tca") is not None
Packit Service 48484a
        self.vignetting = element.find("calibration/vignetting") is not None
Packit Service 48484a
    def __lt__(self, other):
Packit Service 48484a
        return (self.maker, self.model, self.crop) < (other.maker, other.model, self.crop)
Packit Service 48484a
Packit Service 48484a
#======================================================================
Packit Service 48484a
Packit Service 48484a
Packit Service 48484a
Packit Service 48484a
#======================================================================
Packit Service 48484a
# Main routine
Packit Service 48484a
#----------------------------------------------------------------------
Packit Service 48484a
Packit Service 48484a
# set up the commandline parser and define some arguemnts
Packit Service 48484a
parser = argparse.ArgumentParser(description='Create a list of all cameras and lenses in the Lensfun database.')
Packit Service 48484a
parser.add_argument('db_path', metavar='DB_PATH', help='path to the Lensfun database', default='/usr/share/lensfun/', nargs='?')
Packit Service 48484a
parser.add_argument('-g', dest='git', action='store_true', help='use current database from git repository')
Packit Service 48484a
parser.add_argument('-t', dest='table_only', action='store_true', help='pure table/list without surrounding header and description')
Packit Service 48484a
parser.add_argument('-m', dest='markdown', action='store_true', help='output markdown instead of HTML')
Packit Service 48484a
parser.add_argument('-o', dest='outfile', action='store', help='output filename and path', default='./lensfun_coverage.html')
Packit Service 48484a
Packit Service 48484a
cmdline_args = vars(parser.parse_args())
Packit Service 48484a
Packit Service 48484a
Packit Service 48484a
# decide wether to get the most up to date database from git or use the locally installed database
Packit Service 48484a
if cmdline_args['git']==True:
Packit Service 48484a
    XmlDBPath = os.path.join(tempfile.gettempdir(), "lensfun")
Packit Service 48484a
    print("~ Lensfun database is retrieved directly from git")
Packit Service 48484a
    if os.path.isdir(XmlDBPath):
Packit Service 48484a
        shutil.rmtree(XmlDBPath)
Packit Service 48484a
    subprocess.check_output(["git", "clone", "http://git.code.sf.net/p/lensfun/code", XmlDBPath])
Packit Service 48484a
    XmlDBPath = os.path.join(XmlDBPath, "data", "db")
Packit Service 48484a
else:
Packit Service 48484a
    XmlDBPath = cmdline_args['db_path']
Packit Service 48484a
    print("~ Lensfun database is searched in "+XmlDBPath)
Packit Service 48484a
Packit Service 48484a
# parse the database create a list of camera and lens objects
Packit Service 48484a
cameras, lenses = [], []
Packit Service 48484a
for filename in glob.glob(os.path.join(XmlDBPath,"*.xml")):
Packit Service 48484a
    root = ElementTree.parse(filename)
Packit Service 48484a
Packit Service 48484a
    camtype_search = re.search('.*/([^-]*)-(.*).xml', filename, re.IGNORECASE)    
Packit Service 48484a
    if camtype_search:
Packit Service 48484a
        camtype = camtype_search.group(1)
Packit Service 48484a
    else:
Packit Service 48484a
        camtype = 'generic'
Packit Service 48484a
Packit Service 48484a
    cameras.extend(Camera(camera_element) for camera_element in root.findall("camera"))
Packit Service 48484a
    lenses_list = [Lens(lens_element, root, camtype) for lens_element in root.findall("lens")]
Packit Service 48484a
    lenses.extend(lens for lens in lenses_list if lens.distortion or lens.tca or lens.vignetting)
Packit Service 48484a
Packit Service 48484a
cameras.sort()
Packit Service 48484a
lenses.sort(key=lambda Lens: Lens.model.lower())
Packit Service 48484a
lenses.sort(key=lambda Lens: Lens.maker.lower())
Packit Service 48484a
Packit Service 48484a
# finally write the table into the output file
Packit Service 48484a
outfile = open(cmdline_args['outfile'], "w")
Packit Service 48484a
Packit Service 48484a
#----------------------------------------------------------------------
Packit Service 48484a
# write HTML table or markdown formatted list
Packit Service 48484a
if cmdline_args['markdown'] == False:
Packit Service 48484a
Packit Service 48484a
    #----------------------------------------------------------------------
Packit Service 48484a
    # HTML table
Packit Service 48484a
    if cmdline_args['table_only'] == False:
Packit Service 48484a
        outfile.write("<html><head><title>Lensfun's coverage</title></head><body>

Lensfun coverage

Lenses (count: {})

"
Packit Service 48484a
                  "

This table was generated on {} from current Lensfun sources. Your Lensfun version may be older, resulting in "

Packit Service 48484a
                  "less coverage.  If your lens is not included, see

Packit Service 48484a
                  "
  • Lens calibration for Lensfun
  • \n".format(
    Packit Service 48484a
                          len(lenses), datetime.date.today()))
    Packit Service 48484a
    Packit Service 48484a
        outfile.write(""
    manufacturermodelcropdist.TCA
    Packit Service 48484a
                      "vign.\n")
    Packit Service 48484a
        number_of_makers = 0
    Packit Service 48484a
        previous_maker = None
    Packit Service 48484a
    Packit Service 48484a
        for lens in lenses:
    Packit Service 48484a
            if lens.maker.lower() != previous_maker:
    Packit Service 48484a
                number_of_makers += 1
    Packit Service 48484a
    Packit Service 48484a
            outfile.write("""<tr{}>{}{}{}<td{}</td><td{}</td><td{}</td>\n""".format(
    Packit Service 48484a
                ' class="lenslist-bg1"' if number_of_makers % 2 else ' class="lenslist-bg2"',
    Packit Service 48484a
                lens.maker if lens.maker.lower() != previous_maker else "", lens.model, lens.crop or "?",
    Packit Service 48484a
                print_x(lens.distortion), print_x(lens.tca), print_x(lens.vignetting)))
    Packit Service 48484a
            previous_maker = lens.maker.lower()
    Packit Service 48484a
    Packit Service 48484a
        outfile.write("

    Cameras

    Note that new camera models can be added very easily. "

    Packit Service 48484a
                  "Contact the Lensfun maintainers for this.

    ")
    Packit Service 48484a
    Packit Service 48484a
        for maker, cameras in sorted(Camera.camera_makers.items()):
    Packit Service 48484a
            outfile.write("

    {}: {}

    ".format(maker, ", ".join(sorted(cameras))))
    Packit Service 48484a
    Packit Service 48484a
        if cmdline_args['table_only'] == False:
    Packit Service 48484a
            outfile.write("</body></html>")
    Packit Service 48484a
    else:
    Packit Service 48484a
    Packit Service 48484a
        #----------------------------------------------------------------------
    Packit Service 48484a
        # Markdown list
    Packit Service 48484a
    Packit Service 48484a
        if cmdline_args['table_only'] == False:
    Packit Service 48484a
            outfile.write("= Lensfun's coverage = \n\n == Lenses (count: {}) ==\n\n"
    Packit Service 48484a
                      "This list was generated on {} from current Lensfun sources.  Your Lensfun version may be older, resulting in "
    Packit Service 48484a
                      "less coverage.  \nIf your lens is not included, see \n\n* Upload calibration pictures\n"
    Packit Service 48484a
                      "* Lens calibration for Lensfun\n\n".format(
    Packit Service 48484a
                          len(lenses), datetime.date.today()))
    Packit Service 48484a
    Packit Service 48484a
        number_of_makers = 0
    Packit Service 48484a
        previous_maker = None
    Packit Service 48484a
    Packit Service 48484a
        for lens in lenses:
    Packit Service 48484a
            if lens.maker.lower() != previous_maker:
    Packit Service 48484a
                number_of_makers += 1
    Packit Service 48484a
    Packit Service 48484a
            if lens.maker.lower() != previous_maker:
    Packit Service 48484a
                outfile.write("\n== {} ==\n\n".format(lens.maker))
    Packit Service 48484a
    Packit Service 48484a
            outfile.write("* {} ({}, {}/{}/{})\n".format(lens.model, lens.crop or "?",
    Packit Service 48484a
                "D" if lens.distortion else "-", 
    Packit Service 48484a
                "T" if lens.tca else "-",
    Packit Service 48484a
                "V" if lens.vignetting else "-"))
    Packit Service 48484a
            previous_maker = lens.maker.lower()
    Packit Service 48484a
    Packit Service 48484a
    outfile.close()
    Packit Service 48484a
    print("~ List of lenses was written to "+cmdline_args['outfile'])