From 1926e2be24ce55e7c91527bf4c825977c66382b3 Mon Sep 17 00:00:00 2001 From: Ruben van de Ven Date: Thu, 31 Oct 2019 13:55:22 +0100 Subject: [PATCH] Mturk Drawing with padding --- config.yml | 20 +- sorteerhoed/HITStore.py | 2 +- .../__pycache__/HITStore.cpython-37.pyc | Bin 0 -> 5114 bytes sorteerhoed/__pycache__/Signal.cpython-37.pyc | Bin 0 -> 787 bytes .../__pycache__/__init__.cpython-37.pyc | Bin 0 -> 181 bytes .../central_management.cpython-37.pyc | Bin 0 -> 8646 bytes .../__pycache__/plotter.cpython-37.pyc | Bin 0 -> 3160 bytes sorteerhoed/__pycache__/sqs.cpython-37.pyc | Bin 0 -> 1813 bytes .../__pycache__/webserver.cpython-37.pyc | Bin 0 -> 11997 bytes sorteerhoed/central_management.py | 6 +- sorteerhoed/plotter.py | 177 ++++++++----- sorteerhoed/webserver.py | 28 ++- www/index.html | 234 +++++++++++++----- 13 files changed, 334 insertions(+), 133 deletions(-) create mode 100644 sorteerhoed/__pycache__/HITStore.cpython-37.pyc create mode 100644 sorteerhoed/__pycache__/Signal.cpython-37.pyc create mode 100644 sorteerhoed/__pycache__/__init__.cpython-37.pyc create mode 100644 sorteerhoed/__pycache__/central_management.cpython-37.pyc create mode 100644 sorteerhoed/__pycache__/plotter.cpython-37.pyc create mode 100644 sorteerhoed/__pycache__/sqs.cpython-37.pyc create mode 100644 sorteerhoed/__pycache__/webserver.cpython-37.pyc diff --git a/config.yml b/config.yml index edbe538..40670b1 100644 --- a/config.yml +++ b/config.yml @@ -3,11 +3,25 @@ amazon: user_secret: "213j234/234sksjdfus83jd" mturk_sandbox: true mturk_region: us-east-1 + sqs_endpoint_url: "https://sqs.eu-west-3.amazonaws.com/" sqs_url: "https://sqs.eu-west-3.amazonaws.com/60123456789/your_queue" sqs_region_name: "eu-west-3" task_xml: "mt_task.xml" hit_db: store.db hour_rate_aim: 15 -hit_lifetime: 54000 ;15*60*60 -hit_assignment_duration: 300 ; 5*60 -hit_autoapprove_delay: 3600 \ No newline at end of file +hit_lifetime: 54000 #15*60*60 +hit_assignment_duration: 300 # 5*60 +hit_autoapprove_delay: 3600 +dummy_plotter: false +server: + port: 8888 +scanner: # size of scanarea in mm + # total visible glass (and size of the scan) + width: 255 + height: 185 + # area which can be removed + draw_width: 255 + draw_height: 70 + # part of scanner that is invissible left & top + left_padding: 0 + top_padding: 45 diff --git a/sorteerhoed/HITStore.py b/sorteerhoed/HITStore.py index 5ed18be..8769c9a 100644 --- a/sorteerhoed/HITStore.py +++ b/sorteerhoed/HITStore.py @@ -61,7 +61,7 @@ class HIT(Base): return os.path.join('www', self.getImageUrl()) def getImageUrl(self): - return f"scans/{self.id}.png" + return f"scans/{self.id}.jpg" def getStatus(self): if self.scanned_at: diff --git a/sorteerhoed/__pycache__/HITStore.cpython-37.pyc b/sorteerhoed/__pycache__/HITStore.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..907510f132e782f2ab911b614edea2baf465ec3f GIT binary patch literal 5114 zcmb_gOLH5?5#ARTizh*fqNt}~$4(3-d1Nxq&1D3Fp4sS38Xx98o{)BSZ1HXDtq zf#2WdU%wbF8^%AWF#9=RHt=Tu0O1BVBZJY`ipOjT&*2H8o$37UC9bY2J($*&^ojqNVr(yD+U=X3Ki*i|nHQ zuCNvTy~HlzTZvZV%j~jg2xD@ES5HiKRa~81<27*Cg>`JO8}A#u&Kr*n-VisAZT14n zO}>Eg!m-8L+}trbt?#fyW4mMKEiSrIAOjUX5dLnEiH?)IH`8bsCwX}*QDR@n+}%+! zO!jl{R-nYaFcuhCmm%Do+Ne<+eJ^=ovcz$jlN`(dI7 zW+KZlE)EWaM2BWK#WD|793%l2LyfaHOuBh3OQjM*_EN#~Ql>C{m!zKkN?(zZtA{ejP-a0 zI-@=dv+=yD%dK17RJkv2N=gODPl~++NP5WM+S@#uJHzM;(MJh@D{!|copZpnA;z0-OHU`sIuGz^+SHIW3t*nhH)T|`~z|H-G87= zXur(GUNDT*cWso z`}ga;G#2Y}xGR$NTWNO~i$rDXcV*faU4^>WfAZ5e*LQ>(4%X++eLWW4UXX;{AoA5v z9-L{zj&{f@)&{V+x1%85<-t2Y#*+WSYmDk>Uz=5LcVQ&@M_)1>y^$p_%IKRD7|z(3 z*eAvbZOGbY_Tk|nT)|4S+!+L_mplD5O!C^kP+KwV^ivs;rDh`9d$LV=8S~}!S)aQY z_cm%WQk-FqS|rhY;~AlB^wB~!!H_t8<7;5gw>AW_w?}T)4U%kq#RL$CTXFtnzu5<-A8B`%z(oN$*B$VKz77BUsU$GI*8 zU`9(pw<`u`I_2d8KzOH=S4jtn;C`U;MlqpJ#*AWfS{&ePs9aA6BJpRXS~0J$G-N(Yy0P?)iQa#KQOUs_(}sA4bI2egFP2h>8~0 z@O>5RMxrQ6I&4YtMplTtM1-tTl0`}vB=N-zV}4NbbUx4uR}t@+v<~Hi`GO;lkS!1rAbSnOgHD&sy4k|BtZ5x3dZ?yV z@V19XkLzN{>5tU5fj3J)PBH&7x48XSBR_X|>9GNvFL9Tbfq!m+QU#TQXu6Lr4yjmavFF1d&0^%`2NISbQp3-1dPfPnuAX3PjY4cJiCT(VZpCZ18V zh!V4IXW)-KjVvsC1LSB0$~Jyum;`k?yqU&lMzU(6W?E;Rfcw(;t&v!t1Eg^X*63|S zu?Ha+?VznB{3_^DS`tP2oo2NF)j(U=JtimaXPwNXtO7jmaHgiiSjtj$~?XdEi$ z$ux>~gYLnz(LJvcP8C}F9SL3sF>K59uvHh^9<_??KIzug;Rn6wOZIvbZ$^GvY*SgV zOItbp(!@moq)j2Bm$g`V35gs4!QDxRvMX{gm0U=F_elGuT*oB2!$sEZSOu!mUe2FT z8M1tU%wvz%)xwyg#;KIl@@x^w63>We^_{VKK;o88$N?axtHqS>(y|0IxeK#VLTX6O z?G!0zAsH(nQf%?_vXMF=!RFBx4@o@I582P08mGSG5aBUO|hz~-PVKaUNc7vg%(cxof_Sly;B&S?tS%Or@6}Q^j2(=j1PE!2<#5|A4ls@d0qA zt~_mn3DEdw3r^-f75ohxmo+gdP~w=ZiAGj@?V?6G6fnnT-+lh3+;=%g@(8Hfz`XK9 zB4ifw*F^ruy}3AHZ0(O2s_!=j4x|cH#Rluep%fhuDP4(sicC(oNb#RuZI@qyd5(A4 z@UGI-(_HOo@G*Fur?UlX-*{v{d}(amGQPO-$Qj#{%Gd$m0hd>eNtJq<#{G@Y3{@N3 z$7YtOI>(K6$53_EpqiroDzYC6OWXSp#4!H0yU}Sr(}7<>Ympnyd2tlNL6IE}kUjIf zp;CpLS0<1uaF{gWac+l+%I$0zcS=)RPgo8A1c*#gE}kK?8cu^-VMym}=sK|A-3R-( zrky_8yDPOjfcG@qNhBam_FO95*>X#Ae_=V1 zY(dhX1phw@!8!r94?rlAQ%Q0rX&%T#g({N4Hzq?FZK6Duv7Bs3KJi_4hImn5bVajj zryS^c$JLeU+(Z7Ub`@W0YwNQ{@nvC(Ryk$t%;$MA2bbiB);BohPV?eQ*OHgIJMV3+ zyRnI@j4EW^UCdr#>#;OtL)bz65c}4)M7&6-8Sp8vy$@nd*F=yt0|}@AIi07>V2Z)q zG#Emwn)CmjAH+luxPF&ax>cF!&s3Ma)Mekobep|3`cjn+d`})dewrzA3;#wleg ztz_1!vMRc|EE?f@^WjcxJl1Uac}Rq)yV?nnz$}aRCp4z3dp8-k(GvdE6KY(`<2nFC z0t bg=|0czIjT$-pcpog`kf_ooV#)9a_AOZ#$feZ&AE@lA|DGb33nv8xc8Hzx{2;x_qenx(7s(w*v zQfi*QOMY@`Zfaghv3@{NepYI72~f<)z|c}ZIJKm-K)*P@s3bMDC?h{LML#z+IU_MI qGdVFQzNEA$8$~WYJ~J<~BtBlRpz;=nO>TZlX-=vg$llLD%m4tw?J>gu literal 0 HcmV?d00001 diff --git a/sorteerhoed/__pycache__/central_management.cpython-37.pyc b/sorteerhoed/__pycache__/central_management.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b9c0ec249a084847a7214383e2f8151c12ccdf97 GIT binary patch literal 8646 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 literal 0 HcmV?d00001 diff --git a/sorteerhoed/__pycache__/plotter.cpython-37.pyc b/sorteerhoed/__pycache__/plotter.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..3c3c0883d266ed1db7cf3d926753386127bd0c3d GIT binary patch literal 3160 zcmZuzUvC^q5$~S=JG*N;dkMrjK&#`ASah;;fKFV5Ae?>SgiclxTO^DWt>(7d>#=8N z);+UvysS?M8;MWA3m~l@k@x^7#7E#0^b-<1VDSJC_i*BgU-itc6T*z9rnn`@)G_;RyGFMP9XV{=5{`qjIjM;^P$QQ<)DP@+jrl2Z*y0c zlkw(D7H^K^;2_SDL7eu>i8^|vuinhY_*4h|ev&0+zfZU;S|H5wxW@y09X?&F9lx7J`@;HRA=+s`Z4k@4CdPXJDZ+^PI$oTzRYRhpAJ3i2=GEi1Hc z+SArzi`2c`9>tYhVz&1=nCYKSe@$Bye4Q23lFzNn3QT5$m+*(#mV3$0_>33dD?MSI z^IviT)uDap171$eHI`hs=Iy$`h7tIIQ%JLiH(UXV93g zVZ`cuZ3Y-qKhhuaPpqfxXDkCHiP5+rygE3x`p2uQm{zCW#T)aR#6870q=LVrzDWCD z--@#=FS|g02INtYepHo*D+{LN0n21Cl)J-KrvGK{fI*dK<+>Td~m1 zBtv?~gEDz8wO=ox8y~zF$Z?60+Rx3uh};R_ieEe!$TVseV<|-+xilF^?PY`VO1q<6 zK*by7&t;kG4vHDAw>6O;B?U4^stQ64dA-U>tf;7<@FYcTg=)iE?G92ItDbF;r5kl0 zDg&1l#3)%SoVi6AtMbce7jJ_w?(mR@R%nOd0t5Ol)XFF#oXoO0{5Qo4zivK#h$%OMJ6D~dvz1}*zeckWB z+&{F=oS8M}Gl#Ho96ljEYi^5RX8o4^-e3w6NBx56+^tY%kkQyN@z#DZ05nk3+>=C< z2UnCg!^fX~i%O?{(p(u8NaFinqIaYEnu1X?`NrQgynz zg_1v%g0$~-e|{D@ln9YE8Sg#l`HD7t?P~3zaE{`#a(M$os_7!bnzeeC@p~l!B9Wp7 z=GRyc3t2vt**2Eh!|at$oe-Y9gU_KF3p(vAe0r_EthD6JWu*;KN(4XS2H*cC$IkgB zQ=gyCz!NITnU+Dk1Ejl0mU@>QsP=$zl6a7ONRnc&1Xj z2@<~^j~PvkwC2Ig99K_}6R5Y1!w?nsGgMq$s;1jmp*e4ffOM<5)n8tpH@l5s|DE;& z{q}sNTosLT1BJRuJD)gIrH{j>i_B}z*F;FOnhb01JlGq;KY0H7!z+TGNhgzbSHD4X zy0VvyWIido$8!bkxS$w- zXgigedWV+!4v`HI?V8zf_ZyAN)2eE^LVi4{FG1_1NO3edTxV+()}}m;Gqp*bcZqzH z$g3z)UxjRdZ&@z^9M`f|?7OIs1R%%m*eg~CEvlc6ftJI+;Y{x=fc1KD-|02!c9X>; z+3)MH-^Xz}WzSaoB z;OnhUuxfgGP4ym)TmeB2ox(<{DayprhEO-k10`eBv7xa*cV4=|ZB+Mb<5%sJ2(y{= Z|Jk8~?^m1q0iDDJtry@1*Q(#Z`Y-WR`Tqa_ literal 0 HcmV?d00001 diff --git a/sorteerhoed/__pycache__/sqs.cpython-37.pyc b/sorteerhoed/__pycache__/sqs.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..3c4cf419f9d43fe10ca3c7d0041a26915c4ae21a GIT binary patch literal 1813 zcmY*aOK&4Z5bmCr$B#IUlLh610<6UPKpfZ$AcUgbtl+R4NW9?Pk)qLLy5o#954*c( ziLEi0%{9{A0V%lwCocR8enDS3#CkdD=Reu&(R;hAN}JJ z@)u4Pj|s{y{N;Bb7-2Lf9*#y#6T>qo>Sk;vmS>eZjcv~^{T$DM(TXdH>$$gURj>Lb zVK#Fv2yWi#U%E%34cWbW&_%!J}xoMxP9Q;sE|S0i~i2NDj1 z(@vPBC(%Gx;%qPgcwHTE^%Qh2v@{dni2PrE&?@=nVX@WH|Nac4*RJZS!CHmQ z);0<5V(r3?=<9O#__sdklXS--YUQj3cu@N@hmvWlL~0feV)U^$!2W~tg1jWD@q$3+ ztIL@K{yOBpaS44ip7zOjx7^=i_i(>jyK1v4YUABL@`dm47S793dwXA0fnx0hNifY) zUCAXEe#CUWR3r}tSKcZdr7!p(%2GcK67IFoz*9ELqEz|0h@rgJg72jtgdvyGKjRY& zat}@O7)vXeM#o1?D+Ip0+iFV2+l~W6Vw!LaOdp;R)ZI{igR}OK< zNPQKgEan|UyaPFi_drY=y@TFXB)51nQWKb|Y&3$l+X8cEUE9Z*${s>f#u2p6yv?xU zwG$x+K;msKelky7tm3K_r6-xTh7!oP<1Aou-rVLWR|2mPU43#M@{t1Wb(JqvugQ4K z6<-9?Hsi@A9X6C1p(#u!&*6suK9kFu{=h-;rrt}i03Q9091h&s8~nw5Cz^6AUAzx- zZIAI|PzKXgbt-tk;LPT68{i;5M6dSJowhyySd`?856}e>mQc$iN|M~q=ed7@)he4H Mkc9>?gQIKw3+;p4$p8QV literal 0 HcmV?d00001 diff --git a/sorteerhoed/__pycache__/webserver.cpython-37.pyc b/sorteerhoed/__pycache__/webserver.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..8961a9ab24f031d923a667f67153dd88c4eda186 GIT binary patch literal 11997 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 literal 0 HcmV?d00001 diff --git a/sorteerhoed/central_management.py b/sorteerhoed/central_management.py index 18ea8d8..8017d9d 100644 --- a/sorteerhoed/central_management.py +++ b/sorteerhoed/central_management.py @@ -300,8 +300,11 @@ class CentralManagement(): Run scanimage on scaner and returns a string with the filename """ self.eventQueue.put(Signal('scan.start')) + cmd = [ - 'sudo', 'scanimage', '-d', 'epkowa' + 'sudo', 'scanimage', '-d', 'epkowa', '--format', 'jpeg', + '--resolution=100', '-l','20','-t','30','-x',(self.config['scanner']['height']), + '-y',str(self.config['scanner']['width']) ] filename = self.currentHit.getImagePath() proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) @@ -313,6 +316,7 @@ class CentralManagement(): f = io.BytesIO(o) img = Image.open(f) + img = img.transpose(Image.ROTATE_90) img.save(filename) self.eventQueue.put(Signal('hit.scanned', {'hit_id':self.currentHit.id})) diff --git a/sorteerhoed/plotter.py b/sorteerhoed/plotter.py index 0e63533..03ea3ce 100644 --- a/sorteerhoed/plotter.py +++ b/sorteerhoed/plotter.py @@ -6,17 +6,6 @@ from threading import Event from sorteerhoed.Signal import Signal import time -class PathSegment: - def __init__(self): - self.d = [] - - def add(self, i): -# self.d.append(i) - - def get(self, prop): - if prop =='d': - return self.d - class Plotter: def __init__(self, config, eventQ: Queue, runningEvent: Event): #TODO: scanningEvent -> CentralManagement.isScanning -> prevent plotter move during scan, failsafe @@ -25,6 +14,13 @@ class Plotter: self.q = Queue() self.isRunning = runningEvent self.logger = logging.getLogger("sorteerhoed").getChild("plotter") + self.pen_down = False + + self.plotWidth = self.config['scanner']['width'] / 10 / 2.54 + self.plotHeight = self.config['scanner']['height'] / 10 / 2.54 + self.xPadding = self.config['scanner']['left_padding'] / 10 / 2.54; + self.yPadding = self.config['scanner']['top_padding'] / 10 / 2.54; + self.logger.info(f"Paddings x: {self.xPadding} inch y: {self.yPadding} inch") def park(self): self.logger.info("Queue to park plotter") @@ -37,69 +33,118 @@ class Plotter: self.q.put([0,0,0]) def start(self): - self.axiDrawCueListener() - - def axiDrawCueListener(self): - if self.config['dummy_plotter']: - while self.isRunning.is_set(): - # TODO: queue that collects a part of the path data - # on a specific limit or on a specific time interval, do the plot - # also, changing ad.pen_raise() or ad.pen_lower() trigger a new segment - # Plot with ad.plan_trajectory() ?? - plotterRan = False - try: - move = self.q.get(True, 1) - plotterRan = True - except queue.Empty as e: - self.logger.log(5, "Empty queue.") - if plotterRan: - plotterRan = False - self.eventQ.put(Signal('plotter.finished')) - else: - time.sleep(.05) - self.logger.debug(f'Dummy plotter move: {move}') - self.logger.info("Stopping dummy plotter") - else: - self.ad = axidraw.AxiDraw() - - self.ad.interactive() -# self.ad.plot_path() - - connected = self.ad.connect() - if not connected: - raise Exception("Cannot connect to Axidraw") - try: + try: + if not self.config['dummy_plotter']: + self.ad = axidraw.AxiDraw() + + self.ad.interactive() + # self.ad.plot_path() + + connected = self.ad.connect() + if not connected: + raise Exception("Cannot connect to Axidraw") + self.ad.options.units = 1 # set to use centimeters instead of inches self.ad.options.accel = 100; self.ad.options.speed_penup = 100 self.ad.options.speed_pendown = 100 - self.ad.options.model = 1 # A3, set to 1 for A4 + self.ad.options.model = 1 # 2 for A3, 1 for A4 self.ad.moveto(0,0) - plotterWidth = 22 - plotterHeight = 18 # 16? +# plotterWidth = 25 +# plotterHeight = 21 - plotterRan = False - while self.isRunning.is_set(): - # TODO: set timeout on .get() with catch block, so we can escape if no moves come in - try: - move = self.q.get(True, 1) - plotterRan = True - except queue.Empty as e: - self.logger.log(5, "Empty queue.") - if plotterRan: - plotterRan = False - self.eventQ.put(Signal('plotter.finished')) - else: - self.ad.moveto(move[0]* plotterWidth, move[1]*plotterHeight) - self.logger.debug(f'handler! {move}') - except Exception as e: - self.logger.exception(e) - finally: - self.logger.warning("Close Axidraw connection") + else: + self.ad = None + self.axiDrawCueListener() + except Exception as e: + self.logger.exception(e) + finally: + self.logger.warning("Close Axidraw connection") + if self.ad: self.ad.moveto(0,0) self.ad.disconnect() + + # send shutdown signal (if not already set) + self.isRunning.clear() + + def draw_segments(self, segments = []): + coordinates = [] + for segment in segments: + coordinate = [ + # mm to cm to inches + (segment[0]) * self.plotWidth, + (1-segment[1]) * self.plotHeight + ] + #prevent drawing when not in drwaing area + # this is a failsafe for a malicious working or glitching script, as this should also be done in the javascript + if self.pen_down: + if coordinate[0] < self.xPadding or coordinate[0] > self.xPadding+self.plotWidth or \ + coordinate[1] < self.yPadding or coordinate[1] > self.yPadding + self.plotHeight: + self.logger.warn(f"Skip drawing for: {coordinates} out of bounds") + continue + + coordinates.append(coordinate) + self.logger.info(f"Plot: {coordinates}") + if self.ad: + self.ad.plan_trajectory(coordinates) +# self.ad.moveto(move[0]* plotterWidth, move[1]*plotterHeight) +# self.logger.debug(f'handler! {move}') + pass + + def setPenDown(self, pen_state): + """ + False: pen raised, True: pen_lower + """ + if pen_state != self.pen_down: + self.pen_down = pen_state + self.logger.info("Changed pen: {}".format('down' if pen_state else 'up')) + if self.ad: + if pen_state: + self.ad.pen_lower() + else: + self.ad.pen_raise() + return True + return False + + def axiDrawCueListener(self): + plotterRan = False + segments = [] + while self.isRunning.is_set(): + # TODO: queue that collects a part of the path data + # on a specific limit or on a specific time interval, do the plot + # also, changing ad.pen_raise() or ad.pen_lower() trigger a new segment + # Plot with ad.plan_trajectory() ?? + try: + # if no info comes in for .5sec, plot that segment + segment = self.q.get(True, .5) - # send shutdown signal (if not already set) - self.isRunning.clear() \ No newline at end of file + # change of pen state? draw previous segments! + if (segment[2] == 1 and not self.pen_down) or (segment[2] == 0 and self.pen_down) or len(segments) > 150: + if len(segments) > 1: + self.draw_segments(segments) + plotterRan = True + segments = [] #reset + + # and change pen positions + self.setPenDown(segment[2] == 1) + + + segments.append(segment) + + except queue.Empty as e: + self.logger.debug("Timeout queue.") + if len(segments): + # segments to plot! + self.draw_segments(segments) + plotterRan = True + segments = [] + elif plotterRan: + plotterRan = False + self.eventQ.put(Signal('plotter.finished')) +# else: +# time.sleep(.05) +# self.logger.debug(f'Plotter move: {move}') + self.logger.info("Stopping plotter") + diff --git a/sorteerhoed/webserver.py b/sorteerhoed/webserver.py index 837d5d4..185274a 100644 --- a/sorteerhoed/webserver.py +++ b/sorteerhoed/webserver.py @@ -233,9 +233,15 @@ def strokes2D(strokes): return d; class DrawPageHandler(tornado.web.RequestHandler): - def initialize(self, store: HITStore, path: str): + def initialize(self, store: HITStore, path: str, width: int, height: int, draw_width: int, draw_height: int, top_padding: int, left_padding: int): self.store = store self.path = path + self.width = width + self.height = height + self.draw_width = draw_width + self.draw_height = draw_height + self.top_padding = top_padding + self.left_padding = left_padding def get(self): try: @@ -258,7 +264,14 @@ class DrawPageHandler(tornado.web.RequestHandler): logger.info(f"Image url: {image}") self.set_header("Access-Control-Allow-Origin", "*") - contents = open(os.path.join(self.path, 'index.html'), 'r').read().replace("{IMAGE_URL}", image) + contents = open(os.path.join(self.path, 'index.html'), 'r').read() + contents = contents.replace("{IMAGE_URL}", image)\ + .replace("{WIDTH}", str(self.width))\ + .replace("{HEIGHT}", str(self.height))\ + .replace("{DRAW_WIDTH}", str(self.draw_width))\ + .replace("{DRAW_HEIGHT}", str(self.draw_height))\ + .replace("{TOP_PADDING}", str(self.left_padding))\ + .replace("{LEFT_PADDING}", str(self.top_padding)) self.write(contents) class StatusPage(): @@ -342,7 +355,16 @@ class Server: }), (r"/status/ws", StatusWebSocketHandler), (r"/draw", DrawPageHandler, - dict(store = self.store, path=self.web_root)), + dict( + store = self.store, + path=self.web_root, + width=self.config['scanner']['width'], + height=self.config['scanner']['height'], + draw_width=self.config['scanner']['draw_width'], + draw_height=self.config['scanner']['draw_height'], + top_padding=self.config['scanner']['top_padding'], + left_padding=self.config['scanner']['left_padding'] + )), (r"/(.*)", StaticFileWithHeaderHandler, {"path": self.web_root}), ], debug=True, autoreload=False) diff --git a/www/index.html b/www/index.html index c9e183b..526e538 100644 --- a/www/index.html +++ b/www/index.html @@ -12,6 +12,7 @@ right:0; width:100%; height:100%; + font-family: sans-serif; } path { @@ -19,7 +20,6 @@ stroke: red; stroke-width: 2px; } - body.submitted path{ stroke:darkgray; } @@ -28,38 +28,121 @@ display:none; } - #wrapper { - height: 600px; - width: 600px; - position: relative; - background:#ccc; + /*#wrapper { + height: calc({DRAW_HEIGHT}/{HEIGHT} * 100%); + width: calc({DRAW_WIDTH}/{WIDTH} * 100%); + position: absolute; + left: calc(({WIDTH} - {DRAW_WIDTH})/2/{WIDTH} * 100%); + top: calc(({HEIGHT} - {DRAW_HEIGHT})/2/{HEIGHT} * 100%); + background:none; cursor: url(cursor.png) 6 6, auto; + }*/ + #wrapper { + position:absolute; + top:0; + right:0; + bottom:0; + left:0; + background:none; + cursor: url(cursor.png) 6 6, auto; + } + .gray{ + position:absolute; + background:rgba(255,255,255,0.7); + } + #gray_top{ + left:0; + right:0; + top:0; + height:calc({TOP_PADDING}/{HEIGHT} * 100%); + } + #gray_bottom{ + left:0; + right:0; + bottom:0; + height:calc(({HEIGHT} - {DRAW_HEIGHT} - {TOP_PADDING})/{HEIGHT} * 100%); + } + #gray_left{ + left:0; + top:calc({TOP_PADDING}/{HEIGHT} * 100%); + height: calc({DRAW_HEIGHT}/{HEIGHT} * 100%); + width: calc({LEFT_PADDING}/{WIDTH} * 100%); + } + #gray_right{ + right:0; + top:calc({TOP_PADDING}/{HEIGHT} * 100%); + height: calc({DRAW_HEIGHT}/{HEIGHT} * 100%); + width: calc(({WIDTH} - {DRAW_WIDTH} - {LEFT_PADDING})/{WIDTH} * 100%); } html, body{ height: 100%; width: 100%; + margin:0; + background:gray; } + #interface{ + background:white; + height: 0; + overflow: hidden; + padding-top: calc({HEIGHT}/{WIDTH} * 100%); + background: white; + position: relative; + margin: 0 auto; + background-size: 100% 100%; + } + #innerface{ + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + } + @media (min-aspect-ratio: {WIDTH}/{HEIGHT}) { + #interface { + height: 100vh; + width: calc({WIDTH}/{HEIGHT} * 100vh); + padding-top:0; + } + } + #info{ + position: absolute; + bottom: 5px; + width: 600px; + left: calc(50% - 250px); + z-index: 999; + } + .buttons{ + text-align: center; + } -
    -
  • Drag the mouse to trace the line drawing
  • -
  • Follow the lines as precise as possible
  • -
  • Press submit when you're done.
  • -
  • You'll receive a submission token, to fill in at Mechanical Turk
  • -
-
-
- - - - -
-
- - -
-
+
+
+
+ + + + +
+
+
    +
  • Drag the mouse to trace the clearest lines drawing above
  • +
  • Follow the lines as precise as possible
  • +
  • Press submit when you're done.
  • +
  • You'll receive a submission token, to fill in at Mechanical Turk
  • +
+
+ + +
+
+
+
+
+
+
+