Releasing 3.1.2
124
CNIRevelator.py
Normal file
@ -0,0 +1,124 @@
|
|||||||
|
"""
|
||||||
|
********************************************************************************
|
||||||
|
* CNIRevelator *
|
||||||
|
* *
|
||||||
|
* Desc: Application launcher & updater *
|
||||||
|
* *
|
||||||
|
* Copyright © 2018-2019 Adrien Bourmault (neox95) *
|
||||||
|
* *
|
||||||
|
* *
|
||||||
|
* This file is part of CNIRevelator. *
|
||||||
|
* *
|
||||||
|
* CNIRevelator is free software: you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU General Public License as published by *
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or *
|
||||||
|
* any later version. *
|
||||||
|
* *
|
||||||
|
* CNIRevelator is distributed in the hope that it will be useful, *
|
||||||
|
* but WITHOUT ANY WARRANTY*without even the implied warranty of *
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||||
|
* GNU General Public License for more details. *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU General Public License *
|
||||||
|
* along with CNIRevelator. If not, see <https:*www.gnu.org/licenses/>. *
|
||||||
|
********************************************************************************
|
||||||
|
"""
|
||||||
|
# Import critical files
|
||||||
|
import os
|
||||||
|
import threading
|
||||||
|
|
||||||
|
import lang # lang.py
|
||||||
|
import logger # logger.py
|
||||||
|
import globs # globs.py
|
||||||
|
import critical # critical.py
|
||||||
|
|
||||||
|
# Import all other files and crash if necessary
|
||||||
|
try:
|
||||||
|
|
||||||
|
import launcher # launcher.py"
|
||||||
|
import updater # updater.py
|
||||||
|
import pytesseract # pytesseract.py
|
||||||
|
import ihm # ihm.py
|
||||||
|
from tkinter.messagebox import *
|
||||||
|
from tkinter import *
|
||||||
|
except:
|
||||||
|
critical.crashCNIR()
|
||||||
|
|
||||||
|
# Global handler
|
||||||
|
logfile = logger.logCur
|
||||||
|
|
||||||
|
## MAIN FUNCTION OF CNIREVELATOR
|
||||||
|
def main():
|
||||||
|
logfile.printdbg('*** CNIRevelator LOGFILE. Hello World ! ***')
|
||||||
|
|
||||||
|
mainw = mainWindow()
|
||||||
|
|
||||||
|
try:
|
||||||
|
os.environ['PATH'] = globs.CNIRFolder + '\\Tesseract-OCR5\\'
|
||||||
|
os.environ['TESSDATA_PREFIX'] = globs.CNIRFolder + '\\Tesseract-OCR5\\tessdata'
|
||||||
|
tesser_version = pytesseract.get_tesseract_version()
|
||||||
|
except Exception as e:
|
||||||
|
logfile.printerr('ERROR WITH TESSERACT MODULE ' + str(e))
|
||||||
|
else:
|
||||||
|
text = 'Tesseract version ' + str(tesser_version) + ' Licensed Apache 2004 successfully initiated\n'
|
||||||
|
mainw.logOnTerm(text)
|
||||||
|
|
||||||
|
mainw.logOnTerm('\n\n{} \n'.format(lang.all[globs.CNIRlang]["Please type a MRZ or open a scan"]))
|
||||||
|
|
||||||
|
# changelog
|
||||||
|
if globs.CNIRNewVersion:
|
||||||
|
mainw.after_idle(mainw.showChangeLog)
|
||||||
|
|
||||||
|
logfile.printdbg('main() : **** Launching App_main() ****')
|
||||||
|
try:
|
||||||
|
mainw.mainloop()
|
||||||
|
except Exception as e:
|
||||||
|
showerror(lang.all[globs.CNIRlang]["CNIRevelator Fatal Error"], "{} : {}".format(lang.all[globs.CNIRlang]["An error has occured"],e), parent=mainw)
|
||||||
|
logfile.printdbg('main() : **** Ending App_main() ****')
|
||||||
|
|
||||||
|
logfile.printdbg('*** CNIRevelator LOGFILE. Goodbye World ! ***')
|
||||||
|
logfile.close()
|
||||||
|
|
||||||
|
|
||||||
|
## BOOTSTRAP OF CNIREVELATOR
|
||||||
|
try:
|
||||||
|
|
||||||
|
try:
|
||||||
|
# LANGUAGE
|
||||||
|
lang.readLang()
|
||||||
|
except:
|
||||||
|
critical.crashCNIR()
|
||||||
|
updater.exitProcess(1)
|
||||||
|
|
||||||
|
from main import * # main.py
|
||||||
|
# GO
|
||||||
|
try:
|
||||||
|
launcherThread = threading.Thread(target=updater.umain, daemon=False)
|
||||||
|
launcher.lmain(launcherThread)
|
||||||
|
except Exception:
|
||||||
|
critical.crashCNIR(False)
|
||||||
|
|
||||||
|
if updater.UPDATE_IS_MADE:
|
||||||
|
# Launch app !
|
||||||
|
args = updater.UPATH + '\\CNIRevelator.exe' + " DELETE " + globs.CNIRFolder
|
||||||
|
cd = updater.UPATH
|
||||||
|
for i in range(0,3):
|
||||||
|
try:
|
||||||
|
updater.spawnProcess(args, cd)
|
||||||
|
except:
|
||||||
|
time.sleep(3)
|
||||||
|
continue
|
||||||
|
break
|
||||||
|
updater.exitProcess(0)
|
||||||
|
|
||||||
|
# Here we go !
|
||||||
|
try:
|
||||||
|
main()
|
||||||
|
except Exception as e:
|
||||||
|
critical.crashCNIR()
|
||||||
|
updater.exitProcess(1)
|
||||||
|
|
||||||
|
except:
|
||||||
|
critical.crashCNIR()
|
||||||
|
|
||||||
|
updater.exitProcess(0)
|
BIN
Invert.png
Normal file
After Width: | Height: | Size: 553 B |
BIN
background.png
Normal file
After Width: | Height: | Size: 82 KiB |
235
background.svg
Normal file
@ -0,0 +1,235 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||||
|
|
||||||
|
<svg
|
||||||
|
xmlns:osb="http://www.openswatchbook.org/uri/2009/osb"
|
||||||
|
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||||
|
xmlns:cc="http://creativecommons.org/ns#"
|
||||||
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
width="210mm"
|
||||||
|
height="297mm"
|
||||||
|
viewBox="0 0 210 297"
|
||||||
|
version="1.1"
|
||||||
|
id="svg8"
|
||||||
|
inkscape:version="0.92.4 (5da689c313, 2019-01-14)"
|
||||||
|
sodipodi:docname="background.svg"
|
||||||
|
inkscape:export-filename="D:\Public\CNIRevelator-master\CNIRevelator-master\id-card.ico.png"
|
||||||
|
inkscape:export-xdpi="96"
|
||||||
|
inkscape:export-ydpi="96">
|
||||||
|
<defs
|
||||||
|
id="defs2">
|
||||||
|
<linearGradient
|
||||||
|
inkscape:collect="always"
|
||||||
|
id="linearGradient2382">
|
||||||
|
<stop
|
||||||
|
style="stop-color:#006699;stop-opacity:1;"
|
||||||
|
offset="0"
|
||||||
|
id="stop2378" />
|
||||||
|
<stop
|
||||||
|
style="stop-color:#006699;stop-opacity:0;"
|
||||||
|
offset="1"
|
||||||
|
id="stop2380" />
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient
|
||||||
|
id="linearGradient2360"
|
||||||
|
osb:paint="solid">
|
||||||
|
<stop
|
||||||
|
style="stop-color:#006699;stop-opacity:1;"
|
||||||
|
offset="0"
|
||||||
|
id="stop2358" />
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient
|
||||||
|
id="linearGradient6642"
|
||||||
|
osb:paint="solid">
|
||||||
|
<stop
|
||||||
|
style="stop-color:#006699;stop-opacity:1;"
|
||||||
|
offset="0"
|
||||||
|
id="stop6640" />
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient
|
||||||
|
id="linearGradient6634"
|
||||||
|
osb:paint="gradient">
|
||||||
|
<stop
|
||||||
|
style="stop-color:#006699;stop-opacity:1;"
|
||||||
|
offset="0"
|
||||||
|
id="stop6630" />
|
||||||
|
<stop
|
||||||
|
style="stop-color:#006699;stop-opacity:0;"
|
||||||
|
offset="1"
|
||||||
|
id="stop6632" />
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient
|
||||||
|
id="linearGradient6624"
|
||||||
|
osb:paint="gradient">
|
||||||
|
<stop
|
||||||
|
style="stop-color:#006699;stop-opacity:1;"
|
||||||
|
offset="0"
|
||||||
|
id="stop6620" />
|
||||||
|
<stop
|
||||||
|
style="stop-color:#006699;stop-opacity:0;"
|
||||||
|
offset="1"
|
||||||
|
id="stop6622" />
|
||||||
|
</linearGradient>
|
||||||
|
<meshgradient
|
||||||
|
inkscape:collect="always"
|
||||||
|
id="meshgradient6684"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
x="21.469046"
|
||||||
|
y="95.009521"
|
||||||
|
gradientTransform="matrix(1.1362933,0,0,1.063401,-17.304581,-33.164658)">
|
||||||
|
<meshrow
|
||||||
|
id="meshrow8749">
|
||||||
|
<meshpatch
|
||||||
|
id="meshpatch8751">
|
||||||
|
<stop
|
||||||
|
path="c 84.9889,-0.489892 216.909,-47.2726 172.056,5.23565e-06"
|
||||||
|
style="stop-color:#ffffff;stop-opacity:1"
|
||||||
|
id="stop8753" />
|
||||||
|
<stop
|
||||||
|
path="c 0,35.0258 27.3277,78.3796 0,105.077"
|
||||||
|
style="stop-color:#0066a3;stop-opacity:1"
|
||||||
|
id="stop8755" />
|
||||||
|
<stop
|
||||||
|
path="c -57.3516,0 -114.704,0.000313733 -172.056,0.000374711"
|
||||||
|
style="stop-color:#ffffff;stop-opacity:1"
|
||||||
|
id="stop8757" />
|
||||||
|
<stop
|
||||||
|
path="c -109.31,-65.1529 0.000895128,-70.052 0,-105.077"
|
||||||
|
style="stop-color:#0066a3;stop-opacity:1"
|
||||||
|
id="stop8759" />
|
||||||
|
</meshpatch>
|
||||||
|
</meshrow>
|
||||||
|
</meshgradient>
|
||||||
|
<radialGradient
|
||||||
|
inkscape:collect="always"
|
||||||
|
xlink:href="#linearGradient2382"
|
||||||
|
id="radialGradient2384"
|
||||||
|
cx="396.2852"
|
||||||
|
cy="468.11764"
|
||||||
|
fx="396.2852"
|
||||||
|
fy="468.11764"
|
||||||
|
r="369.64817"
|
||||||
|
gradientTransform="matrix(1,0,0,0.56950675,0,201.52149)"
|
||||||
|
gradientUnits="userSpaceOnUse" />
|
||||||
|
</defs>
|
||||||
|
<sodipodi:namedview
|
||||||
|
id="base"
|
||||||
|
pagecolor="#ffffff"
|
||||||
|
bordercolor="#666666"
|
||||||
|
borderopacity="1.0"
|
||||||
|
inkscape:pageopacity="0.0"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:zoom="0.35"
|
||||||
|
inkscape:cx="-154.28572"
|
||||||
|
inkscape:cy="560"
|
||||||
|
inkscape:document-units="mm"
|
||||||
|
inkscape:current-layer="layer1"
|
||||||
|
showgrid="false"
|
||||||
|
inkscape:window-width="1920"
|
||||||
|
inkscape:window-height="1021"
|
||||||
|
inkscape:window-x="1358"
|
||||||
|
inkscape:window-y="-8"
|
||||||
|
inkscape:window-maximized="1" />
|
||||||
|
<metadata
|
||||||
|
id="metadata5">
|
||||||
|
<rdf:RDF>
|
||||||
|
<cc:Work
|
||||||
|
rdf:about="">
|
||||||
|
<dc:format>image/svg+xml</dc:format>
|
||||||
|
<dc:type
|
||||||
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||||
|
<dc:title></dc:title>
|
||||||
|
</cc:Work>
|
||||||
|
</rdf:RDF>
|
||||||
|
</metadata>
|
||||||
|
<g
|
||||||
|
inkscape:label="Calque 1"
|
||||||
|
inkscape:groupmode="layer"
|
||||||
|
id="layer1">
|
||||||
|
<path
|
||||||
|
style="fill:#006699;fill-opacity:0;stroke-width:0.28439415"
|
||||||
|
d="m 84.721063,124.78009 v -18.1023 h 35.244247 35.24426 v 18.1023 18.1023 H 119.96531 84.721063 Z"
|
||||||
|
id="path3715"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
inkscape:export-xdpi="62.28421"
|
||||||
|
inkscape:export-ydpi="62.28421" />
|
||||||
|
<path
|
||||||
|
style="fill:#006699;fill-opacity:0;stroke-width:0.28439415"
|
||||||
|
d="m 84.596851,124.78009 v -18.1023 h 35.399509 35.39952 v 18.1023 18.1023 H 119.99636 84.596851 Z"
|
||||||
|
id="path4522"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
inkscape:export-xdpi="62.28421"
|
||||||
|
inkscape:export-ydpi="62.28421" />
|
||||||
|
<rect
|
||||||
|
style="opacity:1;fill:url(#meshgradient6684);fill-opacity:1;fill-rule:evenodd;stroke-width:0.2908414"
|
||||||
|
id="rect6026"
|
||||||
|
width="195.50467"
|
||||||
|
height="111.73937"
|
||||||
|
x="7.0905566"
|
||||||
|
y="67.868561"
|
||||||
|
inkscape:export-xdpi="62.28421"
|
||||||
|
inkscape:export-ydpi="62.28421" />
|
||||||
|
<path
|
||||||
|
style="opacity:1;fill:none;fill-opacity:0;stroke:none;stroke-width:0.10665803"
|
||||||
|
id="path6702"
|
||||||
|
sodipodi:type="arc"
|
||||||
|
sodipodi:cx="-106.96722"
|
||||||
|
sodipodi:cy="91.675934"
|
||||||
|
sodipodi:rx="27.00486"
|
||||||
|
sodipodi:ry="14.752526"
|
||||||
|
sodipodi:start="0"
|
||||||
|
sodipodi:end="0.01294104"
|
||||||
|
d="m -79.962357,91.675934 a 27.00486,14.752526 0 0 1 -0.0023,0.190908 l -27.002602,-0.190908 z"
|
||||||
|
inkscape:export-xdpi="96"
|
||||||
|
inkscape:export-ydpi="96" />
|
||||||
|
<path
|
||||||
|
style="opacity:1;fill:none;fill-opacity:0;stroke:none;stroke-width:0.09953795"
|
||||||
|
id="path6704"
|
||||||
|
sodipodi:type="arc"
|
||||||
|
sodipodi:cx="50.128902"
|
||||||
|
sodipodi:cy="117.01824"
|
||||||
|
sodipodi:rx="19.252365"
|
||||||
|
sodipodi:ry="0.91162664"
|
||||||
|
sodipodi:start="0"
|
||||||
|
sodipodi:end="0.01294104"
|
||||||
|
d="m 69.381268,117.01824 a 19.252365,0.91162664 0 0 1 -0.0016,0.0118 l -19.250753,-0.0118 z"
|
||||||
|
inkscape:export-xdpi="62.28421"
|
||||||
|
inkscape:export-ydpi="62.28421" />
|
||||||
|
<path
|
||||||
|
style="opacity:1;fill:#006699;fill-opacity:0;stroke:none;stroke-width:0.70548797"
|
||||||
|
d="m 54.328279,151.38009 c 6.738287,-0.18153 9.860558,-0.51601 9.860558,-1.0563 0,-0.43485 -0.214401,-0.58316 -0.476446,-0.32955 -0.262045,0.2536 -1.220099,-0.70936 -2.129014,-2.13994 -0.908912,-1.43057 -1.662638,-2.39129 -1.67495,-2.13492 -0.0123,0.25635 -1.232541,-0.6806 -2.711623,-2.08211 -3.041003,-2.88151 -11.20904,-8.16141 -15.56345,-10.06037 -5.025034,-2.1914 -15.48499,-5.17516 -24.607335,-7.01935 -4.837953,-0.97804 -8.9524961,-1.77826 -9.1434291,-1.77826 -0.190932,0 -0.3471493,-3.90394 -0.3471493,-8.67542 0,-7.7854 0.128749,-8.67924 1.2549803,-8.71272 4.0321241,-0.11985 12.8335191,-0.78443 18.1075721,-1.36727 9.548641,-1.05522 9.999721,-0.99605 10.872131,1.42595 l 0.757679,2.10346 8.348445,-0.19488 8.348442,-0.19487 1.12821,-3.28965 c 0.620515,-1.8093 1.265931,-3.4125 1.434262,-3.56264 0.168331,-0.15015 2.042385,-0.47238 4.164565,-0.71606 2.122181,-0.24367 4.065255,-0.5667 4.317942,-0.71785 0.252685,-0.15114 1.797669,-0.46796 3.433295,-0.70405 4.289131,-0.619126 19.404432,-4.873023 24.662715,-6.940837 5.267804,-2.071562 5.679741,-2.120459 5.679741,-0.674222 0,0.98671 4.46405,1.055298 46.07569,0.708032 25.34165,-0.211474 45.33864,-0.156571 44.43778,0.122013 -1.47944,0.457514 -0.97636,1.00161 5.1992,5.623008 l 6.83714,5.116466 v 10.71956 c 0,9.89196 -0.0969,10.69004 -1.25498,10.33748 -1.128,-0.34341 -8.59991,-1.79357 -9.24131,-1.79357 -0.14338,0 -0.26068,-0.78079 -0.26068,-1.73508 v -1.73509 H 146.3004 100.76254 v 3.12315 3.12316 l 24.2032,0.0358 c 22.52599,0.0333 24.00441,0.1094 21.33466,1.09839 -10.57291,3.91663 -15.72347,6.59657 -20.82107,10.83365 -3.43941,2.85881 -5.35424,4.78609 -5.35424,5.38906 0,0.3784 -0.26817,0.688 -0.59594,0.688 -0.32778,0 -1.05387,0.85887 -1.61355,1.9086 -0.55968,1.04972 -1.39216,2.29341 -1.84998,2.76374 -0.45782,0.47033 -0.94972,1.1958 -1.09313,1.61215 -0.1823,0.52932 -10.82435,0.81596 -35.382744,0.95301 -19.317115,0.10781 -30.684777,0.0765 -25.261467,-0.0697 z m 19.536724,-24.5107 c 0.785136,-1.22945 -2.274815,-6.70861 -4.750306,-8.50591 -6.072977,-4.40923 -12.372723,-6.19003 -21.831412,-6.17126 -14.146328,0.0281 -23.792567,4.80423 -26.431687,13.08717 -0.488044,1.53174 -0.432748,1.54246 9.052578,1.75703 24.444874,0.55296 43.547386,0.48038 43.960827,-0.16703 z m 117.837267,-14.4092 -0.22258,-2.60262 -45.35858,-0.17869 -45.35857,-0.17868 v 2.78131 2.78131 h 45.58116 45.58114 z m -0.22258,-10.58401 v -3.123144 l -45.71714,-0.178641 -45.71713,-0.178649 v 3.480434 3.48045 l 45.71713,-0.17865 45.71714,-0.17864 z"
|
||||||
|
id="path8763"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
inkscape:export-xdpi="62.28421"
|
||||||
|
inkscape:export-ydpi="62.28421" />
|
||||||
|
<path
|
||||||
|
style="opacity:1;fill:#006699;fill-opacity:0;stroke:none;stroke-width:0.70548797"
|
||||||
|
d="m 100.16596,112.80721 -0.12054,-2.60262 -7.350605,0.0226 c -4.042825,0.0125 -15.095617,0.32729 -24.561753,0.69967 -9.466139,0.37238 -26.973114,0.85132 -38.90439,1.06432 l -21.6932314,0.38725 v -6.50485 -6.504868 l 9.5019934,-1.239163 c 5.226096,-0.681544 11.680281,-1.630765 14.342631,-2.109373 l 4.840639,-0.870217 0.06885,3.189611 c 0.03787,1.75427 0.443033,4.75117 0.900383,6.65976 l 0.83154,3.47017 8.661056,0.19394 8.661056,0.19394 0.944402,-2.97008 c 0.519425,-1.63353 1.013139,-5.76662 1.097147,-9.184628 0.144724,-5.888493 0.242562,-6.24101 1.864677,-6.718555 0.941564,-0.2772 4.61632,-1.349587 8.166119,-2.383112 C 80.69971,83.733484 97.128366,76.646908 106.55855,70.716662 l 4.52902,-2.84811 h 18.90595 18.90596 l -2.18965,2.949639 c -1.2043,1.622303 -4.45144,5.691589 -7.21587,9.042856 -2.76443,3.351263 -5.02623,6.236327 -5.02623,6.411256 0,0.17492 11.6982,0.410435 25.99602,0.523367 15.74964,0.124401 9.0365,0.238497 -17.03188,0.289492 l -43.0279,0.0841 -0.22051,2.842206 -0.220517,2.842218 38.228487,0.164089 c 29.94874,0.128546 32.94759,0.209257 13.84602,0.372641 l -24.38247,0.20856 -1.79283,2.372666 -1.79283,2.372666 -11.83267,0.20433 -11.83268,0.204329 v 3.123153 3.12315 l 8.85258,0.34701 8.85259,0.34701 -1.54912,1.90255 -1.5491,1.90254 38.59295,0.18571 38.59295,0.18573 -45.67384,0.16734 -45.67386,0.16736 -0.28129,2.60263 -0.28131,2.60262 z"
|
||||||
|
id="path8765"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
inkscape:export-xdpi="62.28421"
|
||||||
|
inkscape:export-ydpi="62.28421" />
|
||||||
|
<rect
|
||||||
|
style="fill:none;fill-rule:evenodd;stroke-width:0.26252428"
|
||||||
|
id="rect8795"
|
||||||
|
width="211.66666"
|
||||||
|
height="192.01192"
|
||||||
|
x="0"
|
||||||
|
y="25.613092"
|
||||||
|
inkscape:export-xdpi="96"
|
||||||
|
inkscape:export-ydpi="96" />
|
||||||
|
<path
|
||||||
|
style="stroke-width:2.85714293;fill:url(#radialGradient2384);fill-opacity:1"
|
||||||
|
d="m 327.53554,676.44371 c 17.57689,-1.4528 19.34434,-2.1236 15.60946,-5.92402 -2.31646,-2.35715 -9.95032,-12.63463 -16.96412,-22.83889 -7.01377,-10.20423 -14.90228,-20.94643 -17.53,-23.87154 -2.62772,-2.92512 -6.31942,-9.04046 -8.20377,-13.58969 -1.88435,-4.54923 -4.55582,-8.27131 -5.9366,-8.27131 -1.38078,0 -2.51051,-2.2876 -2.51051,-5.08355 0,-2.79594 -2.57143,-6.93691 -5.71429,-9.20217 -3.14286,-2.26525 -5.71428,-5.8218 -5.71428,-7.90345 0,-2.08169 -3.21429,-6.99915 -7.14286,-10.92772 -3.92857,-3.92857 -7.14286,-8.4244 -7.14286,-9.99071 0,-6.09009 -40.33587,-47.06195 -55.01673,-55.88422 -34.19795,-20.55081 -80.77342,-32.34706 -167.126126,-42.32833 l -15,-1.73381 -0.581558,42.24126 c -0.409107,29.71536 -0.898633,35.03976 -1.650835,17.95555 -0.588103,-13.35714 -0.195722,-46.2837 0.871956,-73.17012 l 1.941234,-48.88442 27.388795,-1.92524 c 64.814594,-4.55601 146.518134,-17.28486 203.458984,-31.6975 90.3622,-22.87212 145.61422,-46.66066 200.94522,-86.51618 l 25.23098,-18.17412 107.62617,-0.84172 c 59.19443,-0.46295 92.64054,-0.34165 74.32474,0.26956 l -33.30146,1.11129 -0.99308,14.72469 c -1.74083,25.81205 9.47623,54.65464 26.03854,66.95335 2.42803,1.80299 7.46017,5.94339 11.18254,9.20089 3.72237,3.2575 9.18666,6.6904 12.14286,7.62866 2.9562,0.93827 5.37491,2.90501 5.37491,4.37054 0,1.46554 1.08826,2.66461 2.41838,2.66461 2.52662,0 48.26877,26.3865 53.37017,30.78676 1.61228,1.39067 6.43371,4.82329 10.71428,7.62804 l 7.78289,5.09954 0.62671,-68.18574 c 0.45615,-49.62888 0.90106,-57.29967 1.63486,-28.18574 0.55449,22 0.12829,69.90005 -0.94689,106.44455 l -1.95508,66.44456 -17.53694,-2.00253 c -19.89995,-2.27237 -61.31123,-2.85877 -84.6798,-1.19911 -37.85563,2.68855 -120.12878,26.68601 -134.51069,39.23412 -2.48089,2.16456 -5.37077,3.93555 -6.42197,3.93555 -7.82706,0 -51.76997,39.08254 -54.8484,48.7818 -0.96077,3.02714 -2.94594,5.50391 -4.41149,5.50391 -1.46551,0 -2.6646,1.92858 -2.6646,4.28572 0,2.35714 -1.28571,4.28571 -2.85714,4.28571 -1.57143,0 -2.85714,3.85715 -2.85714,8.57143 0,5.52234 -1.45143,8.57143 -4.08012,8.57143 -4.83474,0 -8.73463,23.07814 -8.74908,51.77374 l -0.009,18.91663 -22.86635,1.78054 c -12.57648,0.97932 -42.15205,1.56123 -65.72348,1.29315 -31.42752,-0.35743 -37.571,-0.92435 -23.03589,-2.12575 z"
|
||||||
|
id="path82"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
transform="scale(0.26458333)"
|
||||||
|
inkscape:export-xdpi="62.28421"
|
||||||
|
inkscape:export-ydpi="62.28421" />
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 14 KiB |
66
critical.py
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
"""
|
||||||
|
********************************************************************************
|
||||||
|
* CNIRevelator *
|
||||||
|
* *
|
||||||
|
* Desc: Critical Stuff for CNIRevelator *
|
||||||
|
* *
|
||||||
|
* Copyright © 2018-2019 Adrien Bourmault (neox95) *
|
||||||
|
* *
|
||||||
|
* This file is part of CNIRevelator. *
|
||||||
|
* *
|
||||||
|
* CNIRevelator is free software: you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU General Public License as published by *
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or *
|
||||||
|
* any later version. *
|
||||||
|
* *
|
||||||
|
* CNIRevelator is distributed in the hope that it will be useful, *
|
||||||
|
* but WITHOUT ANY WARRANTY*without even the implied warranty of *
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||||
|
* GNU General Public License for more details. *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU General Public License *
|
||||||
|
* along with CNIRevelator. If not, see <https:*www.gnu.org/licenses/>. *
|
||||||
|
********************************************************************************
|
||||||
|
"""
|
||||||
|
from tkinter.messagebox import *
|
||||||
|
from importlib import reload
|
||||||
|
from tkinter import *
|
||||||
|
import webbrowser
|
||||||
|
import traceback
|
||||||
|
import psutil
|
||||||
|
import os
|
||||||
|
|
||||||
|
import lang # lang.py
|
||||||
|
import logger # logger.py
|
||||||
|
import globs # globs.py
|
||||||
|
|
||||||
|
def crashCNIR(shutdown=True):
|
||||||
|
"""
|
||||||
|
very last solution
|
||||||
|
"""
|
||||||
|
|
||||||
|
try:
|
||||||
|
root = Tk()
|
||||||
|
root.withdraw()
|
||||||
|
logfile = logger.logCur
|
||||||
|
logfile.printerr("FATAL ERROR : see traceback below.\n{}".format(traceback.format_exc()))
|
||||||
|
showerror(lang.all[globs.CNIRlang]["CNIRevelator Fatal Eror"], lang.all[globs.CNIRlang]["CNIRevelator crashed because a fatal error occured. View log for more infos and please open an issue on Github"])
|
||||||
|
res = askquestion(lang.all[globs.CNIRlang]["CNIRevelator Fatal Eror"], lang.all[globs.CNIRlang]["Would you like to open the log file ?"])
|
||||||
|
if res == "yes":
|
||||||
|
webbrowser.open_new(globs.CNIRErrLog)
|
||||||
|
res = askquestion(lang.all[globs.CNIRlang]["CNIRevelator Fatal Eror"], lang.all[globs.CNIRlang]["Would you like to open an issue on Github to report this bug ?"])
|
||||||
|
if res == "yes":
|
||||||
|
webbrowser.open_new("https://github.com/neox95/CNIRevelator/issues")
|
||||||
|
root.destroy()
|
||||||
|
|
||||||
|
# Quit ?
|
||||||
|
if not shutdown:
|
||||||
|
return
|
||||||
|
|
||||||
|
# Quit totally without remain in memory
|
||||||
|
for process in psutil.process_iter():
|
||||||
|
if process.pid == os.getpid():
|
||||||
|
process.terminate()
|
||||||
|
sys.exit(arg)
|
||||||
|
except:
|
||||||
|
traceback.print_exc()
|
214
downloader.py
Normal file
@ -0,0 +1,214 @@
|
|||||||
|
"""
|
||||||
|
********************************************************************************
|
||||||
|
* CNIRevelator *
|
||||||
|
* *
|
||||||
|
* Desc: Application launcher download stuff *
|
||||||
|
* *
|
||||||
|
* Copyright © 2018-2019 Adrien Bourmault (neox95) *
|
||||||
|
* *
|
||||||
|
* This file is part of CNIRevelator. *
|
||||||
|
* *
|
||||||
|
* CNIRevelator is free software: you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU General Public License as published by *
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or *
|
||||||
|
* any later version. *
|
||||||
|
* *
|
||||||
|
* CNIRevelator is distributed in the hope that it will be useful, *
|
||||||
|
* but WITHOUT ANY WARRANTY*without even the implied warranty of *
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||||
|
* GNU General Public License for more details. *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU General Public License *
|
||||||
|
* along with CNIRevelator. If not, see <https:*www.gnu.org/licenses/>. *
|
||||||
|
********************************************************************************
|
||||||
|
"""
|
||||||
|
|
||||||
|
import base64, hashlib
|
||||||
|
import os
|
||||||
|
from pypac import PACSession
|
||||||
|
from requests.auth import HTTPProxyAuth
|
||||||
|
from Crypto import Random
|
||||||
|
from Crypto.Cipher import AES
|
||||||
|
from requests import Session
|
||||||
|
from time import time
|
||||||
|
|
||||||
|
import critical # critical.py
|
||||||
|
import logger # logger.py
|
||||||
|
import globs # globs.py
|
||||||
|
import ihm # ihm.py
|
||||||
|
import lang # lang.py
|
||||||
|
|
||||||
|
class AESCipher(object):
|
||||||
|
|
||||||
|
def __init__(self, key):
|
||||||
|
self.bs = 32
|
||||||
|
self.key = hashlib.sha256(key.encode()).digest()
|
||||||
|
|
||||||
|
def encrypt(self, raw):
|
||||||
|
raw = self._pad(raw)
|
||||||
|
iv = Random.new().read(AES.block_size)
|
||||||
|
cipher = AES.new(self.key, AES.MODE_CBC, iv)
|
||||||
|
return base64.b64encode(iv + cipher.encrypt(raw))
|
||||||
|
|
||||||
|
def decrypt(self, enc):
|
||||||
|
enc = base64.b64decode(enc)
|
||||||
|
iv = enc[:AES.block_size]
|
||||||
|
cipher = AES.new(self.key, AES.MODE_CBC, iv)
|
||||||
|
return self._unpad(cipher.decrypt(enc[AES.block_size:])).decode('utf-8')
|
||||||
|
|
||||||
|
def _pad(self, s):
|
||||||
|
return s + (self.bs - len(s) % self.bs) * chr(self.bs - len(s) % self.bs)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _unpad(s):
|
||||||
|
return s[:-ord(s[len(s) - 1:])]
|
||||||
|
|
||||||
|
|
||||||
|
class newcredentials:
|
||||||
|
def __init__(self):
|
||||||
|
|
||||||
|
logfile = logger.logCur
|
||||||
|
|
||||||
|
self.login = ''
|
||||||
|
self.password = ''
|
||||||
|
self.valid = False
|
||||||
|
self.readInTheBooks = False
|
||||||
|
self.trying = 0
|
||||||
|
|
||||||
|
while True:
|
||||||
|
session = PACSession(proxy_auth=(HTTPProxyAuth(self.login, self.password)))
|
||||||
|
self.trying += 1
|
||||||
|
|
||||||
|
try:
|
||||||
|
sessionAnswer = session.get('https://www.google.com')
|
||||||
|
except Exception as e:
|
||||||
|
logfile.printdbg('Network Error : ' + str(e))
|
||||||
|
sessionAnswer = ''
|
||||||
|
|
||||||
|
logfile.printdbg("Session Answer : " + str(sessionAnswer))
|
||||||
|
|
||||||
|
if str(sessionAnswer) == '<Response [200]>':
|
||||||
|
logfile.printdbg('Successfully connected to the Internet !')
|
||||||
|
self.sessionHandler = session
|
||||||
|
self.valid = True
|
||||||
|
return
|
||||||
|
|
||||||
|
if str(sessionAnswer) != '<Response [407]>' and self.trying > 2:
|
||||||
|
# because sometimes the proxy does not return an error (especially if we do not provide either credentials)
|
||||||
|
logfile.printerr('Network Error, or need a proxy !')
|
||||||
|
return
|
||||||
|
|
||||||
|
if self.trying > 4:
|
||||||
|
logfile.printerr('Invalid credentials : access denied, a maximum of 3 trials have been raised !')
|
||||||
|
return
|
||||||
|
|
||||||
|
logfile.printdbg('Invalid credentials : access denied')
|
||||||
|
|
||||||
|
# Deleting the root of Evil if needed
|
||||||
|
if self.readInTheBooks:
|
||||||
|
os.remove(globs.CNIRConfig)
|
||||||
|
logfile.printdbg("Deleting the root of Evil")
|
||||||
|
|
||||||
|
try:
|
||||||
|
with open(globs.CNIRConfig, 'rb') as (configFile):
|
||||||
|
self.readInTheBooks = True
|
||||||
|
# Decrypt the config file
|
||||||
|
AESObj = AESCipher(globs.CNIRCryptoKey)
|
||||||
|
try:
|
||||||
|
# Reading it
|
||||||
|
reading = AESObj.decrypt(configFile.read())
|
||||||
|
# Parsing it
|
||||||
|
if reading != '||':
|
||||||
|
if reading.find('||') != -1:
|
||||||
|
# TADAAA
|
||||||
|
self.login, self.password = reading.split('||')[0:2]
|
||||||
|
else:
|
||||||
|
# UPS
|
||||||
|
logfile.printerr('Cryptokey is bad !')
|
||||||
|
return
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
raise IOError(str(e))
|
||||||
|
|
||||||
|
except FileNotFoundError:
|
||||||
|
logfile.printdbg('We will ask for credentials then')
|
||||||
|
|
||||||
|
launcherWindow = ihm.launcherWindowCur
|
||||||
|
|
||||||
|
# Parameters for the password invite
|
||||||
|
invite = ihm.LoginDialog(launcherWindow)
|
||||||
|
invite.transient(launcherWindow)
|
||||||
|
invite.grab_set()
|
||||||
|
|
||||||
|
launcherWindow.wait_window(invite)
|
||||||
|
|
||||||
|
# Getting the credentials
|
||||||
|
self.login = invite.login
|
||||||
|
self.password = invite.key
|
||||||
|
|
||||||
|
AESObj = AESCipher(globs.CNIRCryptoKey)
|
||||||
|
try:
|
||||||
|
os.mkdir(globs.CNIRFolder + '\\config')
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
with open(globs.CNIRConfig, 'wb+') as (configFile):
|
||||||
|
logfile.printdbg('Saving credentials in encrypted config file')
|
||||||
|
configFile.write(AESObj.encrypt(self.login + '||' + self.password))
|
||||||
|
|
||||||
|
|
||||||
|
return
|
||||||
|
|
||||||
|
class newdownload:
|
||||||
|
def __init__(self, credentials, urlFile, destinationFile, title):
|
||||||
|
self.urlFile = urlFile
|
||||||
|
self.destinationFile = destinationFile
|
||||||
|
self.session = credentials.sessionHandler
|
||||||
|
self.title = title
|
||||||
|
|
||||||
|
logfile = logger.logCur
|
||||||
|
launcherWindow = ihm.launcherWindowCur
|
||||||
|
|
||||||
|
logfile.printdbg('Requesting download of {}'.format(urlFile))
|
||||||
|
|
||||||
|
self.handler = self.session.get(self.urlFile, stream=True, headers={'Connection' : 'close', "Cache-Control": "no-cache", "Pragma": "no-cache"})
|
||||||
|
self.handler.raise_for_status()
|
||||||
|
|
||||||
|
self.filesize = int(self.handler.headers['Content-length'])
|
||||||
|
self.chunksize = int(self.filesize / 7)
|
||||||
|
self.count = 0
|
||||||
|
|
||||||
|
def download(self):
|
||||||
|
logfile = logger.logCur
|
||||||
|
launcherWindow = ihm.launcherWindowCur
|
||||||
|
url = self.urlFile
|
||||||
|
filename = self.destinationFile
|
||||||
|
title = self.title
|
||||||
|
|
||||||
|
reducedFilename = filename.split("\\")[-1]
|
||||||
|
|
||||||
|
launcherWindow.printmsg('{} {}'.format(lang.all[globs.CNIRlang]["Downloading"], title))
|
||||||
|
logfile.printdbg('{} {}'.format("Downloading", reducedFilename))
|
||||||
|
|
||||||
|
try:
|
||||||
|
os.remove(filename)
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
|
with open(filename, 'wb') as fh:
|
||||||
|
for chunk in self.handler.iter_content(chunk_size=self.chunksize):
|
||||||
|
fh.write(chunk)
|
||||||
|
|
||||||
|
self.count = os.path.getsize(self.destinationFile)
|
||||||
|
Percent = self.count / self.filesize * 100
|
||||||
|
|
||||||
|
launcherWindow.progressBar.stop()
|
||||||
|
launcherWindow.progressBar.configure(mode='determinate', value=(int(Percent)), maximum=100)
|
||||||
|
launcherWindow.printmsg('{} {}'.format(lang.all[globs.CNIRlang]["Downloading"], title) + ' : {:4.2f} %'.format(Percent))
|
||||||
|
|
||||||
|
launcherWindow.progressBar.configure(mode='indeterminate', value=0, maximum=20)
|
||||||
|
launcherWindow.progressBar.start()
|
||||||
|
|
||||||
|
logfile.printdbg('{} {}'.format(lang.all[globs.CNIRlang]["Successful retrieved"], filename))
|
||||||
|
|
||||||
|
return filename
|
||||||
|
|
71
globs.py
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
"""
|
||||||
|
********************************************************************************
|
||||||
|
* CNIRevelator *
|
||||||
|
* *
|
||||||
|
* Desc: Application launcher global variables *
|
||||||
|
* *
|
||||||
|
* Copyright © 2018-2019 Adrien Bourmault (neox95) *
|
||||||
|
* *
|
||||||
|
* This file is part of CNIRevelator. *
|
||||||
|
* *
|
||||||
|
* CNIRevelator is free software: you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU General Public License as published by *
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or *
|
||||||
|
* any later version. *
|
||||||
|
* *
|
||||||
|
* CNIRevelator is distributed in the hope that it will be useful, *
|
||||||
|
* but WITHOUT ANY WARRANTY*without even the implied warranty of *
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||||
|
* GNU General Public License for more details. *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU General Public License *
|
||||||
|
* along with CNIRevelator. If not, see <https:*www.gnu.org/licenses/>. *
|
||||||
|
********************************************************************************
|
||||||
|
"""
|
||||||
|
import os
|
||||||
|
|
||||||
|
# CNIRevelator version
|
||||||
|
verType = "final release"
|
||||||
|
version = [3, 1, 2]
|
||||||
|
verstring_full = "{}.{}.{} {}".format(version[0], version[1], version[2], verType)
|
||||||
|
verstring = "{}.{}".format(version[0], version[1])
|
||||||
|
|
||||||
|
CNIRTesserHash = '5b58db27f7bc08c58a2cb33d01533b034b067cf8'
|
||||||
|
CNIRFolder = os.getcwd()
|
||||||
|
CNIRLColor = "#006699"
|
||||||
|
CNIRName = "CNIRevelator {}".format(verstring)
|
||||||
|
CNIRCryptoKey = '82Xh!efX3#@P~2eG'
|
||||||
|
CNIRNewVersion = False
|
||||||
|
|
||||||
|
CNIRConfig = CNIRFolder + '\\config\\conf.ig'
|
||||||
|
CNIRTesser = CNIRFolder + '\\Tesseract-OCR5\\'
|
||||||
|
CNIRErrLog = CNIRFolder + '\\logs\\error.log'
|
||||||
|
CNIRMainLog = CNIRFolder + '\\logs\\main.log'
|
||||||
|
CNIRUrlConfig = CNIRFolder + '\\config\\urlconf.ig'
|
||||||
|
CNIRVerStock = CNIRFolder + '\\downloads\\versions.lst'
|
||||||
|
CNIREnv = CNIRFolder + '\\Data\\'
|
||||||
|
|
||||||
|
|
||||||
|
CNIRTesserHash = '947224361ffab8c01f05c9394b44b1bd7c8c3d4d'
|
||||||
|
CNIRFolder = os.path.dirname(os.path.realpath(__file__))
|
||||||
|
CNIRLColor = "#006699"
|
||||||
|
CNIRName = "CNIRevelator {}".format(verstring)
|
||||||
|
CNIRCryptoKey = '82Xh!efX3#@P~2eG'
|
||||||
|
|
||||||
|
CNIRLangFile = CNIRFolder + '\\config\\lang.ig'
|
||||||
|
CNIRlang = "fr"
|
||||||
|
|
||||||
|
CNIRConfig = CNIRFolder + '\\config\\conf.ig'
|
||||||
|
CNIRTesser = CNIRFolder + '\\Tesseract-OCR5\\'
|
||||||
|
CNIRErrLog = CNIRFolder + '\\logs\\error.log'
|
||||||
|
CNIRMainLog = CNIRFolder + '\\logs\\main.log'
|
||||||
|
CNIRUrlConfig = CNIRFolder + '\\config\\urlconf.ig'
|
||||||
|
CNIRVerStock = CNIRFolder + '\\downloads\\versions.lst'
|
||||||
|
CNIREnv = CNIRFolder + '\\Data\\'
|
||||||
|
|
||||||
|
CNIRBetaURL = "https://raw.githubusercontent.com/neox95/CNIRevelator/v3.1/VERSIONS.LST"
|
||||||
|
CNIRDefaultURL = "https://raw.githubusercontent.com/neox95/CNIRevelator/master/VERSIONS.LST"
|
||||||
|
|
||||||
|
CNIRNewVersion = False
|
||||||
|
CNIROpenFile = False
|
||||||
|
debug = True
|
BIN
id-card.ico
Normal file
After Width: | Height: | Size: 16 KiB |
BIN
id-card.ico.png
Normal file
After Width: | Height: | Size: 70 KiB |
279
id-card.svg
Normal file
@ -0,0 +1,279 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||||
|
|
||||||
|
<svg
|
||||||
|
xmlns:osb="http://www.openswatchbook.org/uri/2009/osb"
|
||||||
|
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||||
|
xmlns:cc="http://creativecommons.org/ns#"
|
||||||
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
width="210mm"
|
||||||
|
height="297mm"
|
||||||
|
viewBox="0 0 210 297"
|
||||||
|
version="1.1"
|
||||||
|
id="svg8"
|
||||||
|
inkscape:version="0.92.4 (5da689c313, 2019-01-14)"
|
||||||
|
sodipodi:docname="id-card.svg"
|
||||||
|
inkscape:export-filename="D:\Public\CNIRevelator-master\CNIRevelator-master\id-card.ico.png"
|
||||||
|
inkscape:export-xdpi="96"
|
||||||
|
inkscape:export-ydpi="96">
|
||||||
|
<defs
|
||||||
|
id="defs2">
|
||||||
|
<linearGradient
|
||||||
|
id="linearGradient6642"
|
||||||
|
osb:paint="solid">
|
||||||
|
<stop
|
||||||
|
style="stop-color:#006699;stop-opacity:1;"
|
||||||
|
offset="0"
|
||||||
|
id="stop6640" />
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient
|
||||||
|
inkscape:collect="always"
|
||||||
|
id="linearGradient6634"
|
||||||
|
osb:paint="gradient">
|
||||||
|
<stop
|
||||||
|
style="stop-color:#006699;stop-opacity:1;"
|
||||||
|
offset="0"
|
||||||
|
id="stop6630" />
|
||||||
|
<stop
|
||||||
|
style="stop-color:#006699;stop-opacity:0;"
|
||||||
|
offset="1"
|
||||||
|
id="stop6632" />
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient
|
||||||
|
inkscape:collect="always"
|
||||||
|
id="linearGradient6624"
|
||||||
|
osb:paint="gradient">
|
||||||
|
<stop
|
||||||
|
style="stop-color:#006699;stop-opacity:1;"
|
||||||
|
offset="0"
|
||||||
|
id="stop6620" />
|
||||||
|
<stop
|
||||||
|
style="stop-color:#006699;stop-opacity:0;"
|
||||||
|
offset="1"
|
||||||
|
id="stop6622" />
|
||||||
|
</linearGradient>
|
||||||
|
<meshgradient
|
||||||
|
inkscape:collect="always"
|
||||||
|
id="meshgradient6684"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
x="21.469046"
|
||||||
|
y="95.009521"
|
||||||
|
gradientTransform="matrix(1.1362933,0,0,1.063401,-17.304581,-33.164658)">
|
||||||
|
<meshrow
|
||||||
|
id="meshrow8749">
|
||||||
|
<meshpatch
|
||||||
|
id="meshpatch8751">
|
||||||
|
<stop
|
||||||
|
path="c 84.9889,-0.489892 216.909,-47.2726 172.056,5.23565e-06"
|
||||||
|
style="stop-color:#ffffff;stop-opacity:1"
|
||||||
|
id="stop8753" />
|
||||||
|
<stop
|
||||||
|
path="c 0,35.0258 27.3277,78.3796 0,105.077"
|
||||||
|
style="stop-color:#0066a3;stop-opacity:1"
|
||||||
|
id="stop8755" />
|
||||||
|
<stop
|
||||||
|
path="c -57.3516,0 -114.704,0.000313733 -172.056,0.000374711"
|
||||||
|
style="stop-color:#ffffff;stop-opacity:1"
|
||||||
|
id="stop8757" />
|
||||||
|
<stop
|
||||||
|
path="c -109.31,-65.1529 0.000895128,-70.052 0,-105.077"
|
||||||
|
style="stop-color:#0066a3;stop-opacity:1"
|
||||||
|
id="stop8759" />
|
||||||
|
</meshpatch>
|
||||||
|
</meshrow>
|
||||||
|
</meshgradient>
|
||||||
|
</defs>
|
||||||
|
<sodipodi:namedview
|
||||||
|
id="base"
|
||||||
|
pagecolor="#ffffff"
|
||||||
|
bordercolor="#666666"
|
||||||
|
borderopacity="1.0"
|
||||||
|
inkscape:pageopacity="0.0"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:zoom="0.35"
|
||||||
|
inkscape:cx="-117.14286"
|
||||||
|
inkscape:cy="560"
|
||||||
|
inkscape:document-units="mm"
|
||||||
|
inkscape:current-layer="layer1"
|
||||||
|
showgrid="false"
|
||||||
|
inkscape:window-width="1920"
|
||||||
|
inkscape:window-height="1021"
|
||||||
|
inkscape:window-x="1358"
|
||||||
|
inkscape:window-y="-8"
|
||||||
|
inkscape:window-maximized="1" />
|
||||||
|
<metadata
|
||||||
|
id="metadata5">
|
||||||
|
<rdf:RDF>
|
||||||
|
<cc:Work
|
||||||
|
rdf:about="">
|
||||||
|
<dc:format>image/svg+xml</dc:format>
|
||||||
|
<dc:type
|
||||||
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||||
|
<dc:title></dc:title>
|
||||||
|
</cc:Work>
|
||||||
|
</rdf:RDF>
|
||||||
|
</metadata>
|
||||||
|
<g
|
||||||
|
inkscape:label="Calque 1"
|
||||||
|
inkscape:groupmode="layer"
|
||||||
|
id="layer1">
|
||||||
|
<path
|
||||||
|
style="fill:#006699;fill-opacity:0;stroke-width:0.28439415"
|
||||||
|
d="m 84.721063,124.78009 v -18.1023 h 35.244247 35.24426 v 18.1023 18.1023 H 119.96531 84.721063 Z"
|
||||||
|
id="path3715"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
inkscape:export-xdpi="96"
|
||||||
|
inkscape:export-ydpi="96" />
|
||||||
|
<path
|
||||||
|
style="fill:#006699;fill-opacity:0;stroke-width:0.28439415"
|
||||||
|
d="m 84.596851,124.78009 v -18.1023 h 35.399509 35.39952 v 18.1023 18.1023 H 119.99636 84.596851 Z"
|
||||||
|
id="path4522"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
inkscape:export-xdpi="96"
|
||||||
|
inkscape:export-ydpi="96" />
|
||||||
|
<rect
|
||||||
|
style="opacity:1;fill:url(#meshgradient6684);fill-opacity:1;fill-rule:evenodd;stroke-width:0.2908414"
|
||||||
|
id="rect6026"
|
||||||
|
width="195.50467"
|
||||||
|
height="111.73937"
|
||||||
|
x="7.0905566"
|
||||||
|
y="67.868561"
|
||||||
|
inkscape:export-xdpi="96"
|
||||||
|
inkscape:export-ydpi="96" />
|
||||||
|
<path
|
||||||
|
style="opacity:1;fill:none;fill-opacity:0;stroke:none;stroke-width:0.10665803"
|
||||||
|
id="path6702"
|
||||||
|
sodipodi:type="arc"
|
||||||
|
sodipodi:cx="-106.96722"
|
||||||
|
sodipodi:cy="91.675934"
|
||||||
|
sodipodi:rx="27.00486"
|
||||||
|
sodipodi:ry="14.752526"
|
||||||
|
sodipodi:start="0"
|
||||||
|
sodipodi:end="0.01294104"
|
||||||
|
d="m -79.962357,91.675934 a 27.00486,14.752526 0 0 1 -0.0023,0.190908 l -27.002602,-0.190908 z"
|
||||||
|
inkscape:export-xdpi="96"
|
||||||
|
inkscape:export-ydpi="96" />
|
||||||
|
<path
|
||||||
|
style="opacity:1;fill:none;fill-opacity:0;stroke:none;stroke-width:0.09953795"
|
||||||
|
id="path6704"
|
||||||
|
sodipodi:type="arc"
|
||||||
|
sodipodi:cx="50.128902"
|
||||||
|
sodipodi:cy="117.01824"
|
||||||
|
sodipodi:rx="19.252365"
|
||||||
|
sodipodi:ry="0.91162664"
|
||||||
|
sodipodi:start="0"
|
||||||
|
sodipodi:end="0.01294104"
|
||||||
|
d="m 69.381268,117.01824 a 19.252365,0.91162664 0 0 1 -0.0016,0.0118 l -19.250753,-0.0118 z"
|
||||||
|
inkscape:export-xdpi="96"
|
||||||
|
inkscape:export-ydpi="96" />
|
||||||
|
<path
|
||||||
|
style="opacity:1;fill:#ffffff;fill-opacity:0.97927462;stroke:none;stroke-width:0.09953795"
|
||||||
|
id="path6706"
|
||||||
|
sodipodi:type="arc"
|
||||||
|
sodipodi:cx="47.334206"
|
||||||
|
sodipodi:cy="126.78566"
|
||||||
|
sodipodi:rx="26.394371"
|
||||||
|
sodipodi:ry="14.586026"
|
||||||
|
sodipodi:start="3.1320091"
|
||||||
|
sodipodi:end="0.019782596"
|
||||||
|
d="m 20.941047,126.92544 a 26.394371,14.586026 0 0 1 13.200663,-12.77315 26.394371,14.586026 0 0 1 26.61746,0.075 26.394371,14.586026 0 0 1 12.964242,12.84688"
|
||||||
|
sodipodi:open="true"
|
||||||
|
inkscape:export-xdpi="96"
|
||||||
|
inkscape:export-ydpi="96" />
|
||||||
|
<path
|
||||||
|
style="opacity:1;fill:#ffffff;fill-opacity:0.97927462;stroke:none;stroke-width:0.09953795"
|
||||||
|
id="path6708"
|
||||||
|
sodipodi:type="arc"
|
||||||
|
sodipodi:cx="46.868427"
|
||||||
|
sodipodi:cy="96.702003"
|
||||||
|
sodipodi:rx="10.402489"
|
||||||
|
sodipodi:ry="20.186018"
|
||||||
|
sodipodi:start="2.4930839"
|
||||||
|
sodipodi:end="0.65082534"
|
||||||
|
sodipodi:open="true"
|
||||||
|
d="m 38.577796,108.89433 a 10.402489,20.186018 0 0 1 1.284074,-27.112722 10.402489,20.186018 0 0 1 14.030908,0.03154 10.402489,20.186018 0 0 1 1.251703,27.118425"
|
||||||
|
inkscape:export-xdpi="96"
|
||||||
|
inkscape:export-ydpi="96" />
|
||||||
|
<rect
|
||||||
|
style="fill:#ffffff;fill-rule:evenodd;stroke-width:0.09308306"
|
||||||
|
id="rect6714"
|
||||||
|
width="90.982964"
|
||||||
|
height="5.7302251"
|
||||||
|
x="100.43346"
|
||||||
|
y="87.195045"
|
||||||
|
inkscape:export-xdpi="96"
|
||||||
|
inkscape:export-ydpi="96" />
|
||||||
|
<rect
|
||||||
|
style="fill:#ffffff;fill-rule:evenodd;stroke-width:0.09517508"
|
||||||
|
id="rect6714-6"
|
||||||
|
width="90.982964"
|
||||||
|
height="5.9906888"
|
||||||
|
x="100.43346"
|
||||||
|
y="-104.90665"
|
||||||
|
transform="scale(1,-1)"
|
||||||
|
inkscape:export-xdpi="96"
|
||||||
|
inkscape:export-ydpi="96" />
|
||||||
|
<rect
|
||||||
|
style="fill:#ffffff;fill-rule:evenodd;stroke-width:0.08650398"
|
||||||
|
id="rect6714-4"
|
||||||
|
width="90.982964"
|
||||||
|
height="4.9488306"
|
||||||
|
x="100.744"
|
||||||
|
y="-115.06476"
|
||||||
|
transform="scale(1,-1)"
|
||||||
|
inkscape:export-xdpi="96"
|
||||||
|
inkscape:export-ydpi="96" />
|
||||||
|
<rect
|
||||||
|
style="fill:#ffffff;fill-rule:evenodd;stroke-width:0.08875122"
|
||||||
|
id="rect6714-4-0"
|
||||||
|
width="90.982964"
|
||||||
|
height="5.2092953"
|
||||||
|
x="100.744"
|
||||||
|
y="120.53452"
|
||||||
|
inkscape:export-xdpi="96"
|
||||||
|
inkscape:export-ydpi="96" />
|
||||||
|
<rect
|
||||||
|
style="fill:#ffffff;fill-rule:evenodd;stroke-width:0.24659641"
|
||||||
|
id="rect6714-4-0-9"
|
||||||
|
width="180.10278"
|
||||||
|
height="20.316252"
|
||||||
|
x="13.332048"
|
||||||
|
y="151.79028"
|
||||||
|
inkscape:export-xdpi="96"
|
||||||
|
inkscape:export-ydpi="96" />
|
||||||
|
<path
|
||||||
|
style="opacity:1;fill:#006699;fill-opacity:0;stroke:none;stroke-width:0.70548797"
|
||||||
|
d="m 54.328279,151.38009 c 6.738287,-0.18153 9.860558,-0.51601 9.860558,-1.0563 0,-0.43485 -0.214401,-0.58316 -0.476446,-0.32955 -0.262045,0.2536 -1.220099,-0.70936 -2.129014,-2.13994 -0.908912,-1.43057 -1.662638,-2.39129 -1.67495,-2.13492 -0.0123,0.25635 -1.232541,-0.6806 -2.711623,-2.08211 -3.041003,-2.88151 -11.20904,-8.16141 -15.56345,-10.06037 -5.025034,-2.1914 -15.48499,-5.17516 -24.607335,-7.01935 -4.837953,-0.97804 -8.9524961,-1.77826 -9.1434291,-1.77826 -0.190932,0 -0.3471493,-3.90394 -0.3471493,-8.67542 0,-7.7854 0.128749,-8.67924 1.2549803,-8.71272 4.0321241,-0.11985 12.8335191,-0.78443 18.1075721,-1.36727 9.548641,-1.05522 9.999721,-0.99605 10.872131,1.42595 l 0.757679,2.10346 8.348445,-0.19488 8.348442,-0.19487 1.12821,-3.28965 c 0.620515,-1.8093 1.265931,-3.4125 1.434262,-3.56264 0.168331,-0.15015 2.042385,-0.47238 4.164565,-0.71606 2.122181,-0.24367 4.065255,-0.5667 4.317942,-0.71785 0.252685,-0.15114 1.797669,-0.46796 3.433295,-0.70405 4.289131,-0.619126 19.404432,-4.873023 24.662715,-6.940837 5.267804,-2.071562 5.679741,-2.120459 5.679741,-0.674222 0,0.98671 4.46405,1.055298 46.07569,0.708032 25.34165,-0.211474 45.33864,-0.156571 44.43778,0.122013 -1.47944,0.457514 -0.97636,1.00161 5.1992,5.623008 l 6.83714,5.116466 v 10.71956 c 0,9.89196 -0.0969,10.69004 -1.25498,10.33748 -1.128,-0.34341 -8.59991,-1.79357 -9.24131,-1.79357 -0.14338,0 -0.26068,-0.78079 -0.26068,-1.73508 v -1.73509 H 146.3004 100.76254 v 3.12315 3.12316 l 24.2032,0.0358 c 22.52599,0.0333 24.00441,0.1094 21.33466,1.09839 -10.57291,3.91663 -15.72347,6.59657 -20.82107,10.83365 -3.43941,2.85881 -5.35424,4.78609 -5.35424,5.38906 0,0.3784 -0.26817,0.688 -0.59594,0.688 -0.32778,0 -1.05387,0.85887 -1.61355,1.9086 -0.55968,1.04972 -1.39216,2.29341 -1.84998,2.76374 -0.45782,0.47033 -0.94972,1.1958 -1.09313,1.61215 -0.1823,0.52932 -10.82435,0.81596 -35.382744,0.95301 -19.317115,0.10781 -30.684777,0.0765 -25.261467,-0.0697 z m 19.536724,-24.5107 c 0.785136,-1.22945 -2.274815,-6.70861 -4.750306,-8.50591 -6.072977,-4.40923 -12.372723,-6.19003 -21.831412,-6.17126 -14.146328,0.0281 -23.792567,4.80423 -26.431687,13.08717 -0.488044,1.53174 -0.432748,1.54246 9.052578,1.75703 24.444874,0.55296 43.547386,0.48038 43.960827,-0.16703 z m 117.837267,-14.4092 -0.22258,-2.60262 -45.35858,-0.17869 -45.35857,-0.17868 v 2.78131 2.78131 h 45.58116 45.58114 z m -0.22258,-10.58401 v -3.123144 l -45.71714,-0.178641 -45.71713,-0.178649 v 3.480434 3.48045 l 45.71713,-0.17865 45.71714,-0.17864 z"
|
||||||
|
id="path8763"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
inkscape:export-xdpi="96"
|
||||||
|
inkscape:export-ydpi="96" />
|
||||||
|
<path
|
||||||
|
style="opacity:1;fill:#006699;fill-opacity:0;stroke:none;stroke-width:0.70548797"
|
||||||
|
d="m 100.16596,112.80721 -0.12054,-2.60262 -7.350605,0.0226 c -4.042825,0.0125 -15.095617,0.32729 -24.561753,0.69967 -9.466139,0.37238 -26.973114,0.85132 -38.90439,1.06432 l -21.6932314,0.38725 v -6.50485 -6.504868 l 9.5019934,-1.239163 c 5.226096,-0.681544 11.680281,-1.630765 14.342631,-2.109373 l 4.840639,-0.870217 0.06885,3.189611 c 0.03787,1.75427 0.443033,4.75117 0.900383,6.65976 l 0.83154,3.47017 8.661056,0.19394 8.661056,0.19394 0.944402,-2.97008 c 0.519425,-1.63353 1.013139,-5.76662 1.097147,-9.184628 0.144724,-5.888493 0.242562,-6.24101 1.864677,-6.718555 0.941564,-0.2772 4.61632,-1.349587 8.166119,-2.383112 C 80.69971,83.733484 97.128366,76.646908 106.55855,70.716662 l 4.52902,-2.84811 h 18.90595 18.90596 l -2.18965,2.949639 c -1.2043,1.622303 -4.45144,5.691589 -7.21587,9.042856 -2.76443,3.351263 -5.02623,6.236327 -5.02623,6.411256 0,0.17492 11.6982,0.410435 25.99602,0.523367 15.74964,0.124401 9.0365,0.238497 -17.03188,0.289492 l -43.0279,0.0841 -0.22051,2.842206 -0.220517,2.842218 38.228487,0.164089 c 29.94874,0.128546 32.94759,0.209257 13.84602,0.372641 l -24.38247,0.20856 -1.79283,2.372666 -1.79283,2.372666 -11.83267,0.20433 -11.83268,0.204329 v 3.123153 3.12315 l 8.85258,0.34701 8.85259,0.34701 -1.54912,1.90255 -1.5491,1.90254 38.59295,0.18571 38.59295,0.18573 -45.67384,0.16734 -45.67386,0.16736 -0.28129,2.60263 -0.28131,2.60262 z"
|
||||||
|
id="path8765"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
inkscape:export-xdpi="96"
|
||||||
|
inkscape:export-ydpi="96" />
|
||||||
|
<path
|
||||||
|
style="opacity:1;fill:#006699;fill-opacity:1;stroke:none;stroke-width:0.70548797"
|
||||||
|
d="m 46.260547,151.18011 c 6.845288,-0.23067 10.509758,-0.58818 9.538676,-0.9306 -0.867274,-0.30581 -1.771231,-1.1487 -2.008795,-1.87309 -0.237562,-0.72438 -1.031972,-1.50138 -1.765357,-1.72665 -0.733383,-0.22527 -1.860536,-1.18814 -2.504783,-2.13971 -0.644247,-0.95158 -1.446074,-1.56582 -1.781839,-1.36499 -0.335764,0.20083 -0.781784,-0.0669 -0.99115,-0.59492 -0.209371,-0.52803 -1.856732,-1.50561 -3.660803,-2.1724 -1.804075,-0.66679 -3.280134,-1.48223 -3.280134,-1.81208 0,-0.32987 -0.645419,-0.59975 -1.434262,-0.59975 -0.788846,0 -1.434264,-0.31232 -1.434264,-0.69403 0,-0.38173 -0.645419,-0.69404 -1.434262,-0.69404 -0.788845,0 -1.434264,-0.31232 -1.434264,-0.69403 0,-0.38172 -0.806774,-0.69403 -1.79283,-0.69403 -0.986055,0 -1.792827,-0.27843 -1.792827,-0.61871 0,-0.34029 -2.097611,-1.02222 -4.661357,-1.51539 -2.563745,-0.49318 -4.661356,-1.11107 -4.661356,-1.3731 0,-0.26203 -2.016932,-0.84615 -4.482072,-1.29806 -2.465139,-0.45191 -5.530877,-1.14139 -6.8127501,-1.53219 l -2.3306773,-0.71053 v -9.31564 -9.31561 l 2.6892434,-0.11141 c 1.479084,-0.0613 4.786853,-0.18304 7.350599,-0.2706 2.563745,-0.0875 7.565738,-0.37873 11.11554,-0.64704 8.182084,-0.61844 9.245015,-0.58461 9.551132,0.30417 0.154777,0.44938 3.475972,0.72488 8.738504,0.72488 h 8.488837 l 0.455323,-2.00629 c 0.338232,-1.49037 0.860017,-1.99471 2.029089,-1.9613 1.435188,0.041 5.980156,-0.48121 10.537919,-1.21083 0.986055,-0.15784 2.922309,-0.46481 4.302787,-0.68215 1.380479,-0.21735 3.15538,-0.54063 3.944226,-0.71842 0.788845,-0.1778 2.402391,-0.50427 3.585657,-0.72554 6.732547,-1.25886 9.799885,-2.05311 11.670262,-3.021856 0.878174,-0.454847 1.596673,-0.65182 1.596673,-0.437738 0,0.214099 0.968131,-0.09525 2.151393,-0.687431 1.183272,-0.592177 2.151388,-0.887046 2.151388,-0.655261 0,0.231803 1.12949,-0.254119 2.509957,-1.079823 1.38048,-0.825703 2.50997,-1.283727 2.50997,-1.017843 0,0.265901 0.72609,0.02684 1.61355,-0.53114 1.34621,-0.846491 8.67964,-1.095649 44.26354,-1.503867 29.86524,-0.34262 42.79682,-0.719236 43.13985,-1.256391 0.29842,-0.467309 2.47799,1.172307 5.57711,4.195511 l 5.08724,4.962619 v 10.80895 c 0,9.97298 -0.097,10.78025 -1.25498,10.43773 -4.81778,-1.42515 -10.59087,-2.60228 -14.88048,-3.03413 -6.37719,-0.642 -22.24626,-0.65315 -28.3267,-0.0199 -2.56375,0.267 -16.52091,0.50124 -31.01594,0.52053 l -26.35459,0.0351 v 3.12316 3.12315 l 15.23905,0.0307 15.23905,0.0306 -2.86852,1.45919 c -5.69947,2.89924 -11.95629,8.28587 -14.55841,12.53364 -0.64304,1.04973 -1.4223,1.90859 -1.73168,1.90859 -0.30938,0 -0.56252,0.44316 -0.56252,0.98481 0,1.15809 -2.26844,5.50463 -3.0478,5.83985 -0.29582,0.12724 -0.53785,0.62431 -0.53785,1.1046 0,1.1616 -20.747682,1.83599 -50.493813,1.64126 -17.607369,-0.11526 -19.957929,-0.2247 -11.1795,-0.52052 z m 27.968132,-24.34102 c 0,-1.43816 -2.260953,-5.90074 -3.799169,-7.49867 -2.116871,-2.19901 -8.569,-5.26921 -13.382949,-6.36817 -5.019831,-1.14595 -14.400801,-1.14595 -19.420635,0 -4.813948,1.09896 -11.266077,4.16916 -13.382949,6.36817 -1.341218,1.39328 -3.799168,6.00716 -3.799168,7.13152 0,0.40937 12.158464,0.7207 36.39443,0.93192 11.577474,0.1009 17.39044,-0.0879 17.39044,-0.56477 z m 117.609581,-14.5524 v -2.77613 H 146.3004 100.76254 v 2.77613 2.77613 h 45.53786 45.53786 z m -0.14,-10.237 -0.21857,-3.296654 -45.71714,-0.178641 -45.71713,-0.178649 v 3.475304 3.4753 h 45.93571 45.93571 z"
|
||||||
|
id="path8767"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
inkscape:export-xdpi="96"
|
||||||
|
inkscape:export-ydpi="96" />
|
||||||
|
<rect
|
||||||
|
style="fill:none;fill-rule:evenodd;stroke-width:0.26252428"
|
||||||
|
id="rect8795"
|
||||||
|
width="211.66666"
|
||||||
|
height="192.01192"
|
||||||
|
x="0"
|
||||||
|
y="25.613092"
|
||||||
|
inkscape:export-xdpi="96"
|
||||||
|
inkscape:export-ydpi="96" />
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 16 KiB |
375
ihm.py
Normal file
@ -0,0 +1,375 @@
|
|||||||
|
"""
|
||||||
|
********************************************************************************
|
||||||
|
* CNIRevelator *
|
||||||
|
* *
|
||||||
|
* Desc: Application launcher graphical interface *
|
||||||
|
* *
|
||||||
|
* Copyright © 2018-2019 Adrien Bourmault (neox95) *
|
||||||
|
* *
|
||||||
|
* This file is part of CNIRevelator. *
|
||||||
|
* *
|
||||||
|
* CNIRevelator is free software: you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU General Public License as published by *
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or *
|
||||||
|
* any later version. *
|
||||||
|
* *
|
||||||
|
* CNIRevelator is distributed in the hope that it will be useful, *
|
||||||
|
* but WITHOUT ANY WARRANTY*without even the implied warranty of *
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||||
|
* GNU General Public License for more details. *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU General Public License *
|
||||||
|
* along with CNIRevelator. If not, see <https:*www.gnu.org/licenses/>. *
|
||||||
|
********************************************************************************
|
||||||
|
"""
|
||||||
|
|
||||||
|
from tkinter.messagebox import *
|
||||||
|
from tkinter import *
|
||||||
|
from tkinter import filedialog
|
||||||
|
from tkinter import ttk
|
||||||
|
import PIL.Image, PIL.ImageTk
|
||||||
|
import traceback
|
||||||
|
import webbrowser
|
||||||
|
import cv2
|
||||||
|
|
||||||
|
import critical # critical.py
|
||||||
|
import logger # logger.py
|
||||||
|
import globs # globs.py
|
||||||
|
import lang # lang.py
|
||||||
|
import updater # updater.py
|
||||||
|
import critical # critical.py
|
||||||
|
|
||||||
|
controlKeys = ["Escape", "Right", "Left", "Up", "Down", "Home", "End", "BackSpace", "Delete", "Inser", "Shift_L", "Shift_R", "Control_R", "Control_L"]
|
||||||
|
|
||||||
|
class DocumentAsk(Toplevel):
|
||||||
|
|
||||||
|
def __init__(self, parent, choices):
|
||||||
|
self.choice = 0
|
||||||
|
vals = [0, 1]
|
||||||
|
super().__init__(parent)
|
||||||
|
self.title("{} :".format(lang.all[globs.CNIRlang]["Choose the identity document"]))
|
||||||
|
|
||||||
|
ttk.Radiobutton(self, text=choices[0], command=self.register0, value=vals[0]).pack()
|
||||||
|
ttk.Radiobutton(self, text=choices[1], command=self.register1, value=vals[1]).pack()
|
||||||
|
|
||||||
|
self.button = Button(self, text='OK', command=(self.ok)).pack()
|
||||||
|
self.resizable(width=False, height=False)
|
||||||
|
ws = self.winfo_screenwidth()
|
||||||
|
hs = self.winfo_screenheight()
|
||||||
|
w = hs / 3
|
||||||
|
h = ws / 20
|
||||||
|
self.update()
|
||||||
|
if getattr(sys, 'frozen', False):
|
||||||
|
self.iconbitmap(sys._MEIPASS + '\\id-card.ico\\id-card.ico')
|
||||||
|
else:
|
||||||
|
self.iconbitmap('id-card.ico')
|
||||||
|
x = ws / 2 - w / 2
|
||||||
|
y = hs / 2 - h / 2
|
||||||
|
self.geometry('%dx%d+%d+%d' % (w, h, x, y))
|
||||||
|
|
||||||
|
def register0(self):
|
||||||
|
self.choice = 0
|
||||||
|
def register1(self):
|
||||||
|
self.choice = 1
|
||||||
|
def ok(self):
|
||||||
|
self.destroy()
|
||||||
|
|
||||||
|
|
||||||
|
class OpenScanDialog(Toplevel):
|
||||||
|
|
||||||
|
def __init__(self, parent, text):
|
||||||
|
super().__init__(parent)
|
||||||
|
self.parent = parent
|
||||||
|
self.title(lang.all[globs.CNIRlang]["OCR Detection Validation"])
|
||||||
|
self.resizable(width=False, height=False)
|
||||||
|
self.termtext = Text(self, state='normal', width=45, height=2, wrap='none', font='Terminal 17', fg='#121f38')
|
||||||
|
self.termtext.grid(column=0, row=0, sticky='NEW', padx=5, pady=5)
|
||||||
|
self.termtext.insert('end', text + '\n')
|
||||||
|
self.button = Button(self, text=lang.all[globs.CNIRlang]["Validate"], command=(self.valid))
|
||||||
|
self.button.grid(column=0, row=1, sticky='S', padx=5, pady=5)
|
||||||
|
self.update()
|
||||||
|
hs = self.winfo_screenheight()
|
||||||
|
w = int(self.winfo_width())
|
||||||
|
h = int(self.winfo_height())
|
||||||
|
ws = self.winfo_screenwidth()
|
||||||
|
hs = self.winfo_screenheight()
|
||||||
|
x = ws / 2 - w / 2
|
||||||
|
y = hs / 2 - h / 2
|
||||||
|
self.geometry('%dx%d+%d+%d' % (w, h, x, y))
|
||||||
|
if getattr(sys, 'frozen', False):
|
||||||
|
self.iconbitmap(sys._MEIPASS + '\\id-card.ico\\id-card.ico')
|
||||||
|
else:
|
||||||
|
self.iconbitmap('id-card.ico')
|
||||||
|
|
||||||
|
def valid(self):
|
||||||
|
self.parent.validatedtext = self.termtext.get('1.0', 'end')
|
||||||
|
texting = self.parent.validatedtext.replace(' ', '').replace('\r', '').split('\n')
|
||||||
|
for i in range(len(texting)):
|
||||||
|
for char in texting[i]:
|
||||||
|
if char not in 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789<':
|
||||||
|
showerror(lang.all[globs.CNIRlang]["Validation Error"], lang.all[globs.CNIRlang]["The submitted MRZ contains invalid characters"], parent=self)
|
||||||
|
self.parent.validatedtext = ''
|
||||||
|
|
||||||
|
self.destroy()
|
||||||
|
|
||||||
|
class LoginDialog(Toplevel):
|
||||||
|
|
||||||
|
def __init__(self, parent):
|
||||||
|
self.key = ''
|
||||||
|
self.login = ''
|
||||||
|
super().__init__(parent)
|
||||||
|
self.title(lang.all[globs.CNIRlang]["Connection"])
|
||||||
|
self["background"] = "white"
|
||||||
|
Label(self, text='IPN : ', bg="white").pack(fill=Y)
|
||||||
|
self.entry_login = ttk.Entry(self)
|
||||||
|
self.entry_login.insert(0, '')
|
||||||
|
self.entry_login.pack()
|
||||||
|
Label(self, text='{} : '.format(lang.all[globs.CNIRlang]["Password"]), bg="white").pack(fill=Y)
|
||||||
|
self.entry_pass = ttk.Entry(self, show='*')
|
||||||
|
self.entry_pass.insert(0, '')
|
||||||
|
self.entry_pass.pack(fill=Y)
|
||||||
|
ttk.Button(self, text=lang.all[globs.CNIRlang]["Connection"], command=(self.connecti)).pack(fill=Y, pady=10)
|
||||||
|
self.update()
|
||||||
|
self.resizable(width=False, height=False)
|
||||||
|
ws = self.winfo_screenwidth()
|
||||||
|
hs = self.winfo_screenheight()
|
||||||
|
w = self.winfo_reqwidth() + 5
|
||||||
|
h = self.winfo_reqheight()
|
||||||
|
if getattr(sys, 'frozen', False):
|
||||||
|
self.iconbitmap(sys._MEIPASS + '\\id-card.ico\\id-card.ico')
|
||||||
|
else:
|
||||||
|
self.iconbitmap('id-card.ico')
|
||||||
|
x = ws / 2 - w / 2
|
||||||
|
y = hs / 2 - h / 2
|
||||||
|
self.geometry('%dx%d+%d+%d' % (w, h, x, y))
|
||||||
|
self.bind("<Return>", self.connecti)
|
||||||
|
|
||||||
|
def connecti(self, event=None):
|
||||||
|
self.login = self.entry_login.get().strip()
|
||||||
|
self.key = self.entry_pass.get().strip()
|
||||||
|
self.destroy()
|
||||||
|
|
||||||
|
class ChangelogDialog(Toplevel):
|
||||||
|
|
||||||
|
def __init__(self, parent, text):
|
||||||
|
super().__init__(parent)
|
||||||
|
|
||||||
|
self.title(lang.all[globs.CNIRlang]["Show Changelog"])
|
||||||
|
self["background"] = "white"
|
||||||
|
|
||||||
|
self.grid_columnconfigure(0, weight=1)
|
||||||
|
self.grid_rowconfigure(0, weight=1)
|
||||||
|
|
||||||
|
self.text = Text(self, wrap='word', width=55, height=15, borderwidth=0, font="TkDefaultFont", bg="white")
|
||||||
|
self.text.grid(column=0, row=0, sticky='EWNS', padx=5, pady=5)
|
||||||
|
|
||||||
|
ttk.Button(self, text="OK", command=(self.oki)).grid(column=0, row=1, pady=5)
|
||||||
|
|
||||||
|
self.scrollb = ttk.Scrollbar(self, command=(self.text.yview))
|
||||||
|
self.scrollb.grid(column=1, row=0, sticky='EWNS', padx=5, pady=5)
|
||||||
|
self.text['yscrollcommand'] = self.scrollb.set
|
||||||
|
|
||||||
|
self.text.insert('end', text)
|
||||||
|
self.text['state'] = 'disabled'
|
||||||
|
|
||||||
|
self.update()
|
||||||
|
self.resizable(width=False, height=False)
|
||||||
|
ws = self.winfo_screenwidth()
|
||||||
|
hs = self.winfo_screenheight()
|
||||||
|
w = self.winfo_reqwidth() + 5
|
||||||
|
h = self.winfo_reqheight()
|
||||||
|
if getattr(sys, 'frozen', False):
|
||||||
|
self.iconbitmap(sys._MEIPASS + '\\id-card.ico\\id-card.ico')
|
||||||
|
else:
|
||||||
|
self.iconbitmap('id-card.ico')
|
||||||
|
x = ws / 2 - w / 2
|
||||||
|
y = hs / 2 - h / 2
|
||||||
|
self.geometry('%dx%d+%d+%d' % (w, h, x, y))
|
||||||
|
self.bind("<Return>", self.oki)
|
||||||
|
|
||||||
|
def oki(self, event=None):
|
||||||
|
self.destroy()
|
||||||
|
|
||||||
|
class langDialog(Toplevel):
|
||||||
|
|
||||||
|
def __init__(self, parent):
|
||||||
|
super().__init__(parent)
|
||||||
|
|
||||||
|
self.title(lang.all[globs.CNIRlang]["Language"])
|
||||||
|
|
||||||
|
Label(self, text=lang.all[globs.CNIRlang]["Please choose your language : "]).pack(fill=Y)
|
||||||
|
|
||||||
|
vals = [i for i in lang.all]
|
||||||
|
for i in range(len(lang.all)):
|
||||||
|
ttk.Radiobutton(self, text=vals[i], command=self.createRegister(i), value=vals[i]).pack(fill=Y)
|
||||||
|
|
||||||
|
ttk.Button(self, text="OK", command=(self.oki)).pack(fill=Y, pady=5)
|
||||||
|
|
||||||
|
self.update()
|
||||||
|
self.resizable(width=False, height=False)
|
||||||
|
ws = self.winfo_screenwidth()
|
||||||
|
hs = self.winfo_screenheight()
|
||||||
|
w = self.winfo_reqwidth() + 5
|
||||||
|
h = self.winfo_reqheight()
|
||||||
|
if getattr(sys, 'frozen', False):
|
||||||
|
self.iconbitmap(sys._MEIPASS + '\\id-card.ico\\id-card.ico')
|
||||||
|
else:
|
||||||
|
self.iconbitmap('id-card.ico')
|
||||||
|
x = ws / 2 - w / 2
|
||||||
|
y = hs / 2 - h / 2
|
||||||
|
self.geometry('%dx%d+%d+%d' % (w, h, x, y))
|
||||||
|
self.bind("<Return>", self.oki)
|
||||||
|
|
||||||
|
def oki(self, event=None):
|
||||||
|
self.destroy()
|
||||||
|
|
||||||
|
def createRegister(self, i):
|
||||||
|
def register():
|
||||||
|
lang.updateLang([j for j in lang.all][i])
|
||||||
|
return register
|
||||||
|
|
||||||
|
class updateSetDialog(Toplevel):
|
||||||
|
|
||||||
|
def __init__(self, parent):
|
||||||
|
super().__init__(parent)
|
||||||
|
|
||||||
|
self.title(lang.all[globs.CNIRlang]["Update options"])
|
||||||
|
|
||||||
|
Label(self, text=lang.all[globs.CNIRlang]["Please choose your update channel : "]).pack(fill=Y)
|
||||||
|
|
||||||
|
self.vals = ["Stable", "Beta"]
|
||||||
|
vals = self.vals
|
||||||
|
for i in range(len(vals)):
|
||||||
|
ttk.Radiobutton(self, text=vals[i], command=self.createRegister(i), value=vals[i]).pack(fill=Y)
|
||||||
|
|
||||||
|
ttk.Button(self, text="OK", command=(self.oki)).pack(fill=Y, pady=5)
|
||||||
|
|
||||||
|
self.update()
|
||||||
|
self.resizable(width=False, height=False)
|
||||||
|
ws = self.winfo_screenwidth()
|
||||||
|
hs = self.winfo_screenheight()
|
||||||
|
w = self.winfo_reqwidth() + 5
|
||||||
|
h = self.winfo_reqheight()
|
||||||
|
if getattr(sys, 'frozen', False):
|
||||||
|
self.iconbitmap(sys._MEIPASS + '\\id-card.ico\\id-card.ico')
|
||||||
|
else:
|
||||||
|
self.iconbitmap('id-card.ico')
|
||||||
|
x = ws / 2 - w / 2
|
||||||
|
y = hs / 2 - h / 2
|
||||||
|
self.geometry('%dx%d+%d+%d' % (w, h, x, y))
|
||||||
|
self.bind("<Return>", self.oki)
|
||||||
|
|
||||||
|
def oki(self, event=None):
|
||||||
|
self.destroy()
|
||||||
|
|
||||||
|
def createRegister(self, i):
|
||||||
|
def register():
|
||||||
|
updater.updateChannel(self.vals[i])
|
||||||
|
return register
|
||||||
|
|
||||||
|
class LauncherWindow(Tk):
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
# Initialize the tkinter main class
|
||||||
|
Tk.__init__(self)
|
||||||
|
self.resizable(width=False, height=False)
|
||||||
|
|
||||||
|
# icon
|
||||||
|
if getattr(sys, 'frozen', False):
|
||||||
|
self.iconbitmap(sys._MEIPASS + '\\id-card.ico\\id-card.ico')
|
||||||
|
else:
|
||||||
|
self.iconbitmap('id-card.ico')
|
||||||
|
|
||||||
|
# Setting up the geometry
|
||||||
|
ws = self.winfo_screenwidth()
|
||||||
|
hs = self.winfo_screenheight()
|
||||||
|
wheight = 274
|
||||||
|
wwidth = 480
|
||||||
|
# Centering
|
||||||
|
x = ws / 2 - wwidth / 2
|
||||||
|
y = hs / 2 - wheight / 2
|
||||||
|
self.geometry('%dx%d+%d+%d' % (wwidth, wheight, x, y))
|
||||||
|
|
||||||
|
# Creating objects
|
||||||
|
# Load an image using OpenCV
|
||||||
|
# if getattr(sys, 'frozen', False):
|
||||||
|
# cv_img = cv2.imread(sys._MEIPASS + r"\background.png\background.png")
|
||||||
|
# else:
|
||||||
|
cv_img = cv2.imread("background.png")
|
||||||
|
|
||||||
|
cv_img = cv2.imread("background.png")
|
||||||
|
cv_img = cv2.cvtColor(cv_img, cv2.COLOR_BGR2RGB)
|
||||||
|
cv_img = cv2.blur(cv_img, (15, 15))
|
||||||
|
# Get the image dimensions (OpenCV stores image data as NumPy ndarray)
|
||||||
|
height, width, no_channels = cv_img.shape
|
||||||
|
# Get the image dimensions (OpenCV stores image data as NumPy ndarray)
|
||||||
|
height, width, no_channels = cv_img.shape
|
||||||
|
# Use PIL (Pillow) to convert the NumPy ndarray to a PhotoImage
|
||||||
|
self.photo = PIL.ImageTk.PhotoImage(image = PIL.Image.fromarray(cv_img))
|
||||||
|
self.mainCanvas = Canvas(self, width=wwidth, height=wheight, bg=globs.CNIRLColor, highlightthickness=0)
|
||||||
|
self.mainCanvas.create_image(wwidth /2, wheight /2, image=self.photo)
|
||||||
|
|
||||||
|
# Column
|
||||||
|
self.mainCanvas.grid_rowconfigure(0, weight=1, minsize=(wheight / 10 * 9))
|
||||||
|
self.mainCanvas.grid_rowconfigure(1, weight=1, minsize=(wheight / 10 * 1))
|
||||||
|
|
||||||
|
self.mainCanvas.create_text((wwidth / 2), (wheight / 3), text=(globs.CNIRName), font='Helvetica 30', fill='white')
|
||||||
|
self.mainCanvas.create_text((wwidth / 2), (wheight / 2), text="version " + (globs.verstring_full), font='Helvetica 8', fill='white')
|
||||||
|
self.msg = self.mainCanvas.create_text((wwidth / 2), (wheight / 1.20), text=lang.all[globs.CNIRlang]["Booting up..."], font='Helvetica 9', fill='white')
|
||||||
|
|
||||||
|
#self.pBarZone = Frame(self.mainCanvas, width=wwidth, height=wheight/10)
|
||||||
|
self.update()
|
||||||
|
|
||||||
|
self.progressBar = ttk.Progressbar(self.mainCanvas, orient=HORIZONTAL, length=wwidth, mode='determinate')
|
||||||
|
|
||||||
|
self.wm_title(globs.CNIRName)
|
||||||
|
|
||||||
|
self.mainCanvas.grid(row=0)
|
||||||
|
self.update()
|
||||||
|
self.progressBar.grid(row=1, sticky='S')
|
||||||
|
|
||||||
|
logfile = logger.logCur
|
||||||
|
logfile.printdbg('Launcher IHM successful')
|
||||||
|
self.protocol('WM_DELETE_WINDOW', lambda : 0)
|
||||||
|
self.update()
|
||||||
|
|
||||||
|
def printmsg(self, msg):
|
||||||
|
self.mainCanvas.itemconfigure(self.msg, text=(msg))
|
||||||
|
|
||||||
|
def exit(self):
|
||||||
|
self.after(1000, self.destroy)
|
||||||
|
|
||||||
|
class ResizeableCanvas(Canvas):
|
||||||
|
def __init__(self,parent,**kwargs):
|
||||||
|
Canvas.__init__(self,parent,**kwargs)
|
||||||
|
self.bind("<Configure>", self.on_resize)
|
||||||
|
self.height = self.winfo_reqheight()
|
||||||
|
self.width = self.winfo_reqwidth()
|
||||||
|
|
||||||
|
def on_resize(self,event):
|
||||||
|
# determine the ratio of old width/height to new width/height
|
||||||
|
wscale = float(event.width)/self.width
|
||||||
|
hscale = float(event.height)/self.height
|
||||||
|
self.width = event.width
|
||||||
|
self.height = event.height
|
||||||
|
# rescale all the objects tagged with the "all" tag
|
||||||
|
self.scale("all",0,0,wscale,hscale)
|
||||||
|
|
||||||
|
class StatusBar(Frame):
|
||||||
|
|
||||||
|
def __init__(self, master):
|
||||||
|
Frame.__init__(self, master)
|
||||||
|
self.label = Label(self, bd=1, relief=SUNKEN, anchor=W)
|
||||||
|
self.label.pack(fill=X)
|
||||||
|
|
||||||
|
def set(self, text):
|
||||||
|
self.label.config(text="Document : " + text.lower())
|
||||||
|
self.label.update_idletasks()
|
||||||
|
|
||||||
|
def clear(self):
|
||||||
|
self.label.config(text="")
|
||||||
|
self.label.update_idletasks()
|
||||||
|
|
||||||
|
## Global Handler
|
||||||
|
launcherWindowCur = LauncherWindow()
|
||||||
|
|
57
launcher.py
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
"""
|
||||||
|
********************************************************************************
|
||||||
|
* CNIRevelator *
|
||||||
|
* *
|
||||||
|
* Desc: Application launcher & updater main file *
|
||||||
|
* *
|
||||||
|
* Copyright © 2018-2019 Adrien Bourmault (neox95) *
|
||||||
|
* *
|
||||||
|
* This file is part of CNIRevelator. *
|
||||||
|
* *
|
||||||
|
* CNIRevelator is free software: you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU General Public License as published by *
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or *
|
||||||
|
* any later version. *
|
||||||
|
* *
|
||||||
|
* CNIRevelator is distributed in the hope that it will be useful, *
|
||||||
|
* but WITHOUT ANY WARRANTY*without even the implied warranty of *
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||||
|
* GNU General Public License for more details. *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU General Public License *
|
||||||
|
* along with CNIRevelator. If not, see <https:*www.gnu.org/licenses/>. *
|
||||||
|
********************************************************************************
|
||||||
|
"""
|
||||||
|
|
||||||
|
import sys
|
||||||
|
import os
|
||||||
|
import threading
|
||||||
|
|
||||||
|
import critical # critical.py
|
||||||
|
import updater # updater.py
|
||||||
|
import ihm # ihm.py
|
||||||
|
import globs # globs.py
|
||||||
|
import logger # logger.py
|
||||||
|
import lang # lang.py
|
||||||
|
|
||||||
|
## Main function
|
||||||
|
def lmain(mainThread):
|
||||||
|
logfile = logger.logCur
|
||||||
|
launcherWindow = ihm.launcherWindowCur
|
||||||
|
|
||||||
|
# Hello world
|
||||||
|
logfile.printdbg('*** CNIRLauncher LOGFILE. Hello World ! ***')
|
||||||
|
#logfile.printdbg('Files in directory : ' + str(os.listdir(globs.CNIRFolder)))
|
||||||
|
|
||||||
|
# Hello user
|
||||||
|
launcherWindow.progressBar.configure(mode='indeterminate', value=0, maximum=20)
|
||||||
|
launcherWindow.printmsg(lang.all[globs.CNIRlang]["Starting..."])
|
||||||
|
launcherWindow.progressBar.start()
|
||||||
|
|
||||||
|
# Starting the main update thread
|
||||||
|
mainThread.start()
|
||||||
|
|
||||||
|
launcherWindow.mainloop()
|
||||||
|
|
||||||
|
logfile.printdbg('*** CNIRLauncher LOGFILE. Goodbye World ! ***')
|
||||||
|
return
|
81
logger.py
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
"""
|
||||||
|
********************************************************************************
|
||||||
|
* CNIRevelator *
|
||||||
|
* *
|
||||||
|
* Desc: Application launcher logging stuff *
|
||||||
|
* *
|
||||||
|
* Copyright © 2018-2019 Adrien Bourmault (neox95) *
|
||||||
|
* *
|
||||||
|
* This file is part of CNIRevelator. *
|
||||||
|
* *
|
||||||
|
* CNIRevelator is free software: you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU General Public License as published by *
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or *
|
||||||
|
* any later version. *
|
||||||
|
* *
|
||||||
|
* CNIRevelator is distributed in the hope that it will be useful, *
|
||||||
|
* but WITHOUT ANY WARRANTY*without even the implied warranty of *
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||||
|
* GNU General Public License for more details. *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU General Public License *
|
||||||
|
* along with CNIRevelator. If not, see <https:*www.gnu.org/licenses/>. *
|
||||||
|
********************************************************************************
|
||||||
|
"""
|
||||||
|
|
||||||
|
import logging
|
||||||
|
import os
|
||||||
|
|
||||||
|
import critical # critical.py
|
||||||
|
import globs # globs.py
|
||||||
|
|
||||||
|
## The logging class
|
||||||
|
class NewLoggingSystem:
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
|
||||||
|
# Deleting the error log
|
||||||
|
try:
|
||||||
|
os.mkdir(globs.CNIRFolder + '\\logs')
|
||||||
|
os.remove(globs.CNIRErrLog)
|
||||||
|
except Exception as e:
|
||||||
|
pass
|
||||||
|
|
||||||
|
# Create new logging handle
|
||||||
|
logger = logging.getLogger()
|
||||||
|
logger.setLevel(logging.INFO) # To make sure we can have a debug channel
|
||||||
|
|
||||||
|
# Create channels
|
||||||
|
formatter = logging.Formatter("\n[ %(module)s/%(funcName)s ] %(asctime)s :: %(levelname)s :: %(message)s")
|
||||||
|
error_handler = logging.FileHandler((globs.CNIRErrLog), mode='w', encoding='utf-8', delay=True)
|
||||||
|
info_handler = logging.FileHandler((globs.CNIRMainLog), mode='w', encoding='utf-8')
|
||||||
|
|
||||||
|
error_handler.setLevel(logging.ERROR)
|
||||||
|
error_handler.setFormatter(formatter)
|
||||||
|
logger.addHandler(error_handler)
|
||||||
|
|
||||||
|
info_handler.setLevel(logging.DEBUG)
|
||||||
|
info_handler.setFormatter(formatter)
|
||||||
|
logger.addHandler(info_handler)
|
||||||
|
|
||||||
|
self.logger = logger
|
||||||
|
self.printerr = logger.error
|
||||||
|
|
||||||
|
if globs.debug:
|
||||||
|
self.printdbg = self.logger.info
|
||||||
|
else:
|
||||||
|
self.printdbg = self.doNothing
|
||||||
|
|
||||||
|
def doNothing(self, text):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def close(self):
|
||||||
|
logging.shutdown()
|
||||||
|
|
||||||
|
handlers = self.logger.handlers[:]
|
||||||
|
for handler in handlers:
|
||||||
|
handler.close()
|
||||||
|
self.logger.removeHandler(handler)
|
||||||
|
|
||||||
|
## Global Handler
|
||||||
|
logCur = NewLoggingSystem()
|
562
mrz.py
Normal file
@ -0,0 +1,562 @@
|
|||||||
|
"""
|
||||||
|
********************************************************************************
|
||||||
|
* CNIRevelator *
|
||||||
|
* *
|
||||||
|
* Desc: MRZ data dictionnary for CNIRevelator analyzer and *
|
||||||
|
* functions to analyze these data *
|
||||||
|
* *
|
||||||
|
* Copyright © 2018-2019 Adrien Bourmault (neox95) *
|
||||||
|
* *
|
||||||
|
* This file is part of CNIRevelator. *
|
||||||
|
* *
|
||||||
|
* CNIRevelator is free software: you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU General Public License as published by *
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or *
|
||||||
|
* any later version. *
|
||||||
|
* *
|
||||||
|
* CNIRevelator is distributed in the hope that it will be useful, *
|
||||||
|
* but WITHOUT ANY WARRANTY*without even the implied warranty of *
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||||
|
* GNU General Public License for more details. *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU General Public License *
|
||||||
|
* along with CNIRevelator. If not, see <https:*www.gnu.org/licenses/>. *
|
||||||
|
********************************************************************************
|
||||||
|
"""
|
||||||
|
|
||||||
|
import re
|
||||||
|
import datetime
|
||||||
|
|
||||||
|
import logger # logger.py
|
||||||
|
import globs # globs.py
|
||||||
|
import lang # lang.py
|
||||||
|
import critical # critical.py
|
||||||
|
|
||||||
|
## SEX CODES
|
||||||
|
sexcode = {'M':'Homme', 'F':'Femme', 'X':'Non spécifié'}
|
||||||
|
|
||||||
|
## COUNTRY CODES
|
||||||
|
|
||||||
|
landcode2 = lang.all[globs.CNIRlang]["LANDCODE2"]
|
||||||
|
|
||||||
|
landcode3 = lang.all[globs.CNIRlang]["LANDCODE3"]
|
||||||
|
|
||||||
|
## DOCUMENTS TYPES
|
||||||
|
|
||||||
|
P = [
|
||||||
|
["11222333333333333333333333333333333333333333", "444444444566677777789AAAAAABCCCCCCCCCCCCCCDE"],
|
||||||
|
{
|
||||||
|
"1": ["2", "CODE", "P."],
|
||||||
|
"2": ["3", "PAYS", "[A-Z]+"],
|
||||||
|
"3": ["39", "NOM", "([A-Z]|<)+"],
|
||||||
|
"4": ["9", "NO", ".+"],
|
||||||
|
"5": ["1", "CTRL", "[0-9]", "4"],
|
||||||
|
"6": ["3", "NAT", "[A-Z]+"],
|
||||||
|
"7": ["6", "BDATE", "[0-9]+"],
|
||||||
|
"8": ["1", "CTRL", "[0-9]", "7"],
|
||||||
|
"9": ["1", "SEX", "[A-Z]"],
|
||||||
|
"A": ["6", "EDATE", "[0-9]+"],
|
||||||
|
"B": ["1", "CTRL", "[0-9]", "A"],
|
||||||
|
"C": ["14", "FACULT", ".+"],
|
||||||
|
"D": ["1", "CTRLF", "[0-9]", "C"],
|
||||||
|
"E": ["1", "CTRL", "[0-9]", "4578ABCD"]
|
||||||
|
},
|
||||||
|
lang.all[globs.CNIRlang]["Passeport lisible à la machine"]
|
||||||
|
]
|
||||||
|
|
||||||
|
IP = [
|
||||||
|
["112223333333334555555555555555", "66666678999999ABBBCCCCCCCCCCCD"],
|
||||||
|
{
|
||||||
|
"1": ["2", "CODE", "IP"],
|
||||||
|
"2": ["3", "PAYS", "[A-Z]+"],
|
||||||
|
"3": ["9", "NO", ".+"],
|
||||||
|
"4": ["1", "CTRL", "[0-9]", "3"],
|
||||||
|
"5": ["15", "FACULT", ".+"],
|
||||||
|
"6": ["6", "BDATE", "[0-9]+"],
|
||||||
|
"7": ["1", "CTRL", "[0-9]", "6"],
|
||||||
|
"8": ["1", "SEX", "[A-Z]"],
|
||||||
|
"9": ["6", "EDATE", "[0-9]+"],
|
||||||
|
"A": ["1", "CTRL", "[0-9]", "9"],
|
||||||
|
"B": ["3", "NAT", "[A-Z]+"],
|
||||||
|
"C": ["11", "FACULT", ".+"],
|
||||||
|
"D": ["1", "CTRL", "[0-9]", "345679AC"]
|
||||||
|
},
|
||||||
|
lang.all[globs.CNIRlang]["Carte-passeport"]
|
||||||
|
]
|
||||||
|
|
||||||
|
IDEUR = [
|
||||||
|
["112223333333334555555555555555", "66666678999999ABBBCCCCCCCCCCCD"],
|
||||||
|
{
|
||||||
|
"1": ["2", "CODE", "I."],
|
||||||
|
"2": ["3", "PAYS", "[A-Z]+"],
|
||||||
|
"3": ["9", "NO", ".+"],
|
||||||
|
"4": ["1", "CTRL", "[0-9]", "3"],
|
||||||
|
"5": ["15", "FACULT", ".+"],
|
||||||
|
"6": ["6", "BDATE", "[0-9]+"],
|
||||||
|
"7": ["1", "CTRL", "[0-9]", "6"],
|
||||||
|
"8": ["1", "SEX", "[A-Z]"],
|
||||||
|
"9": ["6", "EDATE", "[0-9]+"],
|
||||||
|
"A": ["1", "CTRL", "[0-9]", "9"],
|
||||||
|
"B": ["3", "NAT", "[A-Z]+"],
|
||||||
|
"C": ["11", "FACULT", ".+"],
|
||||||
|
"D": ["1", "CTRL", "[0-9]", "345679AC"]
|
||||||
|
},
|
||||||
|
lang.all[globs.CNIRlang]["Carte d’identité européenne"]
|
||||||
|
]
|
||||||
|
|
||||||
|
TSEUR = [
|
||||||
|
["112223333333334555555555555555", "66666678999999ABBBCCCCCCCCCCCD"],
|
||||||
|
{
|
||||||
|
"1": ["2", "CODE", "IR"],
|
||||||
|
"2": ["3", "PAYS", "[A-Z]+"],
|
||||||
|
"3": ["9", "NO", ".+"],
|
||||||
|
"4": ["1", "CTRL", "[0-9]", "3"],
|
||||||
|
"5": ["15", "FACULT", ".+"],
|
||||||
|
"6": ["6", "BDATE", "[0-9]+"],
|
||||||
|
"7": ["1", "CTRL", "[0-9]", "6"],
|
||||||
|
"8": ["1", "SEX", "[A-Z]"],
|
||||||
|
"9": ["6", "EDATE", "[0-9]+"],
|
||||||
|
"A": ["1", "CTRL", "[0-9]", "9"],
|
||||||
|
"B": ["3", "NAT", "[A-Z]+"],
|
||||||
|
"C": ["11", "FACULT", ".+"],
|
||||||
|
"D": ["1", "CTRL", "[0-9]", "345679AC"]
|
||||||
|
},
|
||||||
|
lang.all[globs.CNIRlang]["Carte d’identité européenne"]
|
||||||
|
]
|
||||||
|
|
||||||
|
AC = [
|
||||||
|
["112223333333334EEE555555555555", "66666678999999ABBBCCCCCCCCCCCD"],
|
||||||
|
{
|
||||||
|
"1": ["2", "CODE", "AC"],
|
||||||
|
"2": ["3", "PAYS", "[A-Z]+"],
|
||||||
|
"3": ["9", "NO", ".+"],
|
||||||
|
"4": ["1", "CTRL", "[0-9]", "3"],
|
||||||
|
"E": ["3", "INDIC", "[A-Z]{1,2}."],
|
||||||
|
"5": ["12", "FACULT", ".+"],
|
||||||
|
"6": ["6", "BDATE", "[0-9]+ "],
|
||||||
|
"7": ["1", "CTRL", "[0-9]", "6"],
|
||||||
|
"8": ["1", "SEX", "[A-Z]"],
|
||||||
|
"9": ["6", "EDATE", "[0-9]+"],
|
||||||
|
"A": ["1", "CTRL", "[0-9]", "9"],
|
||||||
|
"B": ["3", "NAT", "[A-Z]+"],
|
||||||
|
"C": ["11", "FACULT", ".+"],
|
||||||
|
"D": ["1", "CTRL", "[0-9]","345679AC"]
|
||||||
|
},
|
||||||
|
lang.all[globs.CNIRlang]["Certificat de membre d'équipage"]
|
||||||
|
]
|
||||||
|
|
||||||
|
VA = [
|
||||||
|
["11222333333333333333333333333333333333333333", "444444444566677777789AAAAAABCCCCCCCCCCCCCCCCC"],
|
||||||
|
{
|
||||||
|
"1": ["2", "CODE", "V."],
|
||||||
|
"2": ["3", "PAYS", "[A-Z]+"],
|
||||||
|
"3": ["39", "NOM", "[A-Z]+"],
|
||||||
|
"4": ["9", "NO", ".+"],
|
||||||
|
"5": ["1", "CTRL", "[0-9]","4"],
|
||||||
|
"6": ["3", "NAT", "[A-Z]+"],
|
||||||
|
"7": ["6", "BDATE", "[0-9]+"],
|
||||||
|
"8": ["1", "CTRL", "[0-9]", "7"],
|
||||||
|
"9": ["1", "SEX", "[A-Z]"],
|
||||||
|
"A": ["6", "EDATE", "[0-9]+"],
|
||||||
|
"B": ["1", "CTRL", "[0-9]", "A"],
|
||||||
|
"C": ["16", "FACULT", ".+"]
|
||||||
|
},
|
||||||
|
lang.all[globs.CNIRlang]["Visa de type A"]
|
||||||
|
]
|
||||||
|
|
||||||
|
VB = [
|
||||||
|
["112223333333333333333333333333333333", "444444444566677777789AAAAAABCCCCCC"],
|
||||||
|
{
|
||||||
|
"1": ["2", "CODE", "V."],
|
||||||
|
"2": ["3", "PAYS", "[A-Z]+"],
|
||||||
|
"3": ["31", "NOM", "([A-Z]|<)+"],
|
||||||
|
"4": ["9", "NO", ".+"],
|
||||||
|
"5": ["1", "CTRL", "[0-9]","4"],
|
||||||
|
"6": ["3", "NAT", "[A-Z]+"],
|
||||||
|
"7": ["6", "BDATE", "[0-9]+"],
|
||||||
|
"8": ["1", "CTRL", "[0-9]", "7"],
|
||||||
|
"9": ["1", "SEX", "[A-Z]"],
|
||||||
|
"A": ["6", "EDATE", "[0-9]+"],
|
||||||
|
"B": ["1", "CTRL", "[0-9]", "A"],
|
||||||
|
"C": ["8", "FACULT", ".+"]
|
||||||
|
},
|
||||||
|
lang.all[globs.CNIRlang]["Visa de type B"]
|
||||||
|
]
|
||||||
|
|
||||||
|
TSF = [
|
||||||
|
["112223333333333333333333333333333333", "444444444566677777789AAAAAABCCCCCC"],
|
||||||
|
{
|
||||||
|
"1": ["2", "CODE", "TS"],
|
||||||
|
"2": ["3", "PAYS", "FRA"],
|
||||||
|
"3": ["31", "NOM", "([A-Z]|<)+"],
|
||||||
|
"4": ["9", "NO", ".+"],
|
||||||
|
"5": ["1", "CTRL", "[0-9]","4"],
|
||||||
|
"6": ["3", "NAT", "[A-Z]+"],
|
||||||
|
"7": ["6", "BDATE", "[0-9]+"],
|
||||||
|
"8": ["1", "CTRL", "[0-9]", "7"],
|
||||||
|
"9": ["1", "SEX", "[A-Z]"],
|
||||||
|
"A": ["6", "EDATE", "[0-9]+"],
|
||||||
|
"B": ["1", "CTRL", "[0-9]", "A"],
|
||||||
|
"C": ["8", "FACULT", ".+"]
|
||||||
|
},
|
||||||
|
lang.all[globs.CNIRlang]["Carte de séjour FR"]
|
||||||
|
]
|
||||||
|
|
||||||
|
TDV = [
|
||||||
|
["112223333333333333333333333333333333", "444444444566677777789AAAAAABCCCCCCCD"],
|
||||||
|
{
|
||||||
|
"1": ["2", "CODE", "I."],
|
||||||
|
"2": ["3", "PAYS", "[A-Z]+"],
|
||||||
|
"3": ["31", "NOM", "([A-Z]|<)+"],
|
||||||
|
"4": ["9", "NO", ".+"],
|
||||||
|
"5": ["1", "CTRL", "[0-9]", "4"],
|
||||||
|
"6": ["3", "NAT", "[A-Z]+"],
|
||||||
|
"7": ["6", "BDATE", "[0-9]+"],
|
||||||
|
"8": ["1", "CTRL", "[0-9]", "7"],
|
||||||
|
"9": ["1", "SEX", "[A-Z]"],
|
||||||
|
"A": ["6", "EDATE", "[0-9]+"],
|
||||||
|
"B": ["1", "CTRL", "[0-9]", "A"],
|
||||||
|
"C": ["7", "FACULT", ".+"],
|
||||||
|
"D": ["1", "CTRL", "[0-9]", "4578ABC"]
|
||||||
|
},
|
||||||
|
lang.all[globs.CNIRlang]["Titre d'identité/de voyage"]
|
||||||
|
]
|
||||||
|
|
||||||
|
IDFR = [
|
||||||
|
["112223333333333333333333333333444444", "555566677777899999999999999AAAAAABCD"],
|
||||||
|
{
|
||||||
|
"1": ["2", "CODE", "ID"],
|
||||||
|
"2": ["3", "PAYS", "FRA"],
|
||||||
|
"3": ["25", "NOM", "([A-Z]|<)+"],
|
||||||
|
"4": ["6", "NOINT", ".+"],
|
||||||
|
"5": ["4", "DDATE", "[0-9]+"],
|
||||||
|
"6": ["3", "NOINT2", "[0-9]+"],
|
||||||
|
"7": ["5", "NOINT3", "[0-9]+"],
|
||||||
|
"8": ["1", "CTRL", "[0-9]", "567"],
|
||||||
|
"9": ["14", "PRENOM", "[A-Z]"],
|
||||||
|
"A": ["6", "BDATE", "[0-9]+"],
|
||||||
|
"B": ["1", "CTRL", "[0-9]", "A"],
|
||||||
|
"C": ["1", "SEX", "[A-Z]"],
|
||||||
|
"D": ["1", "CTRL", "[0-9]", "123456789ABCE"]
|
||||||
|
},
|
||||||
|
lang.all[globs.CNIRlang]["Pièce d'identité FR"]
|
||||||
|
]
|
||||||
|
|
||||||
|
DL = [
|
||||||
|
["112223333333334555555666666667", ""],
|
||||||
|
{
|
||||||
|
"1": ["2", "CODE", "D1"],
|
||||||
|
"2": ["3", "PAYS", "[A-Z]+"],
|
||||||
|
"3": ["9", "NO", "[0-9]{2}[A-Z]{2}[0-9]{5}"],
|
||||||
|
"4": ["1", "CTRL", "[0-9]", "123"],
|
||||||
|
"5": ["6", "EDATE", "[0-9]+"],
|
||||||
|
"6": ["8", "NOM", "([A-Z]|<)+"],
|
||||||
|
"7": ["1", "CTRL", "[0-9]", "123456"]
|
||||||
|
},
|
||||||
|
lang.all[globs.CNIRlang]["Permis de conduire"]
|
||||||
|
]
|
||||||
|
|
||||||
|
TYPES = [IDFR, TDV, VB, VA, AC, IDEUR, IP, P, DL, TSF, TSEUR]
|
||||||
|
|
||||||
|
# longest document MRZ line
|
||||||
|
longest = max([len(x[0][0]) for x in TYPES])
|
||||||
|
|
||||||
|
## THE ROOT OF THIS PROJECT !
|
||||||
|
|
||||||
|
def getDocString(doc):
|
||||||
|
return doc[0][0] + doc[0][1]
|
||||||
|
|
||||||
|
def getFieldLimits(doc, fieldtype):
|
||||||
|
"""
|
||||||
|
This function returns the limit of a given field string id for a given document structure
|
||||||
|
"""
|
||||||
|
L1 = limits(doc[0][0], fieldtype)
|
||||||
|
L2 = limits(doc[0][1], fieldtype)
|
||||||
|
|
||||||
|
if -1 in L1:
|
||||||
|
return 1, L2
|
||||||
|
else:
|
||||||
|
return 0, L1
|
||||||
|
return
|
||||||
|
|
||||||
|
def limits(line, fieldtype):
|
||||||
|
"""
|
||||||
|
Returns the limit of a given field structure
|
||||||
|
"""
|
||||||
|
a = line.find(fieldtype)
|
||||||
|
b = line.rfind(fieldtype)
|
||||||
|
return (a,b+1)
|
||||||
|
|
||||||
|
def completeDocField(doc, code, position):
|
||||||
|
"""
|
||||||
|
Completes with '<' the document the field that is located at given position
|
||||||
|
"""
|
||||||
|
field = getDocString(doc)[position]
|
||||||
|
limit = limits(getDocString(doc), field)
|
||||||
|
res = limit[1] - position
|
||||||
|
#print("field : {}, limit : {}, number of char to complete : {}".format(field, limit, res))
|
||||||
|
return res
|
||||||
|
|
||||||
|
|
||||||
|
def docMatch(doc, strs):
|
||||||
|
"""
|
||||||
|
This function calculates a regex match score for a given document and a string couple
|
||||||
|
"""
|
||||||
|
# Global handler
|
||||||
|
logfile = logger.logCur
|
||||||
|
|
||||||
|
level = 0
|
||||||
|
nchar = 0
|
||||||
|
bonus = 0
|
||||||
|
|
||||||
|
for i in range(0,2):
|
||||||
|
cursor = 0
|
||||||
|
#print("Line : {}".format(i))
|
||||||
|
|
||||||
|
while True:
|
||||||
|
if cursor > len(doc[0][i]) - 1:
|
||||||
|
break
|
||||||
|
# Getting the type of field on the cursor position
|
||||||
|
fieldtype = doc[0][i][cursor]
|
||||||
|
lim = limits(doc[0][i], fieldtype)
|
||||||
|
# ready for next field
|
||||||
|
cursor = lim[1]
|
||||||
|
# get the current field and isolates it
|
||||||
|
field = doc[0][i][ lim[0]:lim[1] ]
|
||||||
|
fstr = strs[i][ lim[0]:lim[1] ]
|
||||||
|
# Prepare regex compilation
|
||||||
|
regex = re.compile(doc[1][fieldtype][2])
|
||||||
|
# Test the match
|
||||||
|
matching = regex.match(fstr)
|
||||||
|
# Retrieve the mathing level
|
||||||
|
if matching:
|
||||||
|
level += matching.end()
|
||||||
|
if fieldtype == "1":
|
||||||
|
bonus += 100
|
||||||
|
nchar += int(doc[1][fieldtype][0])
|
||||||
|
|
||||||
|
# Print for debug
|
||||||
|
|
||||||
|
# print("Field : {}, type = {}, on str : {}".format(field, fieldtype, fstr))
|
||||||
|
# logfile.printdbg(" REGEX : {}, match : {}".format(regex, matching))
|
||||||
|
# exit the loop
|
||||||
|
|
||||||
|
#logfile.printdbg("{} level : {}/{} (+{})".format(doc[2], level, nchar, bonus))
|
||||||
|
return (level, nchar, bonus)
|
||||||
|
|
||||||
|
def allDocMatch(strs, final=False):
|
||||||
|
"""
|
||||||
|
This functions test all documents types on the lines provided and returns a score for each
|
||||||
|
"""
|
||||||
|
# Global handler
|
||||||
|
logfile = logger.logCur
|
||||||
|
|
||||||
|
#print(strs)
|
||||||
|
|
||||||
|
SCORES = []
|
||||||
|
for doc in TYPES:
|
||||||
|
# Get the score of the document on the strings
|
||||||
|
level, nchar, bonus = docMatch(doc, strs)
|
||||||
|
# Number of characters compatibles + bonus with the doc indication
|
||||||
|
SCORES += [ level + bonus ]
|
||||||
|
# if the len of strings is the same than document, add a bonus
|
||||||
|
# but only if we are in a final situation
|
||||||
|
if final:
|
||||||
|
if len(strs[0] + strs[1]) == nchar:
|
||||||
|
SCORES[-1] += 100
|
||||||
|
candidate = SCORES.index(max(SCORES))
|
||||||
|
candidates = []
|
||||||
|
canditxt = []
|
||||||
|
# Search the candidates
|
||||||
|
for i in range(len(SCORES)):
|
||||||
|
if SCORES[i] == SCORES[candidate]:
|
||||||
|
candidates += [TYPES[i]]
|
||||||
|
canditxt += [TYPES[i][2]]
|
||||||
|
# Return the candidates
|
||||||
|
#logfile.printdbg("Scores : {}".format(SCORES))
|
||||||
|
#logfile.printdbg("Candidates : {}".format(canditxt))
|
||||||
|
return candidates
|
||||||
|
|
||||||
|
def computeControlSum(code):
|
||||||
|
"""
|
||||||
|
This function computes a control sum for the given characters
|
||||||
|
"""
|
||||||
|
resultat = 0
|
||||||
|
i = -1
|
||||||
|
facteur = [7, 3, 1]
|
||||||
|
for car in code:
|
||||||
|
if car == '<' or car == '\n':
|
||||||
|
valeur = 0
|
||||||
|
i += 1
|
||||||
|
else:
|
||||||
|
if car in '0123456789':
|
||||||
|
valeur = int(car)
|
||||||
|
i += 1
|
||||||
|
else:
|
||||||
|
if car in 'ABCDEFGHIJKLMNOPQRSTUVWXYZ':
|
||||||
|
valeur = ord(car) - 55
|
||||||
|
i += 1
|
||||||
|
else:
|
||||||
|
break
|
||||||
|
resultat += valeur * facteur[(i % 3)]
|
||||||
|
|
||||||
|
return resultat % 10
|
||||||
|
|
||||||
|
def computeAllControlSum(doc, code):
|
||||||
|
"""
|
||||||
|
This function computes all the ctrl sums on a MRZ string and returns all the results
|
||||||
|
it returns the misc infos about the document too
|
||||||
|
"""
|
||||||
|
ctrlSumList = []
|
||||||
|
facult = False
|
||||||
|
|
||||||
|
# iteration on each char of the given MRZ
|
||||||
|
for charPos in range(len(code)):
|
||||||
|
field = getDocString(doc)[charPos]
|
||||||
|
|
||||||
|
if doc[1][field][1] == "CTRL":
|
||||||
|
#print("{} is CTRL field {}".format(code[charPos], field))
|
||||||
|
|
||||||
|
codeChain = ""
|
||||||
|
# iteration on the fields to control
|
||||||
|
for pos in range(len(code)):
|
||||||
|
target = getDocString(doc)[pos]
|
||||||
|
if target in doc[1][field][3]:
|
||||||
|
#print("__field : {} {} {} {}".format(target, pos, field, doc[1][field][3]))
|
||||||
|
codeChain += code[pos]
|
||||||
|
|
||||||
|
#print("chain to control : _{}_".format(codeChain))
|
||||||
|
|
||||||
|
ctrlSum = computeControlSum(codeChain)
|
||||||
|
#print("SUM : {} vs {}".format(code[charPos], ctrlSum))
|
||||||
|
|
||||||
|
ctrlSumList += [ (field, charPos, ctrlSum, facult) ]
|
||||||
|
|
||||||
|
if doc[1][field][1] == "CTRLF":
|
||||||
|
#print("{} is CTRL field {}".format(code[charPos], field))
|
||||||
|
|
||||||
|
codeChain = ""
|
||||||
|
# iteration on the fields to control
|
||||||
|
for pos in range(len(code)):
|
||||||
|
target = getDocString(doc)[pos]
|
||||||
|
if target in doc[1][field][3]:
|
||||||
|
#print("__field : {} {} {} {}".format(target, pos, field, doc[1][field][3]))
|
||||||
|
codeChain += code[pos]
|
||||||
|
|
||||||
|
#print("chain to control : _{}_".format(codeChain))
|
||||||
|
|
||||||
|
ctrlSum = computeControlSum(codeChain)
|
||||||
|
#print("SUM : {} vs {}".format(code[charPos], ctrlSum))
|
||||||
|
|
||||||
|
if code[charPos] == "<":
|
||||||
|
facult = True
|
||||||
|
|
||||||
|
ctrlSumList += [ (field, charPos, ctrlSum, facult) ]
|
||||||
|
|
||||||
|
return {
|
||||||
|
"ctrlSumList" : ctrlSumList
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def getDocInfos(doc, code):
|
||||||
|
# get all the types of infos that are in the document doc
|
||||||
|
infoTypes = [ (doc[1][field][1], limits(doc[0][0] + doc[0][1], field)) for field in doc[1] ]
|
||||||
|
|
||||||
|
res = {}
|
||||||
|
|
||||||
|
for field in infoTypes:
|
||||||
|
|
||||||
|
value = code[ field[1][0] : field[1][1] ].replace("<", " ").strip()
|
||||||
|
|
||||||
|
# State code
|
||||||
|
if field[0] == 'PAYS' or field[0] == 'NAT':
|
||||||
|
try:
|
||||||
|
if len(value) == 3 and value[-1] != "<":
|
||||||
|
res[field[0]] = landcode3[value]
|
||||||
|
elif len(value) == 3 and value[-1] == "<":
|
||||||
|
res[field[0]] = landcode2[value[:-1]]
|
||||||
|
else:
|
||||||
|
res[field[0]] = landcode2[value]
|
||||||
|
except KeyError:
|
||||||
|
res[field[0]] = False
|
||||||
|
|
||||||
|
# Dates
|
||||||
|
elif field[0][1:] == 'DATE':
|
||||||
|
# size adaptation
|
||||||
|
if len(value) == 6:
|
||||||
|
value = "{}/{}/{}".format(value[4:6], value[2:4], value[0:2])
|
||||||
|
elif len(value) == 4:
|
||||||
|
value = "{}/{}/{}".format("01", value[2:4], value[0:2])
|
||||||
|
|
||||||
|
# date validation
|
||||||
|
try:
|
||||||
|
datetime.datetime.strptime(value,"%d/%m/%y")
|
||||||
|
except ValueError:
|
||||||
|
#print(value)
|
||||||
|
if value != "":
|
||||||
|
res[field[0]] = False
|
||||||
|
else:
|
||||||
|
res[field[0]] = value
|
||||||
|
|
||||||
|
# Numbers
|
||||||
|
elif field[0][:-1] == 'NOINT':
|
||||||
|
try:
|
||||||
|
res["NO"] += value
|
||||||
|
except KeyError:
|
||||||
|
res["NO"] = value
|
||||||
|
elif field[0] == 'NOINT':
|
||||||
|
try:
|
||||||
|
res["NO"] += value
|
||||||
|
except KeyError:
|
||||||
|
res["NO"] = value
|
||||||
|
|
||||||
|
elif field[0] == 'FACULT':
|
||||||
|
try:
|
||||||
|
res["INDIC"] += value
|
||||||
|
except KeyError:
|
||||||
|
res["INDIC"] = value
|
||||||
|
|
||||||
|
# Sex
|
||||||
|
elif field[0] == 'SEX':
|
||||||
|
if not value in "MF":
|
||||||
|
res[field[0]] = False
|
||||||
|
else:
|
||||||
|
res[field[0]] = value
|
||||||
|
|
||||||
|
# All other cases
|
||||||
|
else:
|
||||||
|
if value != "":
|
||||||
|
res[field[0]] = value
|
||||||
|
|
||||||
|
return res
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
326
pytesseract.py
Normal file
@ -0,0 +1,326 @@
|
|||||||
|
"""
|
||||||
|
********************************************************************************
|
||||||
|
* CNIRevelator *
|
||||||
|
* *
|
||||||
|
* Desc: Pytesseract modification to comply with Pyinstaller *
|
||||||
|
* *
|
||||||
|
* Copyright © 2017-2018 Matthias A. Lee (madmaze) *
|
||||||
|
* Copyright © 2018-2019 Adrien Bourmault (neox95) *
|
||||||
|
* *
|
||||||
|
* This file is part of CNIRevelator. *
|
||||||
|
* *
|
||||||
|
* CNIRevelator is free software: you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU General Public License as published by *
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or *
|
||||||
|
* any later version. *
|
||||||
|
* *
|
||||||
|
* CNIRevelator is distributed in the hope that it will be useful, *
|
||||||
|
* but WITHOUT ANY WARRANTY*without even the implied warranty of *
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||||
|
* GNU General Public License for more details. *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU General Public License *
|
||||||
|
* along with CNIRevelator. If not, see <https:*www.gnu.org/licenses/>. *
|
||||||
|
********************************************************************************
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
try:
|
||||||
|
import Image
|
||||||
|
except ImportError:
|
||||||
|
from PIL import Image
|
||||||
|
|
||||||
|
import os, sys, subprocess, tempfile, shlex, string
|
||||||
|
from glob import iglob
|
||||||
|
from pkgutil import find_loader
|
||||||
|
from distutils.version import LooseVersion
|
||||||
|
from os.path import realpath, normpath, normcase
|
||||||
|
numpy_installed = find_loader('numpy') is not None
|
||||||
|
if numpy_installed:
|
||||||
|
from numpy import ndarray
|
||||||
|
tesseract_cmd = 'tesseract'
|
||||||
|
RGB_MODE = 'RGB'
|
||||||
|
OSD_KEYS = {'Page number':(
|
||||||
|
'page_num', int),
|
||||||
|
'Orientation in degrees':(
|
||||||
|
'orientation', int),
|
||||||
|
'Rotate':(
|
||||||
|
'rotate', int),
|
||||||
|
'Orientation confidence':(
|
||||||
|
'orientation_conf', float),
|
||||||
|
'Script':(
|
||||||
|
'script', str),
|
||||||
|
'Script confidence':(
|
||||||
|
'script_conf', float)}
|
||||||
|
|
||||||
|
class Output:
|
||||||
|
STRING = 'string'
|
||||||
|
BYTES = 'bytes'
|
||||||
|
DICT = 'dict'
|
||||||
|
|
||||||
|
|
||||||
|
class TesseractError(RuntimeError):
|
||||||
|
|
||||||
|
def __init__(self, status, message):
|
||||||
|
self.status = status
|
||||||
|
self.message = message
|
||||||
|
self.args = (status, message)
|
||||||
|
|
||||||
|
|
||||||
|
class TesseractNotFoundError(EnvironmentError):
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
super(TesseractNotFoundError, self).__init__(tesseract_cmd + " is not installed or it's not in your path")
|
||||||
|
|
||||||
|
|
||||||
|
class TSVNotSupported(EnvironmentError):
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
super(TSVNotSupported, self).__init__('TSV output not supported. Tesseract >= 3.05 required')
|
||||||
|
|
||||||
|
|
||||||
|
def run_once(func):
|
||||||
|
|
||||||
|
def wrapper(*args, **kwargs):
|
||||||
|
if wrapper._result is wrapper:
|
||||||
|
wrapper._result = func(*args, **kwargs)
|
||||||
|
return wrapper._result
|
||||||
|
|
||||||
|
wrapper._result = wrapper
|
||||||
|
return wrapper
|
||||||
|
|
||||||
|
|
||||||
|
def get_errors(error_string):
|
||||||
|
return ' '.join(line for line in error_string.decode('utf-8').splitlines()).strip()
|
||||||
|
|
||||||
|
|
||||||
|
def cleanup(temp_name):
|
||||||
|
""" Tries to remove files by filename wildcard path. """
|
||||||
|
for filename in iglob(temp_name + '*' if temp_name else temp_name):
|
||||||
|
try:
|
||||||
|
os.remove(filename)
|
||||||
|
except OSError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def prepare(image):
|
||||||
|
if isinstance(image, Image.Image):
|
||||||
|
return image
|
||||||
|
if numpy_installed:
|
||||||
|
if isinstance(image, ndarray):
|
||||||
|
pass
|
||||||
|
return Image.fromarray(image)
|
||||||
|
raise TypeError('Unsupported image object')
|
||||||
|
|
||||||
|
|
||||||
|
def save_image(image):
|
||||||
|
temp_name = tempfile.mktemp(prefix='tess_')
|
||||||
|
if isinstance(image, str):
|
||||||
|
return (temp_name, realpath(normpath(normcase(image))))
|
||||||
|
else:
|
||||||
|
image = prepare(image)
|
||||||
|
img_extension = image.format
|
||||||
|
if image.format not in frozenset({'BMP', 'JPEG', 'GIF', 'TIFF', 'PNG'}):
|
||||||
|
img_extension = 'PNG'
|
||||||
|
if not image.mode.startswith(RGB_MODE):
|
||||||
|
image = image.convert(RGB_MODE)
|
||||||
|
if 'A' in image.getbands():
|
||||||
|
background = Image.new(RGB_MODE, image.size, (255, 255, 255))
|
||||||
|
background.paste(image, (0, 0), image)
|
||||||
|
image = background
|
||||||
|
input_file_name = temp_name + os.extsep + img_extension
|
||||||
|
(image.save)(input_file_name, format=img_extension, **image.info)
|
||||||
|
return (
|
||||||
|
temp_name, input_file_name)
|
||||||
|
|
||||||
|
|
||||||
|
def subprocess_args(include_stdout=True):
|
||||||
|
if hasattr(subprocess, 'STARTUPINFO'):
|
||||||
|
si = subprocess.STARTUPINFO()
|
||||||
|
si.dwFlags |= subprocess.STARTF_USESHOWWINDOW
|
||||||
|
env = os.environ
|
||||||
|
else:
|
||||||
|
si = None
|
||||||
|
env = None
|
||||||
|
if include_stdout:
|
||||||
|
ret = {'stdout': subprocess.PIPE}
|
||||||
|
else:
|
||||||
|
ret = {}
|
||||||
|
ret.update({'stdin':subprocess.PIPE, 'stderr':subprocess.PIPE,
|
||||||
|
'startupinfo':si,
|
||||||
|
'env':env})
|
||||||
|
return ret
|
||||||
|
|
||||||
|
|
||||||
|
def run_tesseract(input_filename, output_filename_base, extension, lang, config='', nice=0):
|
||||||
|
cmd_args = []
|
||||||
|
if not sys.platform.startswith('win32'):
|
||||||
|
if nice != 0:
|
||||||
|
cmd_args += ('nice', '-n', str(nice))
|
||||||
|
cmd_args += (tesseract_cmd, input_filename, output_filename_base)
|
||||||
|
if lang is not None:
|
||||||
|
cmd_args += ('-l', lang)
|
||||||
|
cmd_args += shlex.split(config)
|
||||||
|
if extension not in ('box', 'osd', 'tsv'):
|
||||||
|
cmd_args.append(extension)
|
||||||
|
try:
|
||||||
|
proc = (subprocess.Popen)(cmd_args, **subprocess_args())
|
||||||
|
except OSError:
|
||||||
|
raise TesseractNotFoundError()
|
||||||
|
|
||||||
|
status_code, error_string = proc.wait(), proc.stderr.read()
|
||||||
|
proc.stderr.close()
|
||||||
|
if status_code:
|
||||||
|
raise TesseractError(status_code, get_errors(error_string))
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
def run_and_get_output(image, extension, lang=None, config='', nice=0, return_bytes=False):
|
||||||
|
temp_name, input_filename = ('', '')
|
||||||
|
try:
|
||||||
|
temp_name, input_filename = save_image(image)
|
||||||
|
kwargs = {'input_filename':input_filename,
|
||||||
|
'output_filename_base':temp_name + '_out',
|
||||||
|
'extension':extension,
|
||||||
|
'lang':lang,
|
||||||
|
'config':config,
|
||||||
|
'nice':nice}
|
||||||
|
run_tesseract(**kwargs)
|
||||||
|
filename = kwargs['output_filename_base'] + os.extsep + extension
|
||||||
|
with open(filename, 'rb') as (output_file):
|
||||||
|
if return_bytes:
|
||||||
|
return output_file.read()
|
||||||
|
return output_file.read().decode('utf-8').strip()
|
||||||
|
finally:
|
||||||
|
cleanup(temp_name)
|
||||||
|
|
||||||
|
|
||||||
|
def file_to_dict(tsv, cell_delimiter, str_col_idx):
|
||||||
|
result = {}
|
||||||
|
rows = [row.split(cell_delimiter) for row in tsv.split('\n')]
|
||||||
|
if not rows:
|
||||||
|
return result
|
||||||
|
else:
|
||||||
|
header = rows.pop(0)
|
||||||
|
if len(rows[(-1)]) < len(header):
|
||||||
|
rows[(-1)].append('')
|
||||||
|
if str_col_idx < 0:
|
||||||
|
str_col_idx += len(header)
|
||||||
|
for i, head in enumerate(header):
|
||||||
|
result[head] = [int(row[i]) if i != str_col_idx else row[i] for row in rows]
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
def is_valid(val, _type):
|
||||||
|
if _type is int:
|
||||||
|
return val.isdigit()
|
||||||
|
else:
|
||||||
|
if _type is float:
|
||||||
|
pass
|
||||||
|
try:
|
||||||
|
float(val)
|
||||||
|
return True
|
||||||
|
except ValueError:
|
||||||
|
return False
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
def osd_to_dict(osd):
|
||||||
|
return {OSD_KEYS[kv[0]][0]:OSD_KEYS[kv[0]][1](kv[1]) for kv in (line.split(': ') for line in osd.split('\n')) if len(kv) == 2 if is_valid(kv[1], OSD_KEYS[kv[0]][1])}
|
||||||
|
|
||||||
|
|
||||||
|
@run_once
|
||||||
|
def get_tesseract_version():
|
||||||
|
"""
|
||||||
|
Returns LooseVersion object of the Tesseract version
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
return LooseVersion((subprocess.check_output)([tesseract_cmd, '--version'], **subprocess_args(False)).decode('utf-8').split()[1].lstrip(string.printable[10:]))
|
||||||
|
except OSError:
|
||||||
|
raise TesseractNotFoundError()
|
||||||
|
|
||||||
|
|
||||||
|
def image_to_string(image, lang=None, config='', nice=0, boxes=False, output_type=Output.STRING):
|
||||||
|
"""
|
||||||
|
Returns the result of a Tesseract OCR run on the provided image to string
|
||||||
|
"""
|
||||||
|
if boxes:
|
||||||
|
print("\nWarning: Argument 'boxes' is deprecated and will be removed in future versions. Use function image_to_boxes instead.\n")
|
||||||
|
return image_to_boxes(image, lang, config, nice, output_type)
|
||||||
|
else:
|
||||||
|
args = [
|
||||||
|
image, 'txt', lang, config, nice]
|
||||||
|
if output_type == Output.DICT:
|
||||||
|
return {'text': run_and_get_output(*args)}
|
||||||
|
if output_type == Output.BYTES:
|
||||||
|
args.append(True)
|
||||||
|
return run_and_get_output(*args)
|
||||||
|
|
||||||
|
|
||||||
|
def image_to_boxes(image, lang=None, config='', nice=0, output_type=Output.STRING):
|
||||||
|
"""
|
||||||
|
Returns string containing recognized characters and their box boundaries
|
||||||
|
"""
|
||||||
|
config += ' batch.nochop makebox'
|
||||||
|
args = [image, 'box', lang, config, nice]
|
||||||
|
if output_type == Output.DICT:
|
||||||
|
box_header = 'char left bottom right top page\n'
|
||||||
|
return file_to_dict(box_header + run_and_get_output(*args), ' ', 0)
|
||||||
|
else:
|
||||||
|
if output_type == Output.BYTES:
|
||||||
|
args.append(True)
|
||||||
|
return run_and_get_output(*args)
|
||||||
|
|
||||||
|
|
||||||
|
def image_to_data(image, lang=None, config='', nice=0, output_type=Output.STRING):
|
||||||
|
"""
|
||||||
|
Returns string containing box boundaries, confidences,
|
||||||
|
and other information. Requires Tesseract 3.05+
|
||||||
|
"""
|
||||||
|
if get_tesseract_version() < '3.05':
|
||||||
|
raise TSVNotSupported()
|
||||||
|
config = '{} {}'.format('-c tessedit_create_tsv=1', config.strip()).strip()
|
||||||
|
args = [image, 'tsv', lang, config, nice]
|
||||||
|
if output_type == Output.DICT:
|
||||||
|
return file_to_dict(run_and_get_output(*args), '\t', -1)
|
||||||
|
else:
|
||||||
|
if output_type == Output.BYTES:
|
||||||
|
args.append(True)
|
||||||
|
return run_and_get_output(*args)
|
||||||
|
|
||||||
|
|
||||||
|
def image_to_osd(image, lang='osd', config='', nice=0, output_type=Output.STRING):
|
||||||
|
"""
|
||||||
|
Returns string containing the orientation and script detection (OSD)
|
||||||
|
"""
|
||||||
|
config = '{}-psm 0 {}'.format('' if get_tesseract_version() < '3.05' else '-', config.strip()).strip()
|
||||||
|
args = [
|
||||||
|
image, 'osd', lang, config, nice]
|
||||||
|
if output_type == Output.DICT:
|
||||||
|
return osd_to_dict(run_and_get_output(*args))
|
||||||
|
else:
|
||||||
|
if output_type == Output.BYTES:
|
||||||
|
args.append(True)
|
||||||
|
return run_and_get_output(*args)
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
if len(sys.argv) == 2:
|
||||||
|
filename, lang = sys.argv[1], None
|
||||||
|
else:
|
||||||
|
if len(sys.argv) == 4:
|
||||||
|
if sys.argv[1] == '-l':
|
||||||
|
filename, lang = sys.argv[3], sys.argv[2]
|
||||||
|
sys.stderr.write('Usage: python pytesseract.py [-l lang] input_file\n')
|
||||||
|
exit(2)
|
||||||
|
try:
|
||||||
|
print(image_to_string((Image.open(filename)), lang=lang))
|
||||||
|
except IOError:
|
||||||
|
sys.stderr.write('ERROR: Could not open file "%s"\n' % filename)
|
||||||
|
exit(1)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
BIN
rotateLeft.png
Normal file
After Width: | Height: | Size: 750 B |
BIN
rotateLeft1.png
Normal file
After Width: | Height: | Size: 450 B |
BIN
rotateRight.png
Normal file
After Width: | Height: | Size: 738 B |
BIN
rotateRight1.png
Normal file
After Width: | Height: | Size: 428 B |
420
updater.py
Normal file
@ -0,0 +1,420 @@
|
|||||||
|
"""
|
||||||
|
********************************************************************************
|
||||||
|
* CNIRevelator *
|
||||||
|
* *
|
||||||
|
* Desc: Application launcher updating system *
|
||||||
|
* *
|
||||||
|
* Copyright © 2018-2019 Adrien Bourmault (neox95) *
|
||||||
|
* *
|
||||||
|
* This file is part of CNIRevelator. *
|
||||||
|
* *
|
||||||
|
* CNIRevelator is free software: you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU General Public License as published by *
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or *
|
||||||
|
* any later version. *
|
||||||
|
* *
|
||||||
|
* CNIRevelator is distributed in the hope that it will be useful, *
|
||||||
|
* but WITHOUT ANY WARRANTY*without even the implied warranty of *
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||||
|
* GNU General Public License for more details. *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU General Public License *
|
||||||
|
* along with CNIRevelator. If not, see <https:*www.gnu.org/licenses/>. *
|
||||||
|
********************************************************************************
|
||||||
|
"""
|
||||||
|
|
||||||
|
from win32com.client import Dispatch
|
||||||
|
from tkinter.messagebox import *
|
||||||
|
from tkinter import *
|
||||||
|
import pythoncom
|
||||||
|
import sys
|
||||||
|
import time
|
||||||
|
import os
|
||||||
|
import shutil
|
||||||
|
import zipfile
|
||||||
|
import hashlib
|
||||||
|
import subprocess
|
||||||
|
import psutil
|
||||||
|
|
||||||
|
import critical # critical.py
|
||||||
|
import ihm # ihm.py
|
||||||
|
import logger # logger.py
|
||||||
|
import globs # globs.py
|
||||||
|
import downloader # downloader.py
|
||||||
|
import lang # lang.py
|
||||||
|
|
||||||
|
UPDATE_IS_MADE = False
|
||||||
|
UPATH = ' '
|
||||||
|
|
||||||
|
launcherWindow = ihm.launcherWindowCur
|
||||||
|
|
||||||
|
def createShortcut(path, target='', wDir='', icon=''):
|
||||||
|
"""
|
||||||
|
Creates a shortcut for a program or an internet link
|
||||||
|
"""
|
||||||
|
ext = path[-3:]
|
||||||
|
if ext == 'url':
|
||||||
|
shortcut = file(path, 'w')
|
||||||
|
shortcut.write('[InternetShortcut]\n')
|
||||||
|
shortcut.write('URL=%s' % target)
|
||||||
|
shortcut.close()
|
||||||
|
else:
|
||||||
|
shell = Dispatch('WScript.Shell')
|
||||||
|
shortcut = shell.CreateShortCut(shell.SpecialFolders("Desktop") + r"\{}".format(path))
|
||||||
|
shortcut.Targetpath = target
|
||||||
|
shortcut.WorkingDirectory = wDir
|
||||||
|
if icon == '':
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
shortcut.IconLocation = icon
|
||||||
|
shortcut.save()
|
||||||
|
|
||||||
|
def spawnProcess(args, cd):
|
||||||
|
"""
|
||||||
|
Creates a new independant process. Used to launch a new version after update
|
||||||
|
"""
|
||||||
|
subprocess.Popen(args, close_fds=True, cwd=cd, creationflags=subprocess.DETACHED_PROCESS)
|
||||||
|
|
||||||
|
def exitProcess(arg):
|
||||||
|
"""
|
||||||
|
Forcefully quits a process. Used to help deletion of an old version or to quit properly
|
||||||
|
"""
|
||||||
|
# Quit totally without remain in memory
|
||||||
|
for process in psutil.process_iter():
|
||||||
|
if process.pid == os.getpid():
|
||||||
|
process.terminate()
|
||||||
|
sys.exit(arg)
|
||||||
|
|
||||||
|
def updateChannel(choice):
|
||||||
|
if choice == "Beta":
|
||||||
|
with open(globs.CNIRUrlConfig, 'w') as (configFile):
|
||||||
|
configFile.write("{}\n0\n0".format(globs.CNIRBetaURL))
|
||||||
|
else:
|
||||||
|
with open(globs.CNIRUrlConfig, 'w') as (configFile):
|
||||||
|
configFile.write("{}\n0\n0".format(globs.CNIRDefaultURL))
|
||||||
|
|
||||||
|
def getLatestVersion(credentials):
|
||||||
|
"""
|
||||||
|
Returns the latest version of the software
|
||||||
|
"""
|
||||||
|
|
||||||
|
finalver, finalurl, finalchecksum = [None]*3
|
||||||
|
|
||||||
|
# Global Handlers
|
||||||
|
logfile = logger.logCur
|
||||||
|
|
||||||
|
|
||||||
|
# First retrieving the urls !
|
||||||
|
while True:
|
||||||
|
try:
|
||||||
|
# Open the config file
|
||||||
|
logfile.printdbg('Reading urlconf.ig')
|
||||||
|
with open(globs.CNIRUrlConfig, 'r') as (configFile):
|
||||||
|
try:
|
||||||
|
# Reading it
|
||||||
|
reading = configFile.read()
|
||||||
|
# Parsing it
|
||||||
|
urlparsed = reading.split("\n")
|
||||||
|
break
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
raise IOError(str(e))
|
||||||
|
|
||||||
|
except FileNotFoundError:
|
||||||
|
logfile.printdbg('Recreate urlconf.ig')
|
||||||
|
# Recreating the url file
|
||||||
|
try:
|
||||||
|
os.mkdir(globs.CNIRFolder + '\\config')
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
with open(globs.CNIRUrlConfig, 'w') as (configFile):
|
||||||
|
configFile.write("{}\n0\n0".format(globs.CNIRDefaultURL))
|
||||||
|
|
||||||
|
# Getting the list of versions of the software
|
||||||
|
logfile.printdbg('Retrieving the software versions')
|
||||||
|
try:
|
||||||
|
os.mkdir(globs.CNIRFolder + '\\downloads')
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
getTheVersions = downloader.newdownload(credentials, urlparsed[0], globs.CNIRVerStock, "the version repository").download()
|
||||||
|
|
||||||
|
logfile.printdbg('Parsing the software versions')
|
||||||
|
with open(globs.CNIRVerStock) as versionsFile:
|
||||||
|
versionsTab = versionsFile.read().split("\n")[1].split("||")
|
||||||
|
logfile.printdbg('Versions retrieved : {}'.format(versionsTab))
|
||||||
|
# Choose the newer
|
||||||
|
finalver = globs.version.copy()
|
||||||
|
for entry in versionsTab:
|
||||||
|
if not entry:
|
||||||
|
continue
|
||||||
|
verstr, url, checksum = entry.split("|")
|
||||||
|
# Calculating sum considering we can have 99 sub versions
|
||||||
|
ver = verstr.split(".")
|
||||||
|
ver = [int(i) for i in ver]
|
||||||
|
finalsum = finalver[2] + finalver[1]*100 + finalver[0]*100*100
|
||||||
|
sum = ver[2] + ver[1]*100 + ver[0]*100*100
|
||||||
|
# Make a statement
|
||||||
|
if sum >= finalsum:
|
||||||
|
finalver = ver.copy()
|
||||||
|
finalurl = url
|
||||||
|
finalchecksum = checksum
|
||||||
|
else:
|
||||||
|
finalurl = url
|
||||||
|
finalchecksum = None
|
||||||
|
|
||||||
|
return (finalver, finalurl, finalchecksum)
|
||||||
|
|
||||||
|
|
||||||
|
def tessInstall(PATH, credentials):
|
||||||
|
# Global Handlers
|
||||||
|
logfile = logger.logCur
|
||||||
|
|
||||||
|
|
||||||
|
# Verifying that Tesseract is installed
|
||||||
|
if not os.path.exists(PATH + '\\Tesseract-OCR5\\'):
|
||||||
|
finalver, finalurl, finalchecksum = getLatestVersion(credentials)
|
||||||
|
|
||||||
|
if finalurl == None:
|
||||||
|
logfile.printerr('Unable to get the Tesseract url')
|
||||||
|
return False
|
||||||
|
|
||||||
|
tesseracturl = finalurl.replace("CNIRevelator.zip", "tesseract_5.zip")
|
||||||
|
|
||||||
|
# WE ASSUME THAT THE MAIN FILE IS CNIRevelator.zip AND THAT THE TESSERACT PACKAGE IS tesseract_5.zip
|
||||||
|
logfile.printdbg('Preparing download of Tesseract OCR 4...')
|
||||||
|
getTesseract = downloader.newdownload(credentials, tesseracturl, PATH + '\\downloads\\TsrtPackage.zip', "Tesseract 5 OCR Module").download()
|
||||||
|
|
||||||
|
try:
|
||||||
|
# CHECKSUM
|
||||||
|
BUF_SIZE = 65536 # lets read stuff in 64kb chunks!
|
||||||
|
|
||||||
|
sha1 = hashlib.sha1()
|
||||||
|
|
||||||
|
with open(globs.CNIRFolder + '\\downloads\\TsrtPackage.zip', 'rb') as f:
|
||||||
|
while True:
|
||||||
|
data = f.read(BUF_SIZE)
|
||||||
|
if not data:
|
||||||
|
break
|
||||||
|
sha1.update(data)
|
||||||
|
|
||||||
|
check = sha1.hexdigest()
|
||||||
|
logfile.printdbg("SHA1: {0}".format(check))
|
||||||
|
|
||||||
|
if not check == globs.CNIRTesserHash:
|
||||||
|
logfile.printerr("Checksum error")
|
||||||
|
return False
|
||||||
|
|
||||||
|
# Unzip Tesseract
|
||||||
|
logfile.printdbg("Unzipping the package")
|
||||||
|
launcherWindow.printmsg(lang.all[globs.CNIRlang]["Installing the updates"])
|
||||||
|
zip_ref = zipfile.ZipFile(PATH + '\\downloads\\TsrtPackage.zip', 'r')
|
||||||
|
zip_ref.extractall(PATH)
|
||||||
|
zip_ref.close()
|
||||||
|
# Cleanup
|
||||||
|
try:
|
||||||
|
os.remove(UPATH + '\\downloads\\TsrtPackage.zip')
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
return True
|
||||||
|
|
||||||
|
except:
|
||||||
|
return False
|
||||||
|
else:
|
||||||
|
return True
|
||||||
|
|
||||||
|
## Main Batch Function
|
||||||
|
def batch(credentials):
|
||||||
|
# Global Handlers
|
||||||
|
logfile = logger.logCur
|
||||||
|
|
||||||
|
|
||||||
|
# Get the latest version of CNIRevelator
|
||||||
|
finalver, finalurl, finalchecksum = getLatestVersion(credentials)
|
||||||
|
|
||||||
|
if finalver == globs.version:
|
||||||
|
logfile.printdbg('The software is already the newer version')
|
||||||
|
return True
|
||||||
|
|
||||||
|
logfile.printdbg('Preparing download for the new version')
|
||||||
|
|
||||||
|
getTheUpdate = downloader.newdownload(credentials, finalurl, globs.CNIRFolder + '\\downloads\\CNIPackage.zip', "CNIRevelator {}.{}.{}".format(finalver[0], finalver[1], finalver[2])).download()
|
||||||
|
|
||||||
|
launcherWindow.printmsg(lang.all[globs.CNIRlang]["Verifying download..."])
|
||||||
|
|
||||||
|
# CHECKSUM
|
||||||
|
BUF_SIZE = 65536 # lets read stuff in 64kb chunks!
|
||||||
|
|
||||||
|
sha1 = hashlib.sha1()
|
||||||
|
|
||||||
|
with open(globs.CNIRFolder + '\\downloads\\CNIPackage.zip', 'rb') as f:
|
||||||
|
while True:
|
||||||
|
data = f.read(BUF_SIZE)
|
||||||
|
if not data:
|
||||||
|
break
|
||||||
|
sha1.update(data)
|
||||||
|
|
||||||
|
check = sha1.hexdigest()
|
||||||
|
logfile.printdbg("SHA1: {0}".format(check))
|
||||||
|
|
||||||
|
if not check == finalchecksum:
|
||||||
|
logfile.printerr("Checksum error")
|
||||||
|
return False
|
||||||
|
|
||||||
|
# And now prepare install
|
||||||
|
global UPATH
|
||||||
|
UPATH = globs.CNIRFolder + '\\..\\CNIRevelator' + "{}.{}.{}".format(finalver[0], finalver[1], finalver[2])
|
||||||
|
logfile.printdbg("Make place")
|
||||||
|
launcherWindow.printmsg(lang.all[globs.CNIRlang]["Preparing installation..."])
|
||||||
|
# Cleanup
|
||||||
|
try:
|
||||||
|
shutil.rmtree(UPATH + 'temp')
|
||||||
|
except Exception as e:
|
||||||
|
logfile.printdbg('Unable to cleanup : ' +str(e))
|
||||||
|
try:
|
||||||
|
shutil.rmtree(UPATH)
|
||||||
|
except Exception as e:
|
||||||
|
logfile.printdbg('Unable to cleanup : ' +str(e))
|
||||||
|
# Unzip
|
||||||
|
logfile.printdbg("Unzipping the package")
|
||||||
|
launcherWindow.printmsg(lang.all[globs.CNIRlang]["Installing the updates"])
|
||||||
|
zip_ref = zipfile.ZipFile(globs.CNIRFolder + '\\downloads\\CNIPackage.zip', 'r')
|
||||||
|
zip_ref.extractall(UPATH + "temp")
|
||||||
|
zip_ref.close()
|
||||||
|
|
||||||
|
# Move to the right place
|
||||||
|
shutil.copytree(UPATH + 'temp\\CNIRevelator', UPATH)
|
||||||
|
shutil.rmtree(UPATH + 'temp')
|
||||||
|
logfile.printdbg('Extracted :' + UPATH + '\\CNIRevelator.exe')
|
||||||
|
|
||||||
|
# Make a shortcut
|
||||||
|
# hide main window
|
||||||
|
pythoncom.CoInitialize()
|
||||||
|
root = Tk()
|
||||||
|
root.withdraw()
|
||||||
|
res = askquestion(lang.all[globs.CNIRlang]["Shortcut creation"], lang.all[globs.CNIRlang]["Would you like to create/update the shortcut for CNIRevelator on your desktop ?"])
|
||||||
|
if res == "yes":
|
||||||
|
createShortcut("CNIRevelator.lnk", UPATH + '\\CNIRevelator.exe', UPATH)
|
||||||
|
root.destroy()
|
||||||
|
|
||||||
|
launcherWindow.printmsg(lang.all[globs.CNIRlang]["Success !"])
|
||||||
|
|
||||||
|
# Cleanup
|
||||||
|
try:
|
||||||
|
os.remove(globs.CNIRFolder + '\\downloads\\CNIPackage.zip')
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
# Time to quit
|
||||||
|
launcherWindow.printmsg(lang.all[globs.CNIRlang]["Launching the new version..."])
|
||||||
|
global UPDATE_IS_MADE
|
||||||
|
UPDATE_IS_MADE = True
|
||||||
|
return True
|
||||||
|
|
||||||
|
## Main Function
|
||||||
|
def umain():
|
||||||
|
|
||||||
|
# Global Handlers
|
||||||
|
logfile = logger.logCur
|
||||||
|
|
||||||
|
|
||||||
|
credentials = downloader.newcredentials()
|
||||||
|
|
||||||
|
if not credentials.valid:
|
||||||
|
logfile.printerr("Credentials Error. No effective update !")
|
||||||
|
launcherWindow.printmsg(lang.all[globs.CNIRlang]["Credentials Error. No effective update !"])
|
||||||
|
time.sleep(2)
|
||||||
|
launcherWindow.exit()
|
||||||
|
return 0
|
||||||
|
|
||||||
|
# Cleaner for the old version if detected
|
||||||
|
if len(sys.argv) > 2 and str(sys.argv[1]) == "DELETE":
|
||||||
|
globs.CNIRNewVersion = True
|
||||||
|
launcherWindow.printmsg(lang.all[globs.CNIRlang]["Deleting old version"])
|
||||||
|
logfile.printdbg("Old install detected : {}".format(sys.argv[1]))
|
||||||
|
while os.path.exists(str(sys.argv[2])):
|
||||||
|
try:
|
||||||
|
shutil.rmtree(str(sys.argv[2]))
|
||||||
|
except Exception as e:
|
||||||
|
logfile.printerr(str(e))
|
||||||
|
logfile.printdbg('Trying stop the process !')
|
||||||
|
launcherWindow.printmsg('Fail :{}'.format(e))
|
||||||
|
try:
|
||||||
|
for process in psutil.process_iter():
|
||||||
|
if process.name() == 'CNIRevelator.exe':
|
||||||
|
logfile.printdbg('Process found. Command line: {}'.format(process.cmdline()))
|
||||||
|
if process.pid == os.getpid():
|
||||||
|
logfile.printdbg("Don't touch us ! {} = {}".format(process.pid, os.getpid()))
|
||||||
|
else:
|
||||||
|
logfile.printdbg('Terminating process !')
|
||||||
|
process.terminate()
|
||||||
|
shutil.rmtree(str(sys.argv[2]))
|
||||||
|
break
|
||||||
|
except Exception as e:
|
||||||
|
logfile.printerr(str(e))
|
||||||
|
launcherWindow.printmsg('Fail :{}'.format(e))
|
||||||
|
launcherWindow.printmsg(lang.all[globs.CNIRlang]['Starting...'])
|
||||||
|
|
||||||
|
# check we want open a file
|
||||||
|
elif len(sys.argv) > 1 and str(sys.argv[1]) != "DELETE":
|
||||||
|
globs.CNIROpenFile = True
|
||||||
|
print(sys.argv)
|
||||||
|
|
||||||
|
try:
|
||||||
|
try:
|
||||||
|
# EXECUTING THE UPDATE BATCH
|
||||||
|
success = batch(credentials)
|
||||||
|
except Exception as e:
|
||||||
|
critical.crashCNIR()
|
||||||
|
launcherWindow.printmsg('ERROR : ' + str(e))
|
||||||
|
time.sleep(3)
|
||||||
|
launcherWindow.exit()
|
||||||
|
return 1
|
||||||
|
|
||||||
|
if success:
|
||||||
|
logfile.printdbg("Software is up-to-date !")
|
||||||
|
launcherWindow.printmsg('Software is up-to-date !')
|
||||||
|
else:
|
||||||
|
logfile.printerr("An error occured. No effective update !")
|
||||||
|
launcherWindow.printmsg(lang.all[globs.CNIRlang]['An error occured. No effective update !'])
|
||||||
|
time.sleep(2)
|
||||||
|
launcherWindow.exit()
|
||||||
|
return 0
|
||||||
|
|
||||||
|
if UPDATE_IS_MADE:
|
||||||
|
launcherWindow.exit()
|
||||||
|
return 0
|
||||||
|
except:
|
||||||
|
critical.crashCNIR()
|
||||||
|
launcherWindow.exit()
|
||||||
|
sys.exit(2)
|
||||||
|
return 2
|
||||||
|
|
||||||
|
try:
|
||||||
|
try:
|
||||||
|
# INSTALLING TESSERACT OCR
|
||||||
|
success = tessInstall(globs.CNIRFolder, credentials)
|
||||||
|
except Exception as e:
|
||||||
|
critical.crashCNIR()
|
||||||
|
launcherWindow.printmsg('ERROR : ' + str(e))
|
||||||
|
time.sleep(3)
|
||||||
|
launcherWindow.exit()
|
||||||
|
return 1
|
||||||
|
|
||||||
|
if success:
|
||||||
|
logfile.printdbg("Software is up-to-date !")
|
||||||
|
launcherWindow.printmsg(lang.all[globs.CNIRlang]['Software is up-to-date !'])
|
||||||
|
else:
|
||||||
|
logfile.printerr("An error occured. No effective update !")
|
||||||
|
launcherWindow.printmsg(lang.all[globs.CNIRlang]['An error occured. No effective update !'])
|
||||||
|
time.sleep(2)
|
||||||
|
launcherWindow.exit()
|
||||||
|
return 0
|
||||||
|
|
||||||
|
except:
|
||||||
|
critical.crashCNIR()
|
||||||
|
launcherWindow.exit()
|
||||||
|
sys.exit(2)
|
||||||
|
return 2
|
||||||
|
|
||||||
|
time.sleep(2)
|
||||||
|
launcherWindow.exit()
|
||||||
|
return 0
|
BIN
zoomIn.png
Normal file
After Width: | Height: | Size: 772 B |
BIN
zoomIn20.png
Normal file
After Width: | Height: | Size: 1.2 KiB |
BIN
zoomIn50.png
Normal file
After Width: | Height: | Size: 1.2 KiB |
BIN
zoomOut.png
Normal file
After Width: | Height: | Size: 735 B |
BIN
zoomOut20.png
Normal file
After Width: | Height: | Size: 1013 B |
BIN
zoomOut50.png
Normal file
After Width: | Height: | Size: 1.1 KiB |