First commit, working CLI
							
								
								
									
										108
									
								
								dtlib.py
									
									
									
									
									
										Executable file
									
								
							
							
						
						@@ -0,0 +1,108 @@
 | 
			
		||||
#!/usr/bin/env python3
 | 
			
		||||
import sqlite3
 | 
			
		||||
from datetime import datetime
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def extractor(dt_file, start, end):
 | 
			
		||||
    catalog = {}
 | 
			
		||||
    conn = sqlite3.connect(dt_file)
 | 
			
		||||
    cursor = conn.cursor()
 | 
			
		||||
    req = "SELECT id, model, lens, exposure, aperture, iso, focal_length, datetime_taken, width, height FROM images;"
 | 
			
		||||
    cursor.execute(req)
 | 
			
		||||
    res = cursor.fetchall()
 | 
			
		||||
    for data in res:
 | 
			
		||||
        img_date = datetime.strptime(data[7], "%Y:%m:%d %H:%M:%S")
 | 
			
		||||
        if start <= img_date <= end:
 | 
			
		||||
            catalog.update({
 | 
			
		||||
                data[0]:
 | 
			
		||||
                    {
 | 
			
		||||
                        'camera': data[1],
 | 
			
		||||
                        'lens': data[2],
 | 
			
		||||
                        'shutter': float(data[3]*1000),
 | 
			
		||||
                        'aperture': round(float(data[4]), 1),
 | 
			
		||||
                        'iso': int(data[5]),
 | 
			
		||||
                        'focal': float(data[6]),
 | 
			
		||||
                        'datetime': img_date,
 | 
			
		||||
                        'height': int(data[9]),
 | 
			
		||||
                        'width': int(data[8])
 | 
			
		||||
                }
 | 
			
		||||
            })
 | 
			
		||||
    cameras, lenses, focals, apertures, shutter_speeds = {}, {}, {}, {}, {}
 | 
			
		||||
    isos, dimensions, cameras_lenses, dates = {}, {}, {}, {}
 | 
			
		||||
    cameras_list, lenses_list, focals_list, apertures_list, shutter_speeds_list = [], [], [], [], []
 | 
			
		||||
    isos_list, dimensions_list, cameras_lenses_list, dates_list = [], [], [], []
 | 
			
		||||
    for item in catalog.keys():
 | 
			
		||||
        cameras_list.append(catalog[item]['camera'])
 | 
			
		||||
        lenses_list.append(catalog[item]['lens'])
 | 
			
		||||
        if catalog[item]['lens'] and "---" not in catalog[item]['lens']:
 | 
			
		||||
            cameras_lenses_list.append(
 | 
			
		||||
                "{} + {}".format(catalog[item]['camera'], catalog[item]['lens']))
 | 
			
		||||
        focals_list.append(round(float(catalog[item]['focal']), 1))
 | 
			
		||||
        apertures_list.append(catalog[item]['aperture'])
 | 
			
		||||
        shutter_speeds_list.append(catalog[item]['shutter'])
 | 
			
		||||
        isos_list.append(catalog[item]['iso'])
 | 
			
		||||
        dimensions_list.append(
 | 
			
		||||
            round(((catalog[item]['height']*catalog[item]['width'])/10**6), 1))
 | 
			
		||||
        dates_list.append(catalog[item]['datetime'].strftime("%Y%m%d"))
 | 
			
		||||
    for camera in list(set(cameras_list)):
 | 
			
		||||
        if camera:
 | 
			
		||||
            cameras.update({camera: cameras_list.count(camera)})
 | 
			
		||||
    for lens in list(set(lenses_list)):
 | 
			
		||||
        if lens and "---" not in lens:
 | 
			
		||||
            lenses.update({lens: lenses_list.count(lens)})
 | 
			
		||||
    for camera_lense in list(set(cameras_lenses_list)):
 | 
			
		||||
        if camera_lense:
 | 
			
		||||
            cameras_lenses.update(
 | 
			
		||||
                {camera_lense: cameras_lenses_list.count(camera_lense)})
 | 
			
		||||
    for focal in list(set(focals_list)):
 | 
			
		||||
        if focal:
 | 
			
		||||
            focals.update({focal: focals_list.count(focal)})
 | 
			
		||||
    for aperture in list(set(apertures_list)):
 | 
			
		||||
        if aperture:
 | 
			
		||||
            apertures.update({aperture: apertures_list.count(aperture)})
 | 
			
		||||
    for shutter_speed in list(set(shutter_speeds_list)):
 | 
			
		||||
        if shutter_speed:
 | 
			
		||||
            shutter_speeds.update(
 | 
			
		||||
                {shutter_speed: shutter_speeds_list.count(shutter_speed)})
 | 
			
		||||
    for iso in list(set(isos_list)):
 | 
			
		||||
        if iso:
 | 
			
		||||
            isos.update({iso: isos_list.count(iso)})
 | 
			
		||||
    for dimension in list(set(dimensions_list)):
 | 
			
		||||
        if dimension:
 | 
			
		||||
            dimensions.update({dimension: dimensions_list.count(dimension)})
 | 
			
		||||
    for date in list(set(dates_list)):
 | 
			
		||||
        if date:
 | 
			
		||||
            dates.update({date: dates_list.count(date)})
 | 
			
		||||
    return {
 | 
			
		||||
        "total": len(catalog.keys()),
 | 
			
		||||
        "date": dates,
 | 
			
		||||
        "cameras": cameras,
 | 
			
		||||
        "lenses": lenses,
 | 
			
		||||
        "cameras+lenses": cameras_lenses,
 | 
			
		||||
        "focals": focals,
 | 
			
		||||
        "apertures": apertures,
 | 
			
		||||
        "shutter_speeds": shutter_speeds,
 | 
			
		||||
        "isos": isos,
 | 
			
		||||
        "dimensions": dimensions
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
if __name__ == '__main__':
 | 
			
		||||
    import argparse
 | 
			
		||||
    import json
 | 
			
		||||
    parser = argparse.ArgumentParser()
 | 
			
		||||
    parser.add_argument("infile", help="darktable library")
 | 
			
		||||
    parser.add_argument("-s", "--start-date", help="start date as YYYYMMDD. If omitted, begin of the collection.", const=None)
 | 
			
		||||
    parser.add_argument("-e", "--end-date", help="end date as YYYYMMDD. If omitted, today", const=None)
 | 
			
		||||
    args = parser.parse_args()
 | 
			
		||||
    if not args.start_date:
 | 
			
		||||
        args.start_date = "18250101" # Ok, that's the year of the 1st photography by Nicéphore Niépce. Shoul'd be enough for a start date.
 | 
			
		||||
    if not args.end_date:
 | 
			
		||||
        args.end_date = datetime.strftime(datetime.now(), "%Y%m%d")
 | 
			
		||||
    try:
 | 
			
		||||
        datetime.strptime(args.start_date, "%Y%m%d")
 | 
			
		||||
        datetime.strptime(args.end_date, "%Y%m%d")
 | 
			
		||||
    except ValueError:
 | 
			
		||||
        print("Date must be YYYYMMDD.")
 | 
			
		||||
        exit()
 | 
			
		||||
    print(json.dumps(extractor(args.infile, datetime.strptime(args.start_date, "%Y%m%d"), datetime.strptime(args.end_date, "%Y%m%d")), indent=4, sort_keys=True))
 | 
			
		||||
							
								
								
									
										
											BIN
										
									
								
								helpers/cameras/Canon_EOS_1100D.jpg
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 39 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								helpers/cameras/ILCE-6500.jpg
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 258 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								helpers/cameras/ILCE-QX1.jpg
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 68 KiB  | 
							
								
								
									
										1
									
								
								helpers/dictionary.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1 @@
 | 
			
		||||
{"camera": {"ILCE-QX1": {"brand": "Sony", "name": "QX1"}, "ILCE-6500": {"brand": "Sony", "name": "\u03b16500"}, "ILCE-5100": {"brand": "Sony", "name": "\u03b15100"}, "ILCA-77M2": {"brand": "Sony", "name": "\u03b177 II"}, "DSC-RX100M3": {"brand": "Sony", "name": "RX100 III"}, "Canon EOS 1100D": {"brand": "Canon", "name": "EOS 1100D"}, "FIG-LX1": {"brand": "Huawei", "name": "P Smart"}}, "lens": {"E 55-210mm F4.5-6.3 OSS": {"brand": "Sony", "name": "E 55-210mm F4.5-6.3 OSS"}, "10-20mm F3.5": {"brand": "Sigma", "name": "10-20mm F3.5 EX DC HSM"}, "105mm F2.8": {"brand": "Sigma", "name": "MACRO 105mm F2.8 EX DG OS HSM"}, "50mm F1.4": {"brand": "Sony", "name": "50mm F1.4"}, "24-70mm F1.8-2.8": {"brand": "ZEISS", "name": "Vario-Sonnar T* 24-70 mm F1.8-2.8"}, "70-300mm F4.5-5.6 G SSM": {"brand": "Sony", "name": "70\u2013300 mm F4.5\u20135.6 G SSM"}, "E PZ 18-105mm F4 G OSS": {"brand": "Sony", "name": "E PZ 18\u2013105 mm F4 G OSS"}, "FE 90mm F2.8 Macro G OSS": {"brand": "Sony", "name": "FE 90 mm F2.8 Macro G OSS"}, "Canon EF 50mm f/1.8 STM": {"brand": "Canon", "name": "Canon EF 50mm f/1.8 STM"}, "Canon EF-S 18-55mm f/3.5-5.6 IS II": {"brand": "Canon", "name": "EF-S 18-55mm f/3.5-5.6 IS II"}}}
 | 
			
		||||
							
								
								
									
										
											BIN
										
									
								
								helpers/lenses/10-20mm_F3.5.jpg
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 199 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								helpers/lenses/105mm_F2.8.jpg
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 131 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								helpers/lenses/50mm_F1.4.jpg
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 27 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								helpers/lenses/70-300mm_F4.5-5.6_G_SSM.jpg
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 42 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								helpers/lenses/Canon_EF-S_18-55mm_f_3.5-5.6_IS_II.jpg
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 46 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								helpers/lenses/Canon_EF_50mm_f_1.8_STM.jpg
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 40 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								helpers/lenses/E_55-210mm_F4.5-6.3_OSS.jpg
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 58 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								helpers/lenses/E_PZ_18-105mm_F4_G_OSS.jpg
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 28 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								helpers/lenses/FE_90mm_F2.8_Macro_G_OSS.jpg
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 49 KiB  | 
							
								
								
									
										187
									
								
								locales/fr_FR/LC_MESSAGES/report.po
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,187 @@
 | 
			
		||||
msgid ""
 | 
			
		||||
msgstr ""
 | 
			
		||||
"Project-Id-Version: PhotoReport 0.1\n"
 | 
			
		||||
"POT-Creation-Date: 2018-11-13 21:30+0100\n"
 | 
			
		||||
"PO-Revision-Date: 2018-11-13 21:30+0100\n"
 | 
			
		||||
"Last-Translator: \n"
 | 
			
		||||
"Language-Team: \n"
 | 
			
		||||
"Language: fr_FR\n"
 | 
			
		||||
"MIME-Version: 1.0\n"
 | 
			
		||||
"Content-Type: text/plain; charset=UTF-8\n"
 | 
			
		||||
"Content-Transfer-Encoding: 8bit\n"
 | 
			
		||||
"X-Generator: Poedit 2.2\n"
 | 
			
		||||
"X-Poedit-Basepath: ../../..\n"
 | 
			
		||||
"Plural-Forms: nplurals=2; plural=(n > 1);\n"
 | 
			
		||||
"X-Poedit-SearchPath-0: report.py\n"
 | 
			
		||||
 | 
			
		||||
#: report.py:81
 | 
			
		||||
msgid "Statistical photo report"
 | 
			
		||||
msgstr "Rapport statistique des photos"
 | 
			
		||||
 | 
			
		||||
#: report.py:95
 | 
			
		||||
msgid "Pictures informations"
 | 
			
		||||
msgstr "Informations sur les photos"
 | 
			
		||||
 | 
			
		||||
#: report.py:104
 | 
			
		||||
msgid "The set contains {} pictures, "
 | 
			
		||||
msgstr "La collection comprend {} images, "
 | 
			
		||||
 | 
			
		||||
#: report.py:106
 | 
			
		||||
msgid "The set contains only one picture, "
 | 
			
		||||
msgstr "La collection comprend une seule image, "
 | 
			
		||||
 | 
			
		||||
#: report.py:108
 | 
			
		||||
msgid "The set is empty. "
 | 
			
		||||
msgstr "La collection est vide. "
 | 
			
		||||
 | 
			
		||||
#: report.py:110
 | 
			
		||||
msgid "taken from {} to {}. "
 | 
			
		||||
msgstr "prisent du {} au {}. "
 | 
			
		||||
 | 
			
		||||
#: report.py:113
 | 
			
		||||
msgid "The most productive day was {} ({} shots). "
 | 
			
		||||
msgstr "La journée la plus productive fut le {} ({} prises de vue). "
 | 
			
		||||
 | 
			
		||||
#: report.py:117
 | 
			
		||||
msgid "taken on {}. "
 | 
			
		||||
msgstr "prise le {}. "
 | 
			
		||||
 | 
			
		||||
#: report.py:120
 | 
			
		||||
#, python-brace-format
 | 
			
		||||
msgid "Pictures sizes are from {1}{0}Mpx to {2}{0}Mpx, mostly {3}{0}Mpx. "
 | 
			
		||||
msgstr ""
 | 
			
		||||
"La taille des images varie de {1}{0}Mpx à {2}{0}Mpx, pour la plupart à {3}{0}"
 | 
			
		||||
"Mpx. "
 | 
			
		||||
 | 
			
		||||
#: report.py:126
 | 
			
		||||
msgid "Picture size is {}{}Mpx. "
 | 
			
		||||
msgstr "La dimension de l'image est de {}{}Mpx. "
 | 
			
		||||
 | 
			
		||||
#: report.py:140
 | 
			
		||||
msgid "Distribution of shots by date{}"
 | 
			
		||||
msgstr "Répartition des photos par dates{}"
 | 
			
		||||
 | 
			
		||||
#: report.py:140 report.py:253 report.py:277 report.py:308 report.py:332
 | 
			
		||||
msgid " : top 20"
 | 
			
		||||
msgstr " : top 20"
 | 
			
		||||
 | 
			
		||||
#: report.py:141 report.py:252 report.py:276 report.py:307 report.py:331
 | 
			
		||||
msgid "Number of shots"
 | 
			
		||||
msgstr "Nombre de prises de vue"
 | 
			
		||||
 | 
			
		||||
#: report.py:156
 | 
			
		||||
msgid "Cameras & lenses"
 | 
			
		||||
msgstr "Appareils photo & objectifs"
 | 
			
		||||
 | 
			
		||||
#: report.py:164
 | 
			
		||||
msgid "The most commonly used couple is {} with {}. "
 | 
			
		||||
msgstr "Le couple le plus utilisé est le {} avec le {}. "
 | 
			
		||||
 | 
			
		||||
#: report.py:169
 | 
			
		||||
msgid "There are {} lenses, the most used is the {}. "
 | 
			
		||||
msgstr "Il y a {} objectifs, le plus utilisé est le {}. "
 | 
			
		||||
 | 
			
		||||
#: report.py:173
 | 
			
		||||
msgid "The lens is a {}. "
 | 
			
		||||
msgstr "L'objectif est un {}. "
 | 
			
		||||
 | 
			
		||||
#: report.py:175
 | 
			
		||||
msgid "The favorite aperture is {}{}, "
 | 
			
		||||
msgstr "L'ouverture favorite est {}{}, "
 | 
			
		||||
 | 
			
		||||
#: report.py:176 report.py:275 report.py:283
 | 
			
		||||
msgid "F"
 | 
			
		||||
msgstr "f/"
 | 
			
		||||
 | 
			
		||||
#: report.py:178
 | 
			
		||||
msgid "and the favorite focal lenght is {}mm. "
 | 
			
		||||
msgstr "et la longueur focal favorite est {} mm. "
 | 
			
		||||
 | 
			
		||||
#: report.py:182
 | 
			
		||||
msgid "There are {} cameras, the mose used is the {}. "
 | 
			
		||||
msgstr "Il y a {} appareils photos, le plus utilisé est le {}. "
 | 
			
		||||
 | 
			
		||||
#: report.py:186
 | 
			
		||||
msgid "The camera is a {}. "
 | 
			
		||||
msgstr "L'appareil photo est un {}. "
 | 
			
		||||
 | 
			
		||||
#: report.py:188
 | 
			
		||||
msgid " The favorite ISO is {}. "
 | 
			
		||||
msgstr " La sensibilité favorite est de {} ISO. "
 | 
			
		||||
 | 
			
		||||
#: report.py:210
 | 
			
		||||
msgid "Cameras"
 | 
			
		||||
msgstr "Appareils photo"
 | 
			
		||||
 | 
			
		||||
#: report.py:224
 | 
			
		||||
msgid "Lenses"
 | 
			
		||||
msgstr "Objectifs"
 | 
			
		||||
 | 
			
		||||
#: report.py:233
 | 
			
		||||
msgid "Focal lengths & apertures"
 | 
			
		||||
msgstr "Longueurs focales & ouvertures"
 | 
			
		||||
 | 
			
		||||
#: report.py:236
 | 
			
		||||
msgid "Focal lenghts"
 | 
			
		||||
msgstr "Longueurs focales"
 | 
			
		||||
 | 
			
		||||
#: report.py:253
 | 
			
		||||
msgid "Focals{}"
 | 
			
		||||
msgstr "Longueurs focales{}"
 | 
			
		||||
 | 
			
		||||
#: report.py:258
 | 
			
		||||
msgid "Only one focal lenght is used : {}mm. "
 | 
			
		||||
msgstr "Une seule longueur focal est utilisée : {}mm. "
 | 
			
		||||
 | 
			
		||||
#: report.py:260
 | 
			
		||||
msgid "Apertures"
 | 
			
		||||
msgstr "Ouvertures"
 | 
			
		||||
 | 
			
		||||
#: report.py:277
 | 
			
		||||
msgid "Apertures{}"
 | 
			
		||||
msgstr "Ouvertures{}"
 | 
			
		||||
 | 
			
		||||
#: report.py:282
 | 
			
		||||
msgid "Only one aperture is used : {}{}. "
 | 
			
		||||
msgstr "Une seule ouverture est utilisée : {}{}. "
 | 
			
		||||
 | 
			
		||||
#: report.py:289
 | 
			
		||||
msgid "ISO sensitivities & shutter speeds"
 | 
			
		||||
msgstr "Sensibilités ISO & vitesses d'obturation"
 | 
			
		||||
 | 
			
		||||
#: report.py:291
 | 
			
		||||
msgid "ISO sensitivities"
 | 
			
		||||
msgstr "Sensibilités ISO"
 | 
			
		||||
 | 
			
		||||
#: report.py:308
 | 
			
		||||
msgid "ISO sensibilities{}"
 | 
			
		||||
msgstr "Sensibilités ISO{}"
 | 
			
		||||
 | 
			
		||||
#: report.py:313
 | 
			
		||||
msgid "All shots at the same sensitivity : ISO {} "
 | 
			
		||||
msgstr "Toutes les photos ont été prise avec la même sensiblité : ISO {}. "
 | 
			
		||||
 | 
			
		||||
#: report.py:315
 | 
			
		||||
msgid "Shutter speeds"
 | 
			
		||||
msgstr "Vitesses d'obturation"
 | 
			
		||||
 | 
			
		||||
#: report.py:332
 | 
			
		||||
msgid "Shutter speeds{}"
 | 
			
		||||
msgstr "Vitesses d'obturation{}"
 | 
			
		||||
 | 
			
		||||
#: report.py:337
 | 
			
		||||
msgid "All shots at the same speed : {}. "
 | 
			
		||||
msgstr "Toutes les photos ont été prises à la même vitesse : {}. "
 | 
			
		||||
 | 
			
		||||
#~ msgid ""
 | 
			
		||||
#~ "There are {} lenses, the most used is the {}. The favorite aperture is {}"
 | 
			
		||||
#~ "{}, "
 | 
			
		||||
#~ msgstr ""
 | 
			
		||||
#~ "Il y a {} objectifs, le plus utilisé est le {}. L'ouverture favorite est "
 | 
			
		||||
#~ "{}{}, "
 | 
			
		||||
 | 
			
		||||
#~ msgid "Apertures : Top 20"
 | 
			
		||||
#~ msgstr "Ouvertures : top 20"
 | 
			
		||||
 | 
			
		||||
#~ msgid "Great !"
 | 
			
		||||
#~ msgstr "Super !"
 | 
			
		||||
							
								
								
									
										115
									
								
								lrcat.py
									
									
									
									
									
										Executable file
									
								
							
							
						
						@@ -0,0 +1,115 @@
 | 
			
		||||
#!/usr/bin/env python3
 | 
			
		||||
import sqlite3
 | 
			
		||||
from datetime import datetime
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def extractor(lrcat_file, start, end):
 | 
			
		||||
    catalog, camera, lens = {}, {}, {}
 | 
			
		||||
    conn = sqlite3.connect(lrcat_file)
 | 
			
		||||
    cursor = conn.cursor()
 | 
			
		||||
    req = "SELECT id_local, value FROM AgInternedExifCameraModel"
 | 
			
		||||
    cursor.execute(req)
 | 
			
		||||
    res = cursor.fetchall()
 | 
			
		||||
    for data in res:
 | 
			
		||||
        camera.update({data[0]: data[1]})
 | 
			
		||||
    req = "SELECT id_local, value FROM AgInternedExifLens"
 | 
			
		||||
    cursor.execute(req)
 | 
			
		||||
    res = cursor.fetchall()
 | 
			
		||||
    for data in res:
 | 
			
		||||
        lens.update({data[0]: data[1]})
 | 
			
		||||
    req = "SELECT image, focalLength, aperture, isoSpeedRating, shutterSpeed, cameraModelRef, lensRef FROM AgHarvestedExifMetadata"
 | 
			
		||||
    cursor.execute(req)
 | 
			
		||||
    res = cursor.fetchall()
 | 
			
		||||
    for data in res:
 | 
			
		||||
        if data[2]:
 | 
			
		||||
            aperture = round(2**(data[2]/2), 1)
 | 
			
		||||
        if data[4]:
 | 
			
		||||
            shutter = round(1/(2**data[4])*1000, 4)
 | 
			
		||||
        catalog.update({int(data[0]): {'focal': data[1], 'aperture': aperture, 'iso': int(
 | 
			
		||||
            data[3]), 'shutter': shutter, 'camera': camera[data[5]], 'lens': lens[data[6]]}})
 | 
			
		||||
    req = "SELECT id_local, captureTime, fileHeight, fileWidth FROM Adobe_images"
 | 
			
		||||
    cursor.execute(req)
 | 
			
		||||
    res = cursor.fetchall()
 | 
			
		||||
    for data in res:
 | 
			
		||||
        catalog[int(data[0])].update(
 | 
			
		||||
                {'datetime': datetime.strptime(data[1], "%Y-%m-%dT%H:%M:%S"), 'height': int(data[2]), 'width': int(data[3])})
 | 
			
		||||
    cameras, lenses, focals, apertures, shutter_speeds = {}, {}, {}, {}, {}
 | 
			
		||||
    isos, dimensions, cameras_lenses, dates = {}, {}, {}, {}
 | 
			
		||||
    cameras_list, lenses_list, focals_list, apertures_list, shutter_speeds_list = [], [], [], [], []
 | 
			
		||||
    isos_list, dimensions_list, cameras_lenses_list, dates_list = [], [], [], []
 | 
			
		||||
    for item in catalog.keys():
 | 
			
		||||
        if start <= catalog[item]['datetime'] <= end:
 | 
			
		||||
            cameras_list.append(catalog[item]['camera'])
 | 
			
		||||
            lenses_list.append(catalog[item]['lens'])
 | 
			
		||||
            if catalog[item]['lens'] and "---" not in catalog[item]['lens']:
 | 
			
		||||
                cameras_lenses_list.append(
 | 
			
		||||
                    "{} + {}".format(catalog[item]['camera'], catalog[item]['lens']))
 | 
			
		||||
            focals_list.append(catalog[item]['focal'])
 | 
			
		||||
            apertures_list.append(catalog[item]['aperture'])
 | 
			
		||||
            shutter_speeds_list.append(catalog[item]['shutter'])
 | 
			
		||||
            isos_list.append(catalog[item]['iso'])
 | 
			
		||||
            dimensions_list.append(
 | 
			
		||||
                round(((catalog[item]['height']*catalog[item]['width'])/10**6), 1))
 | 
			
		||||
            dates_list.append(catalog[item]['datetime'].strftime("%Y%m%d"))
 | 
			
		||||
    for camera in list(set(cameras_list)):
 | 
			
		||||
        if camera:
 | 
			
		||||
            cameras.update({camera: cameras_list.count(camera)})
 | 
			
		||||
    for lens in list(set(lenses_list)):
 | 
			
		||||
        if lens and "---" not in lens:
 | 
			
		||||
            lenses.update({lens: lenses_list.count(lens)})
 | 
			
		||||
    for camera_lense in list(set(cameras_lenses_list)):
 | 
			
		||||
        if camera_lense:
 | 
			
		||||
            cameras_lenses.update(
 | 
			
		||||
                {camera_lense: cameras_lenses_list.count(camera_lense)})
 | 
			
		||||
    for focal in list(set(focals_list)):
 | 
			
		||||
        if focal:
 | 
			
		||||
            focals.update({focal: focals_list.count(focal)})
 | 
			
		||||
    for aperture in list(set(apertures_list)):
 | 
			
		||||
        if aperture:
 | 
			
		||||
            apertures.update({aperture: apertures_list.count(aperture)})
 | 
			
		||||
    for shutter_speed in list(set(shutter_speeds_list)):
 | 
			
		||||
        if shutter_speed:
 | 
			
		||||
            shutter_speeds.update(
 | 
			
		||||
                {shutter_speed: shutter_speeds_list.count(shutter_speed)})
 | 
			
		||||
    for iso in list(set(isos_list)):
 | 
			
		||||
        if iso:
 | 
			
		||||
            isos.update({iso: isos_list.count(iso)})
 | 
			
		||||
    for dimension in list(set(dimensions_list)):
 | 
			
		||||
        if dimension:
 | 
			
		||||
            dimensions.update({dimension: dimensions_list.count(dimension)})
 | 
			
		||||
    for date in list(set(dates_list)):
 | 
			
		||||
        if date:
 | 
			
		||||
            dates.update({date: dates_list.count(date)})
 | 
			
		||||
    return {
 | 
			
		||||
        "total": len(dimensions_list),
 | 
			
		||||
        "date": dates,
 | 
			
		||||
        "cameras": cameras,
 | 
			
		||||
        "lenses": lenses,
 | 
			
		||||
        "cameras+lenses": cameras_lenses,
 | 
			
		||||
        "focals": focals,
 | 
			
		||||
        "apertures": apertures,
 | 
			
		||||
        "shutter_speeds": shutter_speeds,
 | 
			
		||||
        "isos": isos,
 | 
			
		||||
        "dimensions": dimensions
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
if __name__ == '__main__':
 | 
			
		||||
    import argparse
 | 
			
		||||
    import json
 | 
			
		||||
    parser = argparse.ArgumentParser()
 | 
			
		||||
    parser.add_argument("infile", help="lrcat file")
 | 
			
		||||
    parser.add_argument("-s", "--start-date", help="start date as YYYYMMDD. If omitted, begin of the collection.", const=None)
 | 
			
		||||
    parser.add_argument("-e", "--end-date", help="end date as YYYYMMDD. If omitted, today", const=None)
 | 
			
		||||
    args = parser.parse_args()
 | 
			
		||||
    if not args.start_date:
 | 
			
		||||
        args.start_date = "18250101" # Ok, that's the year of the 1st photography by Nicéphore Niépce. Shoul'd be enough for a start date.
 | 
			
		||||
    if not args.end_date:
 | 
			
		||||
        args.end_date = datetime.strftime(datetime.now(), "%Y%m%d")
 | 
			
		||||
    try:
 | 
			
		||||
        datetime.strptime(args.start_date, "%Y%m%d")
 | 
			
		||||
        datetime.strptime(args.end_date, "%Y%m%d")
 | 
			
		||||
    except ValueError:
 | 
			
		||||
        print("Date must be YYYYMMDD.")
 | 
			
		||||
        exit()
 | 
			
		||||
    print(json.dumps(extractor(args.infile, datetime.strptime(args.start_date, "%Y%m%d"), datetime.strptime(args.end_date, "%Y%m%d")), indent=4, sort_keys=True))
 | 
			
		||||
							
								
								
									
										395
									
								
								report.py
									
									
									
									
									
										Executable file
									
								
							
							
						
						@@ -0,0 +1,395 @@
 | 
			
		||||
#!/usr/bin/env python3
 | 
			
		||||
import numpy as np
 | 
			
		||||
from matplotlib import pyplot as plt
 | 
			
		||||
import json
 | 
			
		||||
import uuid
 | 
			
		||||
import gettext
 | 
			
		||||
from datetime import date, datetime, timedelta
 | 
			
		||||
from babel.dates import format_date
 | 
			
		||||
import locale
 | 
			
		||||
from os.path import isfile
 | 
			
		||||
from tempfile import mkdtemp
 | 
			
		||||
from shutil import copyfile, rmtree
 | 
			
		||||
from subprocess import run
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def i18n(language):
 | 
			
		||||
    try:
 | 
			
		||||
        lang = gettext.translation(
 | 
			
		||||
            'report', localedir='locales', languages=[language])
 | 
			
		||||
        lang.install()
 | 
			
		||||
    except FileNotFoundError:
 | 
			
		||||
        gettext.install('report')
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def bar(data, filename):
 | 
			
		||||
    '''
 | 
			
		||||
    Draw a bar chart from a documented JSON
 | 
			
		||||
    '''
 | 
			
		||||
    font = {'fontname': 'DejaVu Sans', 'size': 10, 'weight': 'normal'}
 | 
			
		||||
    x_location = np.arange(len(data['data']))
 | 
			
		||||
    fig = plt.figure(figsize=(data['width']/2.54, data['height']/2.54))
 | 
			
		||||
    bars = plt.bar(x_location, data['data'],
 | 
			
		||||
                   data['bar_width'], color=data['bar_color'])
 | 
			
		||||
    plt.ylabel(data['Y_label'], **font, fontsize='x-small')
 | 
			
		||||
    plt.title(data['title'], **font)
 | 
			
		||||
    plt.xticks(x_location, data['data_labels'], **font, fontsize='x-small', rotation=45)
 | 
			
		||||
    plt.yticks(**font, fontsize='x-small')
 | 
			
		||||
    plt.ylim(0, max(data['data'])*1.15)
 | 
			
		||||
    for bar in bars:
 | 
			
		||||
        height = bar.get_height()
 | 
			
		||||
        plt.text(bar.get_x() + bar.get_width()/2, height+(max(data['data'])/60), "{}\n({}%)".format(int(height), float(round(height/sum(data['data'])*100, 1))), ha='center', va='bottom', **font, fontsize='xx-small')
 | 
			
		||||
    plt.tight_layout()
 | 
			
		||||
    plt.savefig("{}".format(filename), dpi=300)
 | 
			
		||||
    plt.close(fig)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def pie(data, filename):
 | 
			
		||||
    '''
 | 
			
		||||
    Draw a pie chart
 | 
			
		||||
    '''
 | 
			
		||||
    font = {'fontname': 'DejaVu Sans', 'size': 10, 'weight': 'normal'}
 | 
			
		||||
    fig = plt.figure(figsize=(data['width']/2.54, data['height']/2.54))
 | 
			
		||||
    chart, texts, autotexts = plt.pie(data['parts'], labels=data['labels'],
 | 
			
		||||
            colors=data['colors'], autopct='%1.1f%%', explode=data['explode'], startangle=180)
 | 
			
		||||
    plt.title(data['title'], **font)
 | 
			
		||||
    for text in texts:
 | 
			
		||||
        text.set_size('x-small')
 | 
			
		||||
    for text in autotexts:
 | 
			
		||||
        text.set_size('xx-small')
 | 
			
		||||
    plt.savefig("{}".format(filename), dpi=300)
 | 
			
		||||
    plt.close(fig)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def format_shutter_speed(speed):
 | 
			
		||||
    speed = speed/1000
 | 
			
		||||
    if 1/speed >= 4:
 | 
			
		||||
        shutter_speed = "1/{}".format(int(round(1/speed, 0)))
 | 
			
		||||
    else:
 | 
			
		||||
        if speed < 60:
 | 
			
		||||
            shutter_speed = "{}'".format(round(speed, 3))
 | 
			
		||||
        else:
 | 
			
		||||
            speed_minutes = speed//60
 | 
			
		||||
            speed_seconds = speed%60
 | 
			
		||||
            shutter_speed = "{}\"{}'".format(speed_minutes, speed_seconds)
 | 
			
		||||
    return shutter_speed
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def title():
 | 
			
		||||
    '''
 | 
			
		||||
    Juste the title
 | 
			
		||||
    '''
 | 
			
		||||
    text = _("Statistical photo report")
 | 
			
		||||
    text += "\n"
 | 
			
		||||
    text += "#"*80
 | 
			
		||||
    text += "\n\n"
 | 
			
		||||
    return text
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def general(informations, language, colors, temp_dir):
 | 
			
		||||
    '''
 | 
			
		||||
    General informations. Take a dict() in argument.
 | 
			
		||||
    '''
 | 
			
		||||
    dimensions = []
 | 
			
		||||
    for dimension in informations['dimensions'].keys():
 | 
			
		||||
        dimensions.append(float(dimension))
 | 
			
		||||
    text = _("Pictures informations")
 | 
			
		||||
    text += "\n"
 | 
			
		||||
    text += "="*80
 | 
			
		||||
    text += "\n"
 | 
			
		||||
    informations_total = informations['total']
 | 
			
		||||
    start_date = datetime.strptime(sorted(informations['date'])[0], "%Y%m%d").date()
 | 
			
		||||
    end_date = datetime.strptime(sorted(informations['date'])[-1], "%Y%m%d").date()
 | 
			
		||||
    most_productive = datetime.strptime(sorted(informations['date'], key=informations['date'].get)[-1], "%Y%m%d").date()
 | 
			
		||||
    if informations_total > 1:
 | 
			
		||||
        text += _("The set contains {} pictures, ").format(informations['total'])
 | 
			
		||||
    elif informations_total == 1:
 | 
			
		||||
        text += _("The set contains only one picture, ").format(informations['total'])
 | 
			
		||||
    else:
 | 
			
		||||
        text += _("The set is empty. ")
 | 
			
		||||
    if start_date != end_date:
 | 
			
		||||
        text += _("taken from {} to {}. ").format(
 | 
			
		||||
            format_date(start_date, locale=language, format="medium"),
 | 
			
		||||
            format_date(end_date, locale=language, format="medium"))
 | 
			
		||||
        text += _("The most productive day was {} ({} shots). ").format(
 | 
			
		||||
            format_date(most_productive, locale=language, format="long"),
 | 
			
		||||
            informations['date'][sorted(informations['date'], key=informations['date'].get)[-1]])
 | 
			
		||||
    else:
 | 
			
		||||
        text += _("taken on {}. ").format(start_date)
 | 
			
		||||
    text += "\n\n"
 | 
			
		||||
    if informations_total > 1:
 | 
			
		||||
        text += _("Pictures sizes are from {1}{0}Mpx to {2}{0}Mpx, mostly {3}{0}Mpx. ").format(
 | 
			
		||||
            b'\xc2\xa0'.decode(),
 | 
			
		||||
            sorted(dimensions)[0],
 | 
			
		||||
            sorted(dimensions)[-1],
 | 
			
		||||
            sorted(informations['dimensions'], key=informations['dimensions'].get)[-1])
 | 
			
		||||
    else:
 | 
			
		||||
        text += _("Picture size is {}{}Mpx. ").format(sorted(dimensions)[0], b'\xc2\xa0'.decode())
 | 
			
		||||
    text += "\n\n"
 | 
			
		||||
    if start_date != end_date:
 | 
			
		||||
        dates = {datetime.strptime(k, "%Y%m%d"):int(v) for k,v in informations['date'].items()}
 | 
			
		||||
        top_date = sorted(dates, key=dates.get, reverse=True)[0:20]
 | 
			
		||||
        new_date = {}
 | 
			
		||||
        for date in top_date:
 | 
			
		||||
            new_date.update({date: dates[date]})
 | 
			
		||||
        bar(
 | 
			
		||||
                {
 | 
			
		||||
                    'width': 16,
 | 
			
		||||
                    'height': 12,
 | 
			
		||||
                    'data': [new_date[date] for date in sorted(new_date)],
 | 
			
		||||
                    'data_labels': [format_date(date, locale=language, format="short") for date in sorted(new_date)],
 | 
			
		||||
                    'title': _("Distribution of shots by date{}").format(_(" : top 20") if len(top_date) == 20 else ""),
 | 
			
		||||
                    'Y_label': _("Number of shots"),
 | 
			
		||||
                    'bar_color': colors[2],
 | 
			
		||||
                    'bar_width': 0.8
 | 
			
		||||
                },
 | 
			
		||||
                temp_dir + "/picnb_datetime.pdf")
 | 
			
		||||
        text += ".. figure:: picnb_datetime.pdf\n\t:width: 16cm\n"
 | 
			
		||||
    return text
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def camera_and_lens(informations, language, colors, temp_dir):
 | 
			
		||||
    '''
 | 
			
		||||
    Informations about cameras and lenses used.
 | 
			
		||||
    '''
 | 
			
		||||
    with open("helpers/dictionary.json") as file:
 | 
			
		||||
        helper = json.load(file)
 | 
			
		||||
    text = _("Cameras & lenses")
 | 
			
		||||
    text += "\n"
 | 
			
		||||
    text += "="*80
 | 
			
		||||
    text += "\n\n"
 | 
			
		||||
    top_couple = sorted(informations['cameras+lenses'], key=informations['cameras+lenses'].get)[-1].split(" + ")
 | 
			
		||||
    top_couple_camera, top_couple_lens = top_couple[0], top_couple[1]
 | 
			
		||||
    top_lens = sorted(informations['lenses'], key=informations['lenses'].get)[-1]
 | 
			
		||||
    top_camera = sorted(informations['cameras'], key=informations['cameras'].get)[-1]
 | 
			
		||||
    text += _("The most commonly used couple is {} with {}. ").format(
 | 
			
		||||
            (helper['camera'][top_couple_camera]['brand'] + " " + helper['camera'][top_couple_camera]['name']) if top_couple_camera in helper['camera'] else top_couple_camera,
 | 
			
		||||
            (helper['lens'][top_couple_lens]['brand'] + " " + helper['lens'][top_couple_lens]['name']) if top_couple_lens in helper['lens'] else top_couple_lens,)
 | 
			
		||||
    text += "\n\n"
 | 
			
		||||
    if len(informations['lenses']) > 1:
 | 
			
		||||
        text += _("There are {} lenses, the most used is the {}. ").format(
 | 
			
		||||
                len(informations['lenses']),
 | 
			
		||||
                (helper['lens'][top_lens]['brand'] + " " + helper['lens'][top_lens]['name']) if top_lens in helper['lens'] else top_lens)
 | 
			
		||||
    else:
 | 
			
		||||
        text += _("The lens is a {}. ").format(
 | 
			
		||||
            (helper['lens'][top_lens]['brand'] + " " + helper['lens'][top_lens]['name']) if top_lens in helper['lens'] else top_lens)
 | 
			
		||||
    text += _("The favorite aperture is {}{}, ").format(
 | 
			
		||||
            _("F"),
 | 
			
		||||
            sorted(informations['apertures'], key=informations['apertures'].get)[-1])
 | 
			
		||||
    text += _("and the favorite focal lenght is {}mm. ").format(
 | 
			
		||||
            sorted(informations['focals'], key=informations['focals'].get)[-1])
 | 
			
		||||
    text += "\n\n"
 | 
			
		||||
    if len(informations['cameras']) > 1:
 | 
			
		||||
        text += _("There are {} cameras, the mose used is the {}. ").format(
 | 
			
		||||
                len(informations['cameras']),
 | 
			
		||||
                (helper['camera'][top_camera]['brand'] + " " + helper['camera'][top_camera]['name']) if top_camera in helper['camera'] else top_camera)
 | 
			
		||||
    else:
 | 
			
		||||
        text += _("The camera is a {}. ").format(
 | 
			
		||||
            (helper['camera'][top_camera]['brand'] + " " + helper['camera'][top_camera]['name']) if top_camera in helper['camera'] else top_camera)
 | 
			
		||||
    text += _(" The favorite ISO is {}. ").format(
 | 
			
		||||
            sorted(informations['isos'], key=informations['isos'].get)[-1])
 | 
			
		||||
    text += "\n\n"
 | 
			
		||||
    if isfile("helpers/cameras/{}.jpg".format(top_camera.replace(" ", "_").replace("/", "_"))):
 | 
			
		||||
        copyfile(
 | 
			
		||||
                "helpers/cameras/{}.jpg".format(top_camera.replace(" ", "_").replace("/", "_")),
 | 
			
		||||
                "{}/{}.jpg".format(temp_dir, top_camera.replace(" ", "_").replace("/", "_")))
 | 
			
		||||
        text += ".. image:: {}.jpg\n\t:width: 8cm\n\t:align: left\n".format(top_camera.replace(" ", "_").replace("/", "_"))
 | 
			
		||||
    if isfile("helpers/lenses/{}.jpg".format(top_lens.replace(" ", "_").replace("/", "_"))):
 | 
			
		||||
        copyfile(
 | 
			
		||||
                "helpers/lenses/{}.jpg".format(top_lens.replace(" ", "_").replace("/", "_")),
 | 
			
		||||
                "{}/{}.jpg".format(temp_dir, top_lens.replace(" ", "_").replace("/", "_")))
 | 
			
		||||
        text += ".. image:: {}.jpg\n\t:width: 8cm\n\t:align: right\n".format(top_lens.replace(" ", "_").replace("/", "_"))
 | 
			
		||||
    if len(informations['cameras']) > 1:
 | 
			
		||||
        pie(
 | 
			
		||||
                {
 | 
			
		||||
                    'width': 17,
 | 
			
		||||
                    'height': 8,
 | 
			
		||||
                    'parts': [informations['cameras'][camera] for camera in sorted(informations['cameras'], key=informations['cameras'].get)],
 | 
			
		||||
                    'labels': [((helper['camera'][camera]['brand'] + " " + helper['camera'][camera]['name']) if camera in helper['camera'] else camera) for camera in sorted(informations['cameras'], key=informations['cameras'].get)],
 | 
			
		||||
                    'colors': colors[0:len(list(informations['cameras'].keys()))],
 | 
			
		||||
                    'explode': [0.02]*len(list(informations['cameras'].keys())),
 | 
			
		||||
                    'title': _("Cameras")
 | 
			
		||||
                },
 | 
			
		||||
                temp_dir + "/cameras_parts.pdf")
 | 
			
		||||
        text += "\n\n"
 | 
			
		||||
        text += ".. figure:: cameras_parts.pdf\n\t:width: 17cm\n"
 | 
			
		||||
    if len(informations['lenses']) > 1:
 | 
			
		||||
        pie(
 | 
			
		||||
                {
 | 
			
		||||
                    'width': 17,
 | 
			
		||||
                    'height': 8,
 | 
			
		||||
                    'parts': [informations['lenses'][lens] for lens in sorted(informations['lenses'], key=informations['lenses'].get)],
 | 
			
		||||
                    'labels': [((helper['lens'][lens]['brand'] + " " + helper['lens'][lens]['name']) if lens in helper['lens'] else lens) for lens in sorted(informations['lenses'], key=informations['lenses'].get)],
 | 
			
		||||
                    'colors': colors[0:len(list(informations['lenses'].keys()))],
 | 
			
		||||
                    'explode': [0.02]*len(list(informations['lenses'].keys())),
 | 
			
		||||
                    'title': _("Lenses")
 | 
			
		||||
                },
 | 
			
		||||
                temp_dir + "/lenses_parts.pdf")
 | 
			
		||||
        text += "\n\n"
 | 
			
		||||
        text += ".. figure:: lenses_parts.pdf\n\t:width: 17cm\n"
 | 
			
		||||
    return text
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def focal_aperture(informations, language, colors, temp_dir):
 | 
			
		||||
    text = _("Focal lengths & apertures")
 | 
			
		||||
    text += "\n" + "="*80 + "\n"
 | 
			
		||||
    text += "\n\n"
 | 
			
		||||
    text += _("Focal lenghts")
 | 
			
		||||
    text += "\n" + "-"*80 + "\n"
 | 
			
		||||
    if len(informations['focals']) > 1:
 | 
			
		||||
        focals = {float(k): int(v) for k,v in informations['focals'].items()}
 | 
			
		||||
        top_focals = sorted(focals, key=focals.get, reverse=True)[0:20]
 | 
			
		||||
        new_focals = {}
 | 
			
		||||
        for focal in top_focals:
 | 
			
		||||
            new_focals.update({focal: focals[focal]})
 | 
			
		||||
        bar(
 | 
			
		||||
                {
 | 
			
		||||
                    'width': 17,
 | 
			
		||||
                    'height': 8,
 | 
			
		||||
                    'data': [new_focals[focal] for focal in sorted(new_focals)],
 | 
			
		||||
                    'bar_width': 0.8,
 | 
			
		||||
                    'bar_color': colors[0],
 | 
			
		||||
                    'data_labels': ["{} mm".format(int(focal) if int(focal) == float(focal) else float(focal)) for focal in sorted(new_focals)],
 | 
			
		||||
                    'Y_label': _("Number of shots"),
 | 
			
		||||
                    'title': _("Focals{}").format(_(" : top 20") if len(top_focals) == 20 else "")
 | 
			
		||||
                },
 | 
			
		||||
                temp_dir + "/focal_lenghts.pdf")
 | 
			
		||||
        text += ".. figure:: focal_lenghts.pdf\n\t:width: 17cm\n"
 | 
			
		||||
    else:
 | 
			
		||||
        text += _("Only one focal lenght is used : {}mm. ").format(float(sorted(informations['focals'], key=informations['focals'].get)[0]))
 | 
			
		||||
    text += "\n\n"
 | 
			
		||||
    text += _("Apertures")
 | 
			
		||||
    text += "\n" + "-"*80 + "\n"
 | 
			
		||||
    if len(informations['apertures']) > 1:
 | 
			
		||||
        apertures = {float(k):int(v) for k,v in informations['apertures'].items()}
 | 
			
		||||
        top_apertures = sorted(apertures, key=apertures.get, reverse=True)[0:20]
 | 
			
		||||
        new_apertures = {}
 | 
			
		||||
        for aperture in top_apertures:
 | 
			
		||||
            new_apertures.update({aperture: apertures[aperture]})
 | 
			
		||||
        bar(
 | 
			
		||||
                {
 | 
			
		||||
                    'width': 17,
 | 
			
		||||
                    'height': 8,
 | 
			
		||||
                    'data': [new_apertures[aperture] for aperture in sorted(new_apertures)],
 | 
			
		||||
                    'bar_width': 0.8,
 | 
			
		||||
                    'bar_color': colors[5],
 | 
			
		||||
                    'data_labels': ["{}{}".format(_("F"), int(aperture) if int(aperture) == float(aperture) else float(aperture)) for aperture in sorted(new_apertures)],
 | 
			
		||||
                    'Y_label': _("Number of shots"),
 | 
			
		||||
                    'title': _("Apertures{}").format(_(" : top 20") if len(top_apertures) == 20 else "")
 | 
			
		||||
                },
 | 
			
		||||
                temp_dir + "/apertures.pdf")
 | 
			
		||||
        text += ".. figure:: apertures.pdf\n\t:width: 17cm\n"
 | 
			
		||||
    else:
 | 
			
		||||
        text += _("Only one aperture is used : {}{}. ").format(
 | 
			
		||||
                    _("F"),
 | 
			
		||||
                    float(sorted(informations['apertures'], key=informations['apertures'].get)[0]))
 | 
			
		||||
    text += "\n\n"
 | 
			
		||||
    return text
 | 
			
		||||
 | 
			
		||||
def iso_shutter(informations, language, colors, temp_dir):
 | 
			
		||||
    text = _("ISO sensitivities & shutter speeds")
 | 
			
		||||
    text += "\n" + "="*80 + "\n"
 | 
			
		||||
    text += _("ISO sensitivities")
 | 
			
		||||
    text += "\n" + "-"*80 + "\n"
 | 
			
		||||
    if len(informations['isos']) > 1:
 | 
			
		||||
        isos = {float(k):int(v) for k,v in informations['isos'].items()}
 | 
			
		||||
        top_isos = sorted(isos, key=isos.get, reverse=True)[0:20]
 | 
			
		||||
        new_isos = {}
 | 
			
		||||
        for iso in top_isos:
 | 
			
		||||
            new_isos.update({iso: isos[iso]})
 | 
			
		||||
        bar(
 | 
			
		||||
                {
 | 
			
		||||
                    'width': 17,
 | 
			
		||||
                    'height': 8,
 | 
			
		||||
                    'data': [new_isos[iso] for iso in sorted(new_isos)],
 | 
			
		||||
                    'bar_width': 0.8,
 | 
			
		||||
                    'bar_color': colors[3],
 | 
			
		||||
                    'data_labels': ["ISO {}".format(int(iso) if int(iso) == float(iso) else float(iso)) for iso in sorted(new_isos)],
 | 
			
		||||
                    'Y_label': _("Number of shots"),
 | 
			
		||||
                    'title': _("ISO sensibilities{}").format(_(" : top 20") if len(top_isos) == 20 else "")
 | 
			
		||||
                },
 | 
			
		||||
                temp_dir + "/isos.pdf")
 | 
			
		||||
        text += ".. figure:: isos.pdf\n\t:width: 17cm\n"
 | 
			
		||||
    else:
 | 
			
		||||
        text += _("All shots at the same sensitivity : ISO {} ").format(sorted(informations['isos'], key=informations['isos'].get)[0])
 | 
			
		||||
    text += "\n\n"
 | 
			
		||||
    text += _("Shutter speeds")
 | 
			
		||||
    text += "\n" + "-"*80 + "\n"
 | 
			
		||||
    if len(informations['shutter_speeds']) > 1:
 | 
			
		||||
        shutter_speeds = {float(k):int(v) for k,v in informations['shutter_speeds'].items()}
 | 
			
		||||
        top_shutter_speeds = sorted(shutter_speeds, key=shutter_speeds.get, reverse=True)[0:20]
 | 
			
		||||
        new_shutter_speeds = {}
 | 
			
		||||
        for shutter_speed in top_shutter_speeds:
 | 
			
		||||
            new_shutter_speeds.update({shutter_speed: shutter_speeds[shutter_speed]})
 | 
			
		||||
        bar(
 | 
			
		||||
                {
 | 
			
		||||
                    'width': 17,
 | 
			
		||||
                    'height': 8,
 | 
			
		||||
                    'data': [new_shutter_speeds[shutter_speed] for shutter_speed in sorted(new_shutter_speeds)],
 | 
			
		||||
                    'bar_width': 0.8,
 | 
			
		||||
                    'bar_color': colors[7],
 | 
			
		||||
                    'data_labels': [format_shutter_speed(shutter_speed) for shutter_speed in sorted(new_shutter_speeds)],
 | 
			
		||||
                    'Y_label': _("Number of shots"),
 | 
			
		||||
                    'title': _("Shutter speeds{}").format(_(" : top 20") if len(top_shutter_speeds) == 20 else "")
 | 
			
		||||
                },
 | 
			
		||||
                temp_dir + "/speeds.pdf")
 | 
			
		||||
        text += ".. figure:: speeds.pdf\n\t:width: 17cm\n"
 | 
			
		||||
    else:
 | 
			
		||||
        text += _("All shots at the same speed : {}. ").format(format_shutter_speed(sorted(informations['shutter_speeds'], key=informations['shutter_speeds'].get)[0]))
 | 
			
		||||
    return text
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def footer():
 | 
			
		||||
    return ".. footer::\n\n\t###Page###\n\n"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def page_break():
 | 
			
		||||
    return ".. raw:: pdf\n\n\tPageBreak\n\n"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def create(informations, language, output_file):
 | 
			
		||||
    with open("helpers/dictionary.json") as file:
 | 
			
		||||
        helper = json.load(file)
 | 
			
		||||
    colors = [
 | 
			
		||||
            "#b58900", # yellow
 | 
			
		||||
            "#cb4b16", # orange
 | 
			
		||||
            "#dc322f", # red
 | 
			
		||||
            "#d33682", # magenta
 | 
			
		||||
            "#6c71c4", # violet
 | 
			
		||||
            "#268bd2", # blue
 | 
			
		||||
            "#2aa198", # cyan
 | 
			
		||||
            "#859900" # green
 | 
			
		||||
            ]
 | 
			
		||||
    i18n(language)
 | 
			
		||||
    temp_dir = mkdtemp()
 | 
			
		||||
    document = footer()
 | 
			
		||||
    document += title()
 | 
			
		||||
    document += general(informations, language, colors, temp_dir)
 | 
			
		||||
    document += page_break()
 | 
			
		||||
    document += camera_and_lens(informations, language, colors, temp_dir)
 | 
			
		||||
    document += page_break()
 | 
			
		||||
    document += focal_aperture(informations, language, colors, temp_dir)
 | 
			
		||||
    document += page_break()
 | 
			
		||||
    document += iso_shutter(informations, language, colors, temp_dir)
 | 
			
		||||
    with open(temp_dir + "/report.rst", "w") as rst_file:
 | 
			
		||||
        rst_file.write(document)
 | 
			
		||||
    try:
 | 
			
		||||
        run(["rst2pdf", temp_dir + "/report.rst", "-s", "rst2pdf_stylsheet.style", "--use-floating-images", "-o", output_file], check=True)
 | 
			
		||||
        rmtree(temp_dir)
 | 
			
		||||
        return True
 | 
			
		||||
    except CalledProcessError:
 | 
			
		||||
        return False
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
if __name__ == '__main__':
 | 
			
		||||
    import argparse
 | 
			
		||||
    import json
 | 
			
		||||
    parser = argparse.ArgumentParser()
 | 
			
		||||
    parser.add_argument("infile", help="JSON output from a reader")
 | 
			
		||||
    parser.add_argument("--lang", help="i18n option", default="en")
 | 
			
		||||
    parser.add_argument("--out", "-o", help="outfile", default="./report.pdf")
 | 
			
		||||
    args = parser.parse_args()
 | 
			
		||||
    with open(args.infile, "r") as json_data:
 | 
			
		||||
        data = json.load(json_data)
 | 
			
		||||
    create(data, args.lang, args.out)
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										16
									
								
								rst2pdf_stylsheet.style
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,16 @@
 | 
			
		||||
{"fontsAlias": {
 | 
			
		||||
  "stdFont": "DejaVu Sans",
 | 
			
		||||
  "stdBold": "DejaVu Sans",
 | 
			
		||||
  "stdItalic": "DejaVu Sans",
 | 
			
		||||
  "stdBoldItalic": "DejaVu Sans",
 | 
			
		||||
  "sdtMono": "DejaVu Sans Mono"
 | 
			
		||||
},
 | 
			
		||||
"pageSetup": {
 | 
			
		||||
  "size": "A4",
 | 
			
		||||
  "width": null,
 | 
			
		||||
  "height": null,
 | 
			
		||||
  "margin-top": "1.2cm",
 | 
			
		||||
  "margin-bottom": "1cm",
 | 
			
		||||
  "margin-left": "1.5cm",
 | 
			
		||||
  "margin-right": "1.5cm"
 | 
			
		||||
}}
 | 
			
		||||