How to use _ppFilename method in fMBT

Best Python code snippet using fMBT_python

fmbtgti.py

Source:fmbtgti.py Github

copy

Full Screen

...154 os.access(srcFile, os.R_OK) and155 os.stat(srcFile).st_mtime < os.stat(dstFile).st_mtime):156 return # cached file is up-to-date157 subprocess.call([fmbt_config.imagemagick_convert, srcFile] + convertArgs + [dstFile])158def _ppFilename(origFilename, preprocess):159 return origFilename + ".fmbtoir.cache." + re.sub("[^a-zA-Z0-9.]", "", preprocess) + ".png"160def _intCoords((x, y), (width, height)):161 if 0 <= x <= 1 and type(x) == float: x = x * width162 if 0 <= y <= 1 and type(y) == float: y = y * height163 return (int(round(x)), int(round(y)))164def _boxOnRegion((x1, y1, x2, y2), (minX, minY, maxX, maxY), partial=True):165 if partial:166 return (x1 < x2 and ((minX <= x1 <= maxX) or (minX <= x2 <= maxX)) and167 y1 < y2 and ((minY <= y1 <= maxY) or (minY <= y2 <= maxY)))168 else:169 return (x1 < x2 and ((minX <= x1 <= maxX) and (minX <= x2 <= maxX)) and170 y1 < y2 and ((minY <= y1 <= maxY) and (minY <= y2 <= maxY)))171def _edgeDistanceInDirection((x, y), (width, height), direction):172 x, y = _intCoords((x, y), (width, height))173 direction = direction % 360 # -90 => 270, 765 => 45174 dirRad = math.radians(direction)175 if 0 < direction < 180:176 distTopBottom = y / math.sin(dirRad)177 elif 180 < direction < 360:178 distTopBottom = -(height - y) / math.sin(dirRad)179 else:180 distTopBottom = float('inf')181 if 90 < direction < 270:182 distLeftRight = -x / math.cos(dirRad)183 elif 270 < direction <= 360 or 0 <= direction < 90:184 distLeftRight = (width - x) / math.cos(dirRad)185 else:186 distLeftRight = float('inf')187 return min(distTopBottom, distLeftRight)188### Binding to eye4graphics C-library189class _Bbox(ctypes.Structure):190 _fields_ = [("left", ctypes.c_int32),191 ("top", ctypes.c_int32),192 ("right", ctypes.c_int32),193 ("bottom", ctypes.c_int32),194 ("error", ctypes.c_int32)]195class _Rgb888(ctypes.Structure):196 _fields_ = [("red", ctypes.c_uint8),197 ("green", ctypes.c_uint8),198 ("blue", ctypes.c_uint8)]199_libpath = ["", ".",200 os.path.dirname(os.path.abspath(__file__)),201 distutils.sysconfig.get_python_lib(plat_specific=1)]202_suffix = ".so"203if os.name == "nt":204 _suffix = ".dll"205for _dirname in _libpath:206 try:207 eye4graphics = ctypes.CDLL(os.path.join(_dirname , "eye4graphics"+_suffix))208 struct_bbox = _Bbox(0, 0, 0, 0, 0)209 eye4graphics.findNextColor.restype = ctypes.c_int210 eye4graphics.findNextHighErrorBlock.argtypes = [211 ctypes.c_void_p,212 ctypes.c_void_p,213 ctypes.c_int,214 ctypes.c_int,215 ctypes.c_double,216 ctypes.c_void_p]217 eye4graphics.findNextDiff.restype = ctypes.c_int218 eye4graphics.findNextDiff.argtypes = [219 ctypes.c_void_p,220 ctypes.c_void_p,221 ctypes.c_void_p,222 ctypes.c_double,223 ctypes.c_double,224 ctypes.c_void_p,225 ctypes.c_void_p,226 ctypes.c_int]227 eye4graphics.openImage.argtypes = [ctypes.c_char_p]228 eye4graphics.openImage.restype = ctypes.c_void_p229 eye4graphics.openedImageDimensions.argtypes = [ctypes.c_void_p, ctypes.c_void_p]230 eye4graphics.closeImage.argtypes = [ctypes.c_void_p]231 eye4graphics.rgb5652rgb.restype = ctypes.c_int232 eye4graphics.rgb5652rgb.argtypes = [233 ctypes.c_void_p,234 ctypes.c_int,235 ctypes.c_int,236 ctypes.c_void_p]237 break238 except: pass239else:240 raise ImportError("%s cannot load eye4graphics%s" % (__file__, _suffix))241def _e4gOpenImage(filename):242 image = eye4graphics.openImage(filename)243 if not image:244 raise IOError('Cannot open image "%s"' % (filename,))245 else:246 return image247def _e4gImageDimensions(e4gImage):248 struct_bbox = _Bbox(0, 0, 0, 0, 0)249 eye4graphics.openedImageDimensions(ctypes.byref(struct_bbox), e4gImage)250 return (struct_bbox.right, struct_bbox.bottom)251def _e4gImageIsBlank(filename):252 e4gImage = _e4gOpenImage(filename)253 rv = (eye4graphics.openedImageIsBlank(e4gImage) == 1)254 eye4graphics.closeImage(e4gImage)255 return rv256### end of binding to eye4graphics.so257def sortItems(items, criteria):258 """259 Returns GUIItems sorted according to given criteria260 Parameters:261 items (list of GUIItems):262 items to be sorted263 criteria (string):264 Supported values:265 "topleft" - sort by top left coordinates of items266 "area" - sort by areas of items267 """268 if criteria == "topleft":269 top_left_items = [(i.bbox()[1], i.bbox()[0], i) for i in items]270 top_left_items.sort()271 return [tli[2] for tli in top_left_items]272 elif criteria == "area":273 area_items = [274 ((i.bbox()[2] - i.bbox()[0]) * (i.bbox()[3] - i.bbox()[1]), i)275 for i in items]276 area_items.sort()277 return [ai[1] for ai in area_items]278 else:279 raise ValueError('invalid sort criteria "%s"' % (criteria,))280class GUITestConnection(object):281 """282 Implements GUI testing primitives needed by GUITestInterface.283 All send* and recv* methods return284 - True on success285 - False on user error (unknown keyName, coordinates out of range)286 - raise Exception on framework error (connection lost, missing287 dependencies).288 """289 def sendPress(self, keyName):290 return self.sendKeyDown(keyName) and self.sendKeyUp(keyName)291 def sendKeyDown(self, keyName):292 raise NotImplementedError('sendKeyDown("%s") needed but not implemented.' % (keyName,))293 def sendKeyUp(self, keyName):294 raise NotImplementedError('sendKeyUp("%s") needed but not implemented.' % (keyName,))295 def sendTap(self, x, y):296 return self.sendTouchDown(x, y) and self.sendTouchUp(x, y)297 def sendTouchDown(self, x, y):298 raise NotImplementedError('sendTouchDown(%d, %d) needed but not implemented.' % (x, y))299 def sendTouchMove(self, x, y):300 raise NotImplementedError('sendTouchMove(%d, %d) needed but not implemented.' % (x, y))301 def sendTouchUp(self, x, y):302 raise NotImplementedError('sendTouchUp(%d, %d) needed but not implemented.' % (x, y))303 def sendType(self, text):304 raise NotImplementedError('sendType("%s") needed but not implemented.' % (text,))305 def recvScreenshot(self, filename):306 """307 Saves screenshot from the GUI under test to given filename.308 """309 raise NotImplementedError('recvScreenshot("%s") needed but not implemented.' % (filename,))310 def recvScreenUpdated(self, waitTime, pollDelay):311 """312 Wait until the screen has been updated, but no longer than the313 timeout (waitTime). Return True if the screen was updated314 before the timeout, otherwise False.315 Implementing this method is optional. If not implemented, the316 method returns None, and an inefficient recvScreenshot-based317 implementation is used instead from fmbtgti. pollDelay can be318 ignored if more efficient solutions are available319 (update-event based triggering, for instance).320 """321 return None322 def target(self):323 """324 Returns a string that is unique to each test target. For325 instance, Android device serial number.326 """327 return "GUITestConnectionTarget"328class SimulatedGUITestConnection(GUITestConnection):329 """330 Simulates GUITestConnection: records method calls and fakes screenshots331 All send* methods return True. recvScreenshot returns always True332 if non-empty list of fake screenshot filenames is given (see333 constructor and setScreenshotFilenames). Otherwise it returns334 False.335 """336 def __init__(self, screenshotFilenames=()):337 """338 Parameters:339 screenshotFilenames (tuple of filenames):340 calling recvScreenshot uses next item in this tuple as341 the observed screenshot.342 """343 GUITestConnection.__init__(self)344 self.setScreenshotFilenames(screenshotFilenames)345 self._calls = []346 for recordedMethod in ("sendPress", "sendKeyDown", "sendKeyUp",347 "sendTap", "sendTouchDown", "sendTouchMove",348 "sendTouchUp", "sendType"):349 self.__dict__[recordedMethod] = self._recorder(recordedMethod)350 def _recorder(self, method):351 return lambda *args, **kwargs: self._calls.append(352 (time.time(), method, args, kwargs)) or True353 def history(self):354 return self._calls355 def clearHistory(self):356 self._calls = []357 def setScreenshotFilenames(self, screenshotFilenames):358 self._screenshotFilenames = screenshotFilenames359 self._nextScreenshotFilename = 0360 def recvScreenshot(self, filename):361 self._calls.append((time.time(), "recvScreenshot", (filename,), {}))362 if self._screenshotFilenames:363 if self._nextScreenshotFilename >= len(self._screenshotFilenames):364 self._nextScreenshotFilename = 0365 fakeFilename = self._screenshotFilenames[self._nextScreenshotFilename]366 self._nextScreenshotFilename += 1367 if not os.access(fakeFilename, os.R_OK):368 raise IOError('screenshot file not found: "%s"' % (fakeFilename,))369 shutil.copy(fakeFilename, filename)370 return True371 else:372 return False373 def target(self):374 return "SimulatedGUITestConnection"375class OrEngine(object):376 """377 Optical recognition engine. Base class for OCR and OIR engines,378 enables registering engine instances.379 """380 def __init__(self, *args, **kwargs):381 pass382 def register(self, defaultOcr=False, defaultOir=False):383 """384 Register this engine instance to the list of OCR and/or OIR385 engines.386 Parameters:387 defaultOcr (optional, boolean):388 if True, use this OCR engine by default in all new389 GUITestInterface instances. The default is False.390 defaultOir (optional, boolean):391 if True, use this OIR engine by default in all new392 GUITestInterface instances. The default is False.393 Returns the index with which the engine was registered to the394 list of OCR or OIR engines. If this instance implements both395 OCR and OIR engines, returns pair (OCR index, OIR index).396 """397 # Allow a single engine implement both OCR and OIR engine398 # interfaces. Therefore, it must be possible to call399 # e.register(defaultOcr=True, defaultOir=True).400 #401 global _g_defaultOcrEngine, _g_defaultOirEngine402 global _g_ocrEngines, _g_oirEngines403 engineIndexes = []404 if isinstance(self, OcrEngine):405 if not self in _g_ocrEngines:406 _g_ocrEngines.append(self)407 engineIndexes.append(_g_ocrEngines.index(self))408 if defaultOcr:409 _g_defaultOcrEngine = self410 if isinstance(self, OirEngine):411 if not self in _g_oirEngines:412 _g_oirEngines.append(self)413 engineIndexes.append(_g_oirEngines.index(self))414 if defaultOir:415 _g_defaultOirEngine = self416 if len(engineIndexes) == 1:417 return engineIndexes[0]418 else:419 return engineIndexes420class OcrEngine(OrEngine):421 """422 This is an abstract interface for OCR engines that can be plugged423 into fmbtgti.GUITestInterface instances and Screenshots.424 To implement an OCR engine, you need to override _findText() at425 minimum. See _findText documentation in this class for426 requirements.427 If possible in your OCR engine, you can provide _dumpOcr() to428 reveal what is recognized in screenshots.429 For efficient caching of results and freeing cached results, you430 can override _addScreenshot() and _removeScreenshot(). Every431 screenshot is added before findText() or dumpOcr().432 A typical usage of OcrEngine instance:433 - oe.addScreenshot(ss)434 - oe.findText(ss, text1, <engine/screenshot/find-specific-args>)435 - oe.findText(ss, text2, <engine/screenshot/find-specific-args>)436 - oe.removeScreenshot(ss)437 Note that there may be several screenshots added before they are438 removed.439 """440 def __init__(self, *args, **kwargs):441 super(OcrEngine, self).__init__(*args, **kwargs)442 self._ssFindTextDefaults = {}443 self._findTextDefaults = {}444 ocrFindArgs, _ = _takeOcrArgs(self, kwargs)445 self._setFindTextDefaults(ocrFindArgs)446 def dumpOcr(self, screenshot, **kwargs):447 """448 Returns what is recognized in the screenshot. For debugging449 purposes.450 """451 ocrArgs = self.__ocrArgs(screenshot, **kwargs)452 return self._dumpOcr(screenshot, **ocrArgs)453 def _dumpOcr(self, screenshot, **kwargs):454 return None455 def addScreenshot(self, screenshot, **findTextDefaults):456 """457 Prepare for finding text from the screenshot.458 Parameters:459 screenshot (fmbtgti.Screenshot)460 screenshot object to be searched from.461 other parameters (optional)462 findText defaults for this screenshot.463 Notice that there may be many screenshots simultaneously.464 Do not keep reference to the screenshot object.465 """466 self.setScreenshotFindTextDefaults(screenshot, **findTextDefaults)467 return self._addScreenshot(screenshot, **findTextDefaults)468 def _addScreenshot(self, screenshot, **findTextDefaults):469 pass470 def removeScreenshot(self, screenshot):471 """472 OCR queries on the screenshot will not be made anymore.473 """474 self._removeScreenshot(screenshot)475 try:476 del self._ssFindTextDefaults[id(screenshot)]477 except KeyError:478 raise KeyError('screenshot "%s" does not have findTextDefaults. '479 'If OcrEngine.addScreenshot() is overridden, it '480 '*must* call parent\'s addScreenshot.' % (screenshot.filename(),))481 def _removeScreenshot(self, screenshot):482 pass483 def setFindTextDefaults(self, **findTextDefaults):484 return self._setFindTextDefaults(findTextDefaults, screenshot=None)485 def setScreenshotFindTextDefaults(self, screenshot, **findTextDefaults):486 return self._setFindTextDefaults(findTextDefaults, screenshot=screenshot)487 def _setFindTextDefaults(self, defaults, screenshot=None):488 """489 Set default values for optional arguments for findText().490 Parameters:491 defaults (dictionary)492 Default keyword arguments and their values.493 screenshot (optional, fmbtgti.Screenshot instance)494 Use the defaults for findText on this screenshot. If495 the defaults are None, make them default for all496 screenshots. Screenshot-specific defaults override497 engine default.498 """499 if screenshot == None:500 self._findTextDefaults.update(defaults)501 else:502 ssid = id(screenshot)503 if not ssid in self._ssFindTextDefaults:504 self._ssFindTextDefaults[ssid] = self._findTextDefaults.copy()505 self._ssFindTextDefaults[ssid].update(defaults)506 def findTextDefaults(self, screenshot=None):507 if screenshot == None:508 return self._findTextDefaults509 elif id(screenshot) in self._ssFindTextDefaults:510 return self._ssFindTextDefaults[id(screenshot)]511 else:512 return None513 def _findTextArgNames(self):514 """515 Returns names of optional findText arguments.516 """517 return inspect.getargspec(self._findText).args[3:]518 def __ocrArgs(self, screenshot, **priorityArgs):519 ocrArgs = {}520 ocrArgs.update(self._findTextDefaults)521 ssId = id(screenshot)522 if ssId in self._ssFindTextDefaults:523 ocrArgs.update(self._ssFindTextDefaults[ssId])524 ocrArgs.update(priorityArgs)525 return ocrArgs526 def findText(self, screenshot, text, **kwargs):527 """528 Return list of fmbtgti.GUIItems that match to text.529 """530 ocrArgs = self.__ocrArgs(screenshot, **kwargs)531 return self._findText(screenshot, text, **ocrArgs)532 def _findText(self, screenshot, text, **kwargs):533 """534 Find appearances of text from the screenshot.535 Parameters:536 screenshot (fmbtgti.Screenshot)537 Screenshot from which text is to be searched538 for. Use Screenshot.filename() to get the filename.539 text (string)540 text to be searched for.541 other arguments (engine specific)542 kwargs contain keyword arguments given to543 findText(screenshot, text, ...), already extended544 first with screenshot-specific findTextDefaults, then545 with engine-specific findTextDefaults.546 _findText *must* define all engine parameters as547 explicit keyword arguments:548 def _findText(self, screenshot, text, engArg1=42):549 ...550 Return list of fmbtgti.GUIItems.551 """552 raise NotImplementedError("_findText needed but not implemented.")553class _EyenfingerOcrEngine(OcrEngine):554 """555 OCR engine parameters that can be used in all556 ...OcrText() methods (swipeOcrText, tapOcrText, findItemsByOcrText, ...):557 match (float, optional):558 minimum match score in range [0.0, 1.0]. The default is559 1.0 (exact match).560 area ((left, top, right, bottom), optional):561 search from the given area only. Left, top, right and562 bottom are either absolute coordinates (integers) or563 floats in range [0.0, 1.0]. In the latter case they are564 scaled to screenshot dimensions. The default is (0.0,565 0.0, 1.0, 1.0), that is, search everywhere in the566 screenshot.567 lang (string, optional):568 pass given language option to Tesseract. See supported569 LANGUAGES (-l) in Tesseract documentation. The default570 is "eng" (English).571 pagesegmodes (list of integers, optional):572 try all integers as tesseract -pagesegmode573 arguments. The default is [3], another good option could574 be [3, 6].575 preprocess (string, optional):576 preprocess filter to be used in OCR for better577 result. Refer to eyenfinger.autoconfigure to search for578 a good one, or try with ImageMagick's convert:579 $ convert screenshot.png <preprocess> screenshot-pp.png580 $ tesseract screenshot-pp.png stdout581 configfile (string, optional):582 Tesseract configuration file.583 Example: limit recognized characters to hexadecimals by creating file584 "hexchars" with content585 tessedit_char_whitelist 0123456789abcdefABCDEF586 To use this file in a single run, pass it to any Ocr method:587 dut.verifyOcrText("DEADBEEF", configfile="hexchars")588 or to use it on every Ocr method, set it as a default:589 dut.ocrEngine().setFindTextDefaults(configfile="hexchars")590 """591 class _OcrResults(object):592 __slots__ = ("filename", "screenSize", "pagesegmodes", "preprocess", "area", "words", "lang", "configfile")593 def __init__(self, filename, screenSize):594 self.filename = filename595 self.screenSize = screenSize596 self.pagesegmodes = None597 self.preprocess = None598 self.area = None599 self.words = None600 self.lang = None601 self.configfile = None602 def __init__(self, *args, **engineDefaults):603 engineDefaults["area"] = engineDefaults.get("area", (0.0, 0.0, 1.0, 1.0))604 engineDefaults["lang"] = engineDefaults.get("lang", "eng")605 engineDefaults["match"] = engineDefaults.get("match", 1.0)606 engineDefaults["pagesegmodes"] = engineDefaults.get("pagesegmodes", _OCRPAGESEGMODES)607 engineDefaults["preprocess"] = engineDefaults.get("preprocess", _OCRPREPROCESS)608 engineDefaults["configfile"] = engineDefaults.get("configfile", None)609 super(_EyenfingerOcrEngine, self).__init__(*args, **engineDefaults)610 self._ss = {} # OCR results for screenshots611 def _addScreenshot(self, screenshot, **findTextDefaults):612 ssId = id(screenshot)613 self._ss[ssId] = _EyenfingerOcrEngine._OcrResults(screenshot.filename(), screenshot.size())614 def _removeScreenshot(self, screenshot):615 ssId = id(screenshot)616 if ssId in self._ss:617 del self._ss[ssId]618 def _findText(self, screenshot, text, match=None, preprocess=None, area=None, pagesegmodes=None, lang=None, configfile=None):619 ssId = id(screenshot)620 self._assumeOcrResults(screenshot, preprocess, area, pagesegmodes, lang, configfile)621 for ppfilter in self._ss[ssId].words.keys():622 try:623 score_text_bbox_list = eyenfinger.findText(624 text, self._ss[ssId].words[ppfilter], match=match)625 if not score_text_bbox_list:626 continue627 else:628 break629 except eyenfinger.BadMatch:630 continue631 else:632 return []633 retval = [GUIItem("OCR text (match %.2f)" % (score,),634 bbox, self._ss[ssId].filename,635 ocrFind=text, ocrFound=matching_text)636 for score, matching_text, bbox in score_text_bbox_list]637 return retval638 def _dumpOcr(self, screenshot, match=None, preprocess=None, area=None, pagesegmodes=None, lang=None, configfile=None):639 ssId = id(screenshot)640 self._assumeOcrResults(screenshot, preprocess, area, pagesegmodes, lang, configfile)641 w = []642 for ppfilter in self._ss[ssId].preprocess:643 for word in self._ss[ssId].words[ppfilter]:644 for appearance, (wid, middle, bbox) in enumerate(self._ss[ssId].words[ppfilter][word]):645 (x1, y1, x2, y2) = bbox646 w.append((word, (x1, y1, x2, y2)))647 return sorted(set(w), key=lambda i:(i[1][1]/8, i[1][0]))648 def _assumeOcrResults(self, screenshot, preprocess, area, pagesegmodes, lang, configfile):649 ssId = id(screenshot)650 if not type(preprocess) in (list, tuple):651 preprocess = [preprocess]652 if (self._ss[ssId].words == None653 or self._ss[ssId].preprocess != preprocess654 or self._ss[ssId].area != area655 or self._ss[ssId].lang != lang656 or self._ss[ssId].configfile != configfile):657 self._ss[ssId].words = {}658 self._ss[ssId].preprocess = preprocess659 self._ss[ssId].area = area660 self._ss[ssId].lang = lang661 self._ss[ssId].configfile = configfile662 for ppfilter in preprocess:663 pp = ppfilter % { "zoom": "-resize %sx" % (self._ss[ssId].screenSize[0] * 2) }664 try:665 eyenfinger.iRead(source=self._ss[ssId].filename, ocr=True, preprocess=pp, ocrArea=area, ocrPageSegModes=pagesegmodes, lang=lang, configfile=configfile)666 except Exception:667 self._ss[ssId].words = None668 raise669 self._ss[ssId].words[ppfilter] = eyenfinger._g_words670def _defaultOcrEngine():671 if _g_defaultOcrEngine:672 return _g_defaultOcrEngine673 else:674 _EyenfingerOcrEngine().register(defaultOcr=True)675 return _g_defaultOcrEngine676class OirEngine(OrEngine):677 """678 This is an abstract interface for OIR (optical image recognition)679 engines that can be plugged into fmbtgti.GUITestInterface680 instances and Screenshots.681 To implement an OIR engine, you need to override _findBitmap() at682 minimum. See _findBitmap documentation in this class for683 requirements.684 This base class provides full set of OIR parameters to685 _findBitmap. The parameters are combined from686 - OirEngine find defaults, specified when OirEngine is687 instantiated.688 - Screenshot instance find defaults.689 - bitmap / bitmap directory find defaults (read from the690 .fmbtoirrc that is in the same directory as the bitmap).691 - ...Bitmap() method parameters.692 The latter in the list override the former.693 For efficient caching of results and freeing cached results, you694 can override _addScreenshot() and _removeScreenshot(). Every695 screenshot is added before findBitmap().696 A typical usage of OirEngine instance:697 - oe.addScreenshot(ss)698 - oe.findBitmap(ss, bmpFilename1, <engine/screenshot/find-specific-args>)699 - oe.findBitmap(ss, bmpFilename2, <engine/screenshot/find-specific-args>)700 - oe.removeScreenshot(ss)701 Note that there may be several screenshots added before they are702 removed. ss is a Screenshot instance. Do not keep references to703 Screenshot intances, otherwise garbage collector will not remove704 them.705 """706 def __init__(self, *args, **kwargs):707 super(OirEngine, self).__init__(*args, **kwargs)708 self._ssFindBitmapDefaults = {}709 self._findBitmapDefaults = {}710 oirArgs, _ = _takeOirArgs(self, kwargs)711 self._setFindBitmapDefaults(oirArgs)712 def addScreenshot(self, screenshot, **findBitmapDefaults):713 """714 Prepare for finding bitmap from the screenshot.715 Parameters:716 screenshot (fmbtgti.Screenshot)717 screenshot object to be searched from.718 other parameters (optional)719 findBitmap defaults for this screenshot.720 Notice that there may be many screenshots simultaneously.721 Do not keep reference to the screenshot object.722 """723 self.setScreenshotFindBitmapDefaults(screenshot, **findBitmapDefaults)724 return self._addScreenshot(screenshot, **findBitmapDefaults)725 def _addScreenshot(self, screenshot, **findBitmapDefaults):726 pass727 def removeScreenshot(self, screenshot):728 """729 OIR queries on the screenshot will not be made anymore.730 """731 self._removeScreenshot(screenshot)732 try:733 del self._ssFindBitmapDefaults[id(screenshot)]734 except KeyError:735 raise KeyError('screenshot "%s" does not have findBitmapDefaults. '736 'If OirEngine.addScreenshot() is overridden, it '737 '*must* call parent\'s addScreenshot.' % (screenshot.filename(),))738 def _removeScreenshot(self, screenshot):739 pass740 def setFindBitmapDefaults(self, **findBitmapDefaults):741 return self._setFindBitmapDefaults(findBitmapDefaults, screenshot=None)742 def setScreenshotFindBitmapDefaults(self, screenshot, **findBitmapDefaults):743 return self._setFindBitmapDefaults(findBitmapDefaults, screenshot=screenshot)744 def _setFindBitmapDefaults(self, defaults, screenshot=None):745 """746 Set default values for optional arguments for findBitmap().747 Parameters:748 defaults (dictionary)749 Default keyword arguments and their values.750 screenshot (optional, fmbtgti.Screenshot instance)751 Use the defaults for findBitmap on this screenshot. If752 the defaults are None, make them default for all753 screenshots. Screenshot-specific defaults override754 engine default.755 """756 if screenshot == None:757 self._findBitmapDefaults.update(defaults)758 else:759 ssid = id(screenshot)760 if not ssid in self._ssFindBitmapDefaults:761 self._ssFindBitmapDefaults[ssid] = self._findBitmapDefaults.copy()762 self._ssFindBitmapDefaults[ssid].update(defaults)763 def findBitmapDefaults(self, screenshot=None):764 if screenshot == None:765 return self._findBitmapDefaults766 elif id(screenshot) in self._ssFindBitmapDefaults:767 return self._ssFindBitmapDefaults[id(screenshot)]768 else:769 return None770 def _findBitmapArgNames(self):771 """772 Returns names of optional findBitmap arguments.773 """774 return inspect.getargspec(self._findBitmap).args[3:]775 def __oirArgs(self, screenshot, bitmap, **priorityArgs):776 oirArgs = {}777 oirArgs.update(self._findBitmapDefaults)778 ssId = id(screenshot)779 if ssId in self._ssFindBitmapDefaults:780 oirArgs.update(self._ssFindBitmapDefaults[ssId])781 oirArgs.update(priorityArgs)782 return oirArgs783 def findBitmap(self, screenshot, bitmap, **kwargs):784 """785 Return list of fmbtgti.GUIItems that match to bitmap.786 """787 oirArgs = self.__oirArgs(screenshot, bitmap, **kwargs)788 bitmapLocsFilename = bitmap + _g_forcedLocExt789 if os.access(bitmapLocsFilename, os.R_OK):790 # Use hardcoded bitmap locations file instead of real OIR791 # bitmap.png.locs file format:792 # [(x11, y11, x12, y12), ..., (xn1, yn1, xn2, yn2)]793 try:794 bboxList = eval(file(bitmapLocsFilename).read().strip())795 foundItems = []796 for (left, top, right, bottom) in bboxList:797 x1, y1 = _intCoords((left, top), screenshot.size())798 x2, y2 = _intCoords((right, bottom), screenshot.size())799 foundItems.append(800 GUIItem("bitmap location", (x1, y1, x2, y2),801 screenshot.filename(), bitmap=bitmapLocsFilename))802 return foundItems803 except Exception, e:804 raise ValueError('Error reading bounding box list from %s: %s' %805 repr(bitmapLocsFilename), e)806 return self._findBitmap(screenshot, bitmap, **oirArgs)807 def _findBitmap(self, screenshot, bitmap, **kwargs):808 """809 Find appearances of bitmap from the screenshot.810 Parameters:811 screenshot (fmbtgti.Screenshot)812 Screenshot from which bitmap is to be searched813 for. Use Screenshot.filename() to get the filename.814 bitmap (string)815 bitmap to be searched for.816 other arguments (engine specific)817 kwargs contain keyword arguments given to818 findBitmap(screenshot, bitmap, ...), already extended819 first with screenshot-specific findBitmapDefaults, then820 with engine-specific findBitmapDefaults.821 _findBitmap *must* define all engine parameters as822 explicit keyword arguments:823 def _findBitmap(self, screenshot, bitmap, engArg1=42):824 ...825 Returns list of fmbtgti.GUIItems.826 """827 raise NotImplementedError("_findBitmap needed but not implemented.")828class _Eye4GraphicsOirEngine(OirEngine):829 """OIR engine parameters that can be used in all830 ...Bitmap() methods (swipeBitmap, tapBitmap, findItemsByBitmap, ...):831 colorMatch (float, optional):832 required color matching accuracy. The default is 1.0833 (exact match). For instance, 0.75 requires that every834 pixel's every RGB component value on the bitmap is at835 least 75 % match with the value of corresponding pixel's836 RGB component in the screenshot.837 opacityLimit (float, optional):838 threshold for comparing pixels with non-zero alpha839 channel. Pixels less opaque than the given threshold are840 skipped in match comparison. The default is 0, that is,841 alpha channel is ignored.842 area ((left, top, right, bottom), optional):843 search bitmap from the given area only. Left, top right844 and bottom are either absolute coordinates (integers) or845 floats in range [0.0, 1.0]. In the latter case they are846 scaled to screenshot dimensions. The default is (0.0,847 0.0, 1.0, 1.0), that is, search everywhere in the848 screenshot.849 limit (integer, optional):850 number of returned matches is limited to the limit. The851 default is -1: all matches are returned. Applicable in852 findItemsByBitmap.853 allowOverlap (boolean, optional):854 allow returned icons to overlap. If False, returned list855 contains only non-overlapping bounding boxes. The856 default is False.857 scale (float or pair of floats, optional):858 scale to be applied to the bitmap before859 matching. Single float is a factor for both X and Y860 axis, pair of floats is (xScale, yScale). The default is861 1.0.862 bitmapPixelSize (integer, optional):863 size of pixel rectangle on bitmap for which there must864 be same color on corresponding screenshot rectangle. If865 scale is 1.0, default is 1 (rectangle is 1x1). If scale866 != 1.0, the default is 2 (rectangle is 2x2).867 screenshotPixelSize (integer, optional):868 size of pixel rectangle on screenshot in which there869 must be a same color pixel as in the corresponding870 rectangle on bitmap. The default is scale *871 bitmapPixelSize.872 preprocess (string, optional):873 preprocess parameters that are executed to both screenshot874 and reference bitmap before running findBitmap. By default875 there is no preprocessing.876 Example: d.verifyBitmap("ref.png", preprocess="-threshold 60%")877 will execute two imagemagick commands:878 1. convert screenshot.png -threshold 60% screenshot-pp.png879 2. convert ref.png -threshold 60% ref-pp.png880 and then search for ref-pp.png in screenshot-pp.png. This results881 in black-and-white comparison (immune to slight color changes).882 If unsure about parameters, but you have a bitmap that should be883 detected in a screenshot, try obj.oirEngine().adjustParameters().884 Example:885 d.enableVisualLog("params.html")886 screenshot = d.refreshScreenshot()887 results = d.oirEngine().adjustParameters(screenshot, "mybitmap.png")888 if results:889 item, params = results[0]890 print "found %s with parameters:" % (item,)891 print "\n".join(sorted([" %s = %s" % (k, params[k]) for k in params]))892 print "verify:", d.verifyBitmap("mybitmap.png", **params)893 Notice, that you can force refreshScreenshot to load old screenshot:894 d.refreshScreenshot("old.png")895 """896 def __init__(self, *args, **engineDefaults):897 engineDefaults["colorMatch"] = engineDefaults.get("colorMatch", 1.0)898 engineDefaults["opacityLimit"] = engineDefaults.get("opacityLimit", 0.0)899 engineDefaults["area"] = engineDefaults.get("area", (0.0, 0.0, 1.0, 1.0))900 engineDefaults["limit"] = engineDefaults.get("limit", -1)901 engineDefaults["allowOverlap"] = engineDefaults.get("allowOverlap", False)902 engineDefaults["scale"] = engineDefaults.get("scale", 1.0)903 engineDefaults["bitmapPixelSize"] = engineDefaults.get("bitmapPixelSize", 0)904 engineDefaults["screenshotPixelSize"] = engineDefaults.get("screenshotPixelSize", 0)905 engineDefaults["preprocess"] = engineDefaults.get("preprocess", "")906 OirEngine.__init__(self, *args, **engineDefaults)907 self._openedImages = {}908 # openedRelatedScreenshots maps a screenshot filename to909 # a list of preprocessed screenshot objects. All those objects910 # must be closed when the screenshot is removed.911 self._openedRelatedScreenshots = {}912 self._findBitmapCache = {}913 def _addScreenshot(self, screenshot, **findBitmapDefaults):914 filename = screenshot.filename()915 self._openedImages[filename] = _e4gOpenImage(filename)916 # make sure size() is available, this can save an extra917 # opening of the screenshot file.918 if screenshot.size(allowReadingFile=False) == None:919 screenshot.setSize(_e4gImageDimensions(self._openedImages[filename]))920 self._findBitmapCache[filename] = {}921 def _removeScreenshot(self, screenshot):922 filename = screenshot.filename()923 if filename in self._openedRelatedScreenshots:924 for screenshotPP in self._openedRelatedScreenshots[filename]:925 self._removeScreenshot(screenshotPP)926 del self._openedRelatedScreenshots[filename]927 eye4graphics.closeImage(self._openedImages[filename])928 del self._openedImages[filename]929 del self._findBitmapCache[filename]930 def adjustParameters(self, screenshot, bitmap,931 scaleRange = [p/100.0 for p in range(110,210,10)],932 colorMatchRange = [p/100.0 for p in range(100,60,-10)],933 pixelSizeRange = range(2,5),934 resultCount = 1,935 **oirArgs):936 """937 Search for scale, colorMatch, bitmapPixelSize and938 screenshotPixelSize parameters that find the bitmap in the939 screenshot.940 Parameters:941 screenshot (Screenshot instance):942 screenshot that contains the bitmap.943 bitmap (string):944 bitmap filename.945 scaleRange (list of floats, optional):946 scales to go through.947 The default is: 1.1, 1.2, ... 2.0.948 colorMatchRange (list of floats, optional):949 colorMatches to try out.950 The default is: 1.0, 0.9, ... 0.7.951 pixelSizeRange (list of integers, optional):952 values for bitmapPixelSize and screenshotPixelSize.953 The default is: [2, 3]954 resultCount (integer, optional):955 number of parameter combinations to be found.956 The default is 1. 0 is unlimited.957 other OIR parameters: as usual, refer to engine documentation.958 Returns list of pairs: (GUIItem, findParams), where959 GUIItem is the detected item (GUIItem.bbox() is the box around it),960 and findParams is a dictionary containing the parameters.961 """962 if not screenshot.filename() in self._findBitmapCache:963 self.addScreenshot(screenshot)964 ssAdded = True965 else:966 ssAdded = False967 retval = []968 for colorMatch in colorMatchRange:969 for pixelSize in pixelSizeRange:970 for scale in scaleRange:971 findParams = oirArgs.copy()972 findParams.update({"colorMatch": colorMatch,973 "limit": 1,974 "scale": scale,975 "bitmapPixelSize": pixelSize,976 "screenshotPixelSize": pixelSize})977 results = self.findBitmap(screenshot, bitmap,978 **findParams)979 if results:980 retval.append((results[0], findParams))981 if len(retval) == resultCount:982 return retval983 if ssAdded:984 self.removeScreenshot(screenshot)985 return retval986 def _findBitmap(self, screenshot, bitmap, colorMatch=None,987 opacityLimit=None, area=None, limit=None,988 allowOverlap=None, scale=None,989 bitmapPixelSize=None, screenshotPixelSize=None,990 preprocess=None):991 """992 Find items on the screenshot that match to bitmap.993 """994 ssFilename = screenshot.filename()995 ssSize = screenshot.size()996 cacheKey = (bitmap, colorMatch, opacityLimit, area, limit,997 scale, bitmapPixelSize, screenshotPixelSize, preprocess)998 if cacheKey in self._findBitmapCache[ssFilename]:999 return self._findBitmapCache[ssFilename][cacheKey]1000 self._findBitmapCache[ssFilename][cacheKey] = []1001 if preprocess:1002 ssFilenamePP = _ppFilename(ssFilename, preprocess)1003 bitmapPP = _ppFilename(bitmap, preprocess)1004 if not ssFilenamePP in self._openedImages:1005 _convert(ssFilename, preprocess, ssFilenamePP)1006 screenshotPP = Screenshot(ssFilenamePP)1007 self.addScreenshot(screenshotPP)1008 if not ssFilename in self._openedRelatedScreenshots:1009 self._openedRelatedScreenshots[ssFilename] = []1010 self._openedRelatedScreenshots[ssFilename].append(screenshotPP)1011 _convert(bitmap, preprocess, bitmapPP)1012 ssFilename = ssFilenamePP1013 bitmap = bitmapPP1014 self._findBitmapCache[ssFilename][cacheKey] = []1015 e4gIcon = _e4gOpenImage(bitmap)1016 matchCount = 01017 leftTopRightBottomZero = (_intCoords((area[0], area[1]), ssSize) +...

Full Screen

Full Screen

Automation Testing Tutorials

Learn to execute automation testing from scratch with LambdaTest Learning Hub. Right from setting up the prerequisites to run your first automation test, to following best practices and diving deeper into advanced test scenarios. LambdaTest Learning Hubs compile a list of step-by-step guides to help you be proficient with different test automation frameworks i.e. Selenium, Cypress, TestNG etc.

LambdaTest Learning Hubs:

YouTube

You could also refer to video tutorials over LambdaTest YouTube channel to get step by step demonstration from industry experts.

Run fMBT automation tests on LambdaTest cloud grid

Perform automation testing on 3000+ real desktop and mobile devices online.

Try LambdaTest Now !!

Get 100 minutes of automation test minutes FREE!!

Next-Gen App & Browser Testing Cloud

Was this article helpful?

Helpful

NotHelpful