def __init__(self,parameters,title="test"): self.snapOn = False self.lastEvent = None self.lock = False self.parameters = parameters self.parameters.define(id='name',desc='Nom du tutorial',type='string',default='snap') self.parameters.define(id='title',desc='Titre du tutorial',type='string',default='snap tutorial') self.parameters.define(id="description", desc="Description du tutorial (markdown)",type="string", default="") self.parameters.define(id='autoDelay',desc='Delai entre les capture auto (en s)',type='float',default=0.5) self.parameters.define(id='toggleKey',desc='Touche debut/arrêt prise de snapshots', type='string', default='twosuperior') self.parameters.define(id='followActive',desc='Observer la fenêtre active uniquement', type='boolean', default=True) self.parameters.define(id='cropL',desc="Correction Left (crop)", type='integer',default=0) self.parameters.define(id='cropR',desc="Correction Right (crop)", type='integer',default=0) self.parameters.define(id='cropT',desc="Correction Top (crop)", type='integer',default=0) self.parameters.define(id='cropB',desc="Correction Bottom (crop)", type='integer',default=0) self.parameters.define(id='diffPct',desc="Ecart toléré entre les images (en %)", type='float',default=1) self.setProfile('default') self.init(title) self.km = KMEvents() self.km.bindCallback(('mousePressLeft', 'mouseReleaseLeft','mouseSlide', 'mousePressRight','mouseReleaseRight', 'mousePressMiddle','mouseReleaseMiddle', 'mouseWheelUp','mouseWheelDown'), self.takeSnap) self.km.bindCallback(('mouseMove'), self.cancelTimedSnap) #self.km.start() self.parameters.setHook('toggleKey',self.reload)
class Snapshot(): def __init__(self,parameters,title="test"): self.snapOn = False self.lastEvent = None self.lock = False self.parameters = parameters self.parameters.define(id='name',desc='Nom du tutorial',type='string',default='snap') self.parameters.define(id='title',desc='Titre du tutorial',type='string',default='snap tutorial') self.parameters.define(id="description", desc="Description du tutorial (markdown)",type="string", default="") self.parameters.define(id='autoDelay',desc='Delai entre les capture auto (en s)',type='float',default=0.5) self.parameters.define(id='toggleKey',desc='Touche debut/arrêt prise de snapshots', type='string', default='twosuperior') self.parameters.define(id='followActive',desc='Observer la fenêtre active uniquement', type='boolean', default=True) self.parameters.define(id='cropL',desc="Correction Left (crop)", type='integer',default=0) self.parameters.define(id='cropR',desc="Correction Right (crop)", type='integer',default=0) self.parameters.define(id='cropT',desc="Correction Top (crop)", type='integer',default=0) self.parameters.define(id='cropB',desc="Correction Bottom (crop)", type='integer',default=0) self.parameters.define(id='diffPct',desc="Ecart toléré entre les images (en %)", type='float',default=1) self.setProfile('default') self.init(title) self.km = KMEvents() self.km.bindCallback(('mousePressLeft', 'mouseReleaseLeft','mouseSlide', 'mousePressRight','mouseReleaseRight', 'mousePressMiddle','mouseReleaseMiddle', 'mouseWheelUp','mouseWheelDown'), self.takeSnap) self.km.bindCallback(('mouseMove'), self.cancelTimedSnap) #self.km.start() self.parameters.setHook('toggleKey',self.reload) def reload(self): print "reload %s" % self.params.toggleKey self.km.setToggleKey('keyPress%s' % self.params.toggleKey) def setProfile(self,profile): self.params = self.parameters.profile(profile) def init(self,title): self.i = 0 self.seq = 0 self.starttime = None self.timeline = [] self.scenario = [] self.lastCall = time.time() self.lastSnap = None self.title = title self.cancelSnap = False def status(self): return {'n':len(self.timeline),'on':self.snapOn} def captureToggleKey(self): return {'key': self.km.captureToggleKey() } def start(self): self.snapOn = True self.km.start() self.timer = Timer(self.params.autoDelay,self.takeTimedSnap,()) self.timer.start() self.seq += 1 if not self.starttime: self.starttime = time.time() def takeTimedSnap(self): if not self.cancelSnap: x,y = self.km.getMouseXY() self.takeSnap(Event(type="timed",x=x,y=y,activeWindow=self.km.getActiveWindowGeometry()),force=True) else: print 'cancelsnap' self.cancelSnap = False if self.snapOn: Timer(self.params.autoDelay,self.takeTimedSnap,()).start() def cancelTimedSnap(self,event=None): self.cancelSnap = True def stop(self): self.snapOn = False self.cancelSnap = True self.km.end() def toggle(self,event=None): if self.snapOn: self.stop() else: self.start() def takeSnap(self,event=None,force=False): if not self.km.capture: return self.cancelTimedSnap() now = time.time() self.waiting = 0 if not self.lock: self.lock = True self.img = ImageGrab.grab() if self.lastSnap and self.diffImage(self.img,self.lastSnap)<0.1: self.img = self.lastSnap self.lock = False else: self.waiting += 1 while self.lock: pass if event.type != 'timed' or self.waiting == 0: self.timeline.append(dict(timestamp=now,event=event,image=self.img,active=event.activeWindow)) self.waiting -= 1 def saveTimeline(self): import os self.savepath = os.path.join('snap',"%s" % self.params.title) if not os.path.exists(self.savepath): os.makedirs(self.savepath) last = None imnum = 0 sorttl = sorted(self.timeline, key=lambda k: k['timestamp']) for i,elt in enumerate(sorttl): current = elt['image'] active=elt['active'] if self.params.followActive: currentcrop = current.crop((active['x'],active['y'],active['x']+active['w'],active['y']+active['h'])) elt['imagecrop'] = currentcrop event = elt['event'] if last: diff = self.diffImage(current,lastimage) if self.params.followActive: diffcrop = self.diffImage(currentcrop,lastimagecrop) else: diff = 100 diffcrop = 100 if (diff>self.params.diffPct) and (not self.params.followActive or (self.params.followActive and diffcrop>self.params.diffPct )): #or (last['active'] != active):# or ('Press' in elt['event'].type) imnum += 1 elt['iname'] = 'im%d' % imnum lastimage = current lastimagecrop = currentcrop #elt['image'].save(os.path.join(self.savepath,"tmp%d.png" % imnum),'PNG') else: elt['iname'] = last['iname'] last = elt self.imagesnames = {} count = 0 self.imsaved = 0 self.lastimage = "" def save(elt): self.imsaved += 1 active = elt['active'] crop = elt['image'].crop((active['x']+self.params.cropL,active['y']+self.params.cropT,active['x']+active['w']+self.params.cropR,active['y']+active['h']+self.params.cropB)) crop.save(os.path.join(self.savepath,"%s-%03d-a.png" % (self.params.title,self.imsaved)),'PNG') impath = os.path.join(self.savepath,"%s-%03d.png" % (self.params.title,self.imsaved)) elt['image'].save(impath,'PNG') self.imagesnames[elt['iname']] = impath self.lastevt = sorttl[0] self.last = None def compare(t1,t2): if not t1 or not t2: return True return ((t1['iname']!=t2['iname']) and ( ((not self.params.followActive) and self.diffImage(t1['image'],t2['image'])>self.params.diffPct) or (self.params.followActive and self.diffImage(t1['imagecrop'],t2['imagecrop'])>self.params.diffPct) ) ) steps = [] prevstep = [] scenario = dict(name=self.params.name,title=self.params.title,desc=self.params.description,steps=[]) currentzoom = [] anchorid = 0 for i,tlelt in enumerate(sorttl): if (tlelt['event'].type!='timed'): t = tlelt['timestamp']-self.starttime if 'Press' in tlelt['event'].type: steps.append(dict(action="anchor",id="a%d" % anchorid,title="Step %d" % anchorid,image="")) #steps.append(dict(action="loadImage",image="")) anchorid += 1 if compare(self.lastevt,self.last): if not self.lastevt['iname'] in self.imagesnames.keys(): save(self.lastevt) steps[-1]['image'] = self.imagesnames[self.lastevt['iname']] self.last = self.lastevt if compare(tlelt,self.last): if not tlelt['iname'] in self.imagesnames.keys(): save(tlelt) showimage = True self.last = tlelt else: showimage = False if 'Press' in tlelt['event'].type and count==0: if (tlelt['active'] != currentzoom): steps.append(dict(action='zoom', x=tlelt['active']['x'], y=tlelt['active']['y'], w=tlelt['active']['w'], h=tlelt['active']['h'], mask=True )) step = dict(action='click', button=tlelt['event'].button, x=tlelt['event'].x, y=tlelt['event'].y, count=tlelt['event'].count ) if showimage: step['image'] = self.imagesnames[tlelt['iname']]; steps.append(step) count = tlelt['event'].count if 'Release' in tlelt['event'].type: count -= 1 if showimage: steps.append(dict(action='loadImage',image=self.imagesnames[tlelt['iname']])) self.lastevt = tlelt if compare(self.last,self.lastevt): save(self.lastevt) steps.append({ "action": "zoom", "h": -1, "mask": True, "w": -1, "x": 0, "y": 0 }) steps.append(dict(action='loadImage', image=self.imagesnames[self.lastevt['iname']])) # anchor=dict(id="a%d" % anchorid,title="Step %d" % anchorid), # message=dict(type="markdown",content="# End of tuto"))) steps.append(dict(action='zoom',x=0,y=0,w=-1,h=-1,mask=True,message=dict(type="markdown",content="# End of tuto"))) steps[0]['message'] = dict(type='markdown',content="# Start of tuto") scenario['steps'] = steps scenario['image'] = dict(name=steps[0]['image']) import json js = "var sce=%s;" % json.dumps(scenario,sort_keys=True, indent=4, separators=(',', ': ')) with open("data.js",'w') as f: f.write(js) self.init(self.title) def diffImage(self,image1,image2): diff = ImageChops.difference(image1,image2).histogram() diff = 100-float(100*diff.count(0))/len(diff) return diff