Releasing 3.1.2

This commit is contained in:
Adrien Bourmault 2019-08-21 10:26:17 +02:00 committed by GitHub
parent 45d8734f7d
commit 81313007b0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
29 changed files with 5359 additions and 0 deletions

124
CNIRevelator.py Normal file
View 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

Binary file not shown.

After

Width:  |  Height:  |  Size: 553 B

BIN
OCR.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 512 B

BIN
background.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 82 KiB

235
background.svg Normal file
View 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
View 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
View 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
View 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

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

BIN
id-card.ico.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 70 KiB

279
id-card.svg Normal file
View 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
View 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()

1473
lang.py Normal file

File diff suppressed because it is too large Load Diff

57
launcher.py Normal file
View 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
View 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()

1076
main.py Normal file

File diff suppressed because it is too large Load Diff

562
mrz.py Normal file
View 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 didentité 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 didentité 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
View 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

Binary file not shown.

After

Width:  |  Height:  |  Size: 750 B

BIN
rotateLeft1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 450 B

BIN
rotateRight.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 738 B

BIN
rotateRight1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 428 B

420
updater.py Normal file
View 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

Binary file not shown.

After

Width:  |  Height:  |  Size: 772 B

BIN
zoomIn20.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

BIN
zoomIn50.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

BIN
zoomOut.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 735 B

BIN
zoomOut20.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1013 B

BIN
zoomOut50.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB