def get_single_rgb_color_from_zone(self, zone): screen = self.get_area(zone) scr = ImageProcessor()._get_screenshot(screen) rgb = scr.convert('RGB') r, g, b = rgb.getpixel((1, 1)) return [r, g, b]
def _init_static_elements(self, screen=None): """Init position of static elements of window. Assumes that window is on screen or error will be raised """ #init buttons for button in self.buttons.values(): button.find_on_screen(screen) screen = ImageProcessor().get_screenshot() if screen is None else screen #check window if "check" in self.config: images_to_check = [] if isinstance(self.config["check"], list): for img_name in self.config["check"]: images_to_check.append(get_image_from_config(img_name)) if type(images_to_check[0]) == list: for image in images_to_check[0]: res = ImageProcessor().is_image_on_screen(image, screen=screen) if not res: msg = "Image {} was not found at screen".format(image) ErrorHandler().report_error(msg) raise RuntimeError(msg) elif type(images_to_check) == list: for image in images_to_check: try: ImageProcessor().image_should_be_on_screen(image[0], image[1], screen=screen) except RuntimeError as e: pass else: images_to_check.append(get_image_from_config(self.config["check"])) for image in images_to_check: ImageProcessor().image_should_be_on_screen(image[0], image[1], screen=screen)
def get_button_info(config): """Returns list of states info""" states = {} # config can contain simple filename if isinstance(config, (str, bytes)): states[STATE_NORMAL] = (ImageProcessor().load_image(config), DEFAULT_THRESHOLD) elif isinstance(config, dict): # or filename and threshold # or list of states # or threshold and list of states default_threshold = config[ THRESHOLD_LABEL] if THRESHOLD_LABEL in config else DEFAULT_THRESHOLD if IMAGE_LABEL in config: states[STATE_NORMAL] = (ImageProcessor().load_image( config[IMAGE_LABEL]), default_threshold) elif STATES_LABEL in config: states_config = config[STATES_LABEL] for state_label in POSSIBLE_STATES: if state_label in states_config: states[state_label] = get_state_info( states_config[state_label], default_threshold) else: raise AssertionError("image or states must be defined") else: raise AssertionError("Lists are not supported in button block") return states
def find_on_screen(states, screen=None): #creates the Class object - image_processor image_processor = ImageProcessor() #checks if screen is provided, else gets the active window screenshot screen = screen if screen is not None else image_processor._get_screenshot( ) #collects images images_to_find = states.values() #searches for image in state on screen coords = image_processor.find_one_of(images_to_find, screen=screen) #if found - calculates the image position (coordinates) if coords is not None: return coords.get_pos() #try again if not found in first attempt ErrorHandler().report_warning("First try was unsuccessful") utils.sleep(0.020) coords = image_processor.find_one_of(images_to_find) if coords is not None: return coords.get_pos() #no one state is found #prepare the error message content images = [] for state_name, state_info in states.items(): images.append((state_name, state_info[0])) msg = "Button not found on screen in all possible states" images.append(("screen", screen)) ErrorHandler().report_error(msg, *images) raise RuntimeError(msg)
def wait_for_animation_starts(self, zone=None, timeout=15, threshold=0.99, step=0.5): #convert passed args to float values timeout = float(timeout) threshold = float(threshold) step = float(step) # gets the first screenshot from given zone (if zone is none, takes the whole active window) new_screen = ImageProcessor()._get_screen(False, zone) # saves the time starting point (when the first screenshot was taken) start_time = datetime.datetime.now() #In a loop compares the screenshot with previously taken from screen. #If images are NOT identical returns True, else continue until timeout occurs - throws error and returns False. while True: utils.sleep(step) old_screen = new_screen new_screen = ImageProcessor()._get_screen(False, zone) result = ImageProcessor().find_image_result( new_screen, old_screen, threshold) if not result.found: return True if (datetime.datetime.now() - start_time).seconds > timeout: break ErrorHandler().report_warning( "Timeout exceeded while waiting for animation starts") return False
def is_complex_template_on_screen(self, templates_set, threshold=0.99, cache=False, zone=None): """Checks if the elements of the given templates set are on screen. Returns *bool*: True if all the parts from the set are found. Templates should be passed as a list. Examples: | ${complex_template} = Is Complex Template On Screen | templates | threshold=0.99 | zone=None """ on_screen = True screen = ImageProcessor(self.error_handler, self.output_dir).get_screenshot() for image in templates_set: on_screen &= ImageProcessor(self.error_handler, self.output_dir)._is_image_on_screen( image, threshold, cache, zone, screen) if not on_screen: break return on_screen
def get_number_with_text_from_zone(self, zone=None, lang=None, resize_percent=0, resize=0, contrast=0, background=None, invert=False, brightness=0, change_mode=True, tessdata_dir=None, cache=False): """Returns only number from zone with text and number. For arguments details check `Get Number From Zone` Examples: | Get Number With Text From Zone | zone=[x y w h] | lang=eng | resize_percent=15 | resize=0.95 | contrast=0.1 | background=${None} | invert=${False} | brightness=0 | change_mode=${True} """ self.window_area = GUIProcess().get_window_area() if background is not None: img = ImageProcessor( self.error_handler, self.screenshot_folder).get_image_to_recognize_with_background( zone, resize_percent, contrast, background, invert, brightness, cache) else: img = ImageProcessor( self.error_handler, self.screenshot_folder).get_image_to_recognize( zone, resize_percent, contrast, invert, brightness, change_mode, self.window_area, cache) if int(resize) > 0: resize = int(resize) img = resize_img(img, resize) config = "" if lang: mydir = os.path.abspath(os.path.dirname(__file__)) resdir = os.path.abspath(os.path.join(os.sep, mydir, tessdata_dir)) config += ("--tessdata-dir %s -l %s " % (resdir, lang)).replace( "\\", "//") config += "-psm 6" txt = image_to_string(img, config=config) num = re.compile('[0-9|.0-9]+') num = num.findall(txt) num = ''.join(num) try: return float(num) except ValueError as e: msg = "Error while parsing text:" + str(e) ErrorHandler(self.screenshot_folder).report_error( msg, ("img", img)) raise
def get_float_number_from_zone(self, zone=None, lang=None, resize_percent=0, resize=0, contrast=0, background=None, invert=False, brightness=0, change_mode=True, tessdata_dir=None, cache=False): """Returns the *float*. For details check `Get Number From Zone` Examples: | Get Float Number From Zone | zone=[x y w h] | lang=eng | resize_percent=15 | resize=0.95 | contrast=0.1 | background=${None} | invert=${False} | brightness=0 | change_mode=${True} """ self.window_area = GUIProcess().get_window_area() if background is not None: img = ImageProcessor( self.error_handler, self.screenshot_folder).get_image_to_recognize_with_background( zone, resize_percent, contrast, background, brightness, invert, cache) else: img = ImageProcessor( self.error_handler, self.screenshot_folder).get_image_to_recognize( zone, resize_percent, contrast, invert, brightness, change_mode, self.window_area, cache) if int(resize) > 0: resize = int(resize) img = resize_img(img, resize) config = "" if lang: mydir = os.path.abspath(os.path.dirname(__file__)) resdir = os.path.abspath(os.path.join(os.sep, mydir, tessdata_dir)) config += ("--tessdata-dir %s -l %s " % (resdir, lang)).replace( "\\", "//") config += "-psm 8 -c tessedit_char_whitelist=.,0123456789" txt = image_to_string(img, config=config) txt = float(txt) try: return txt except ValueError as e: msg = "Error while parsing number: " + str(e) ErrorHandler(self.screenshot_folder).report_error( msg, ("img", img)) raise
def is_any_part_of_complex_template_on_screen(self, threshold=None, cache=False, zone=None): screen = ImageProcessor().get_screenshot() if not cache else None for image in self.images: if ImageProcessor().is_image_on_screen( image[0], _get_threshold(image, threshold), cache, zone, screen): return True return False
def __init__(self, screenshot_folder=None): self.screenshot_folder = screenshot_folder self.error_handler = ErrorHandler(self.screenshot_folder) Template.__init__(self, self.error_handler, self.screenshot_folder) ComplexTemplate.__init__(self, self.error_handler, self.screenshot_folder) GUIProcess.__init__(self) Zone.__init__(self, self.screenshot_folder, self.error_handler) ImageProcessor.__init__(self, self.error_handler, self.screenshot_folder) Animations.__init__(self, self.error_handler, self.screenshot_folder)
def is_animating(self, zone=None, threshold=0.99, step=0.5): # convert passed args to float values threshold = float(threshold) step = float(step) #gets the first screenshot than waits for 'step' time and gets the second screenshot old_screen = ImageProcessor()._get_screen(False, zone) utils.sleep(step) new_screen = ImageProcessor()._get_screen(False, zone) #compares the first and the second screenshots, returns result. If screenshots are identical - True. return not ImageProcessor().find_image_result(new_screen, old_screen, threshold).found
def get_state_info(config, default_threshold): # config can contain simple filename # or filename and threshold (threshold there is prior to default) #checks the passed config entry (line from yaml) and loads image if isinstance(config, (str, bytes)): return (ImageProcessor().load_image(config), default_threshold) elif isinstance(config, dict): filename = config[IMAGE_LABEL] threshold = config[ THRESHOLD_LABEL] if THRESHOLD_LABEL in config else default_threshold return (ImageProcessor().load_image(filename), threshold) else: raise AssertionError("Lists are not supported in state block")
def is_complex_template_on_screen(self, threshold=None, cache=False, zone=None): on_screen = True screen = ImageProcessor().get_screenshot() if not cache else None for image in self.images: on_screen &= ImageProcessor().is_image_on_screen( image[0], _get_threshold(image, threshold), cache, zone, screen) if not on_screen: break return on_screen
def get_number_from_zone(self, lang=None, resize_before=0, resize_after=0, contrast=0, cache=False, contour=False, invert=False, brightness=0, change_mode=True): img = ImageProcessor().get_image_to_recognize(self.get_area(), cache, resize_before, contrast, contour, invert, brightness, change_mode) resize = int(resize_after) if int(resize) > 0: resize = int(resize) img = resize_after_screenshot_modification(img, resize) config = "" config += "-psm 8 -c tessedit_char_whitelist=0123456789" try: return int(image_to_string(img, config=config)) except ValueError as e: msg = "Error while parsing number: " + str(e) ErrorHandler().report_error(msg, ("img", img)) raise
def find_on_screen(self, screen=None): found = ImageProcessor().find_multiple_images(self.image_info[0], self.image_info[1], screen=screen) if self.expected is not None: if self.expected != len(found): images = [("button", self.image_info[0])] if len(found) > 0: images.append(("screen", found[0].screen)) elif screen is not None: images.append(("screen", screen)) msg = "Found {} buttons, but only {} expected".format( len(found), self.expected) ErrorHandler().report_error(msg, *images) raise RuntimeError(msg) ErrorHandler().report_info("Found {} buttons {} on screen".format( len(found), self.name)) #sort in horizontal or vertical direction sorted_found = sorted(found, key=lambda res: res.x if self.direction == 0 else res.y) #save pos for every button self.buttons = [entry.get_pos() for entry in sorted_found]
def get_number_with_text_from_zone(self, lang=None, resize_before=0, resize_after=0, contrast=0, cache=False, contour=False, invert=False, brightness=0, change_mode=True): img = ImageProcessor().get_image_to_recognize(self.get_area(), cache, resize_before, contrast, contour, invert, brightness, change_mode) resize = int(resize_after) if resize > 0: img = resize_after_screenshot_modification(img, resize) config = "" config += "-psm 6" txt = image_to_string(img, config=config) num = re.compile('[0-9]') num = num.findall(txt) num = ''.join(num) num = int(num) try: return num except ValueError as e: msg = "Error while parsing text:" + str(e) ErrorHandler().report_error(msg, ("img", img)) raise
def resize_after_screenshot_modification(img, resize): """"Stretches the initial image PIL.IMAGE filters: ANTIALIAS NEAREST BICUBIC BIL INEAR """ """ Loads an image from ``filename``, resizes it by ``resize_percent`` and returns the resized image. The resized image will is saved by default ``resized.png``. Percentage is relative to original size, for example 5 is half, 10 equal and 20 double size. Percentage must be greater than zero. """ if resize > 0: origFile = ImageProcessor()._make_up_filename() img.save(origFile) origresize = Image.open(origFile) old_width, old_height = origresize.size new_width = int(old_width * resize) new_height = int(old_height * resize) img = img.resize((new_width, new_height), Image.ANTIALIAS) img.save('resized.png') return img
def is_button_active(self, index): if STATE_NORMAL in self.states: state_info = self.states[STATE_NORMAL] result = ImageProcessor().is_image_on_screen( state_info[0], state_info[1]) if result: return True if STATE_HIGHLIGHTED in self.states: state_info = self.states[STATE_HIGHLIGHTED] result = ImageProcessor().is_image_on_screen( state_info[0], state_info[1]) if result: return True return False
def wait_for_dynamic_button(self, index, timeout, threshold): """Any state""" images_to_find = [] for state in sorted(self.states.values()): images_to_find.append((state[0], state[1], True)) return ImageProcessor().wait_for_one_of(images_to_find, timeout)
def wait_for_template_to_hide(self, index=-1, threshold=None, timeout=15, zone=None): image = self._get_template_image(index) return ImageProcessor().wait_for_image_to_hide( image[0], _get_threshold(image, threshold), timeout, zone)
def wait_for_complex_template(self, threshold=None, timeout=15, zone=None): waiting_result = False for image in self.images: waiting_result = ImageProcessor().wait_for_image( image[0], _get_threshold(image, threshold), timeout, zone) if not waiting_result: return waiting_result return waiting_result
def get_templates_count(self, index=-1, threshold=None, cache=False, zone=None): image = self._get_template_image(index) return ImageProcessor().get_images_count( image[0], _get_threshold(image, threshold), cache, zone)
def template_should_not_be_on_screen(self, index=-1, threshold=None, cache=False, zone=None): image = self._get_template_image(index) return ImageProcessor().image_should_not_be_on_screen( image[0], _get_threshold(image, threshold), cache, zone)
def save_zone_content_to_output(self, zone): '''FOR DEBUG: saves the content (screenshot) of the provided zone. Pass zone. Image is saved in the output folder in launcher ''' screen_img = ImageProcessor(self.error_handler, self.screenshot_folder)._screenshot(zone) ErrorHandler(self.screenshot_folder).save_pictures([(screen_img, "zone")])
def wait_for_activate_and_press(self, index, timeout, step=0.5): states_to_wait = [] for state in STATES_ACTIVE: if state in self.states: states_to_wait.append( (self.states[state][0], self.states[state][1], True)) assert bool( states_to_wait ), "Button has not active states in list of possible states" result = ImageProcessor().wait_for_one_of(states_to_wait, timeout) if not result.found: raise RuntimeError( "Button was not found on screen or is in unknown state") self.click_center(result.get_pos(), 1)
def get_image_from_zone(self, zone, image_name): """Returns image from given zone and saves it to 'output' under the provided image_name or default""" screen = self.get_area(zone) scr = ImageProcessor()._get_screenshot(screen) if image_name is not None: screen_name = image_name else: screen_name = 'image_from_zone' try: output = BuiltIn().get_variable_value('${OUTPUT_DIR}') except RobotNotRunningError: LOGGER.info('Could not get output dir, using default - output') output = os.path.join(os.getcwd(), 'output') scr.save(output + '\\' + screen_name + '.png') return output + '\\' + screen_name + '.png'
def get_templates_count(self, image, threshold=0.99, cache=False, zone=None): """Counts the number of the given template occurences on screen (in the given zone). Returns an _integer_. Examples: | ${my_template} = Get Templates Count | template | threshold=0.99 | zone=None """ screen = ImageProcessor(self.error_handler, self.output_dir)._get_screen(cache, zone) return ImageProcessor(self.error_handler, self.output_dir)._get_images_count( image, threshold, cache, zone, screen)
def find_image(self, image, threshold=0.99, cache=False, zone=None): #gets zone value zone = self.zones[zone].get_area() if zone is not None else None #searches for image on screen result = ImageProcessor().find_image(image, threshold, cache, zone) if result.found: return True else: return False
def get_float_number_from_zone(self, cache=False, zone=None, lang=None, resize_percent=0, resize=0, contrast=0, invert=False, brightness=0, change_mode=True, tessdata_dir=None): """Returns the *float*. For details check `Get Number From Zone` Examples: | Get Float Number From Zone | zone=[x y w h] | lang=eng | resize_percent=15 | resize=0.95 | contrast=0.1 | background=${None} | invert=${False} | brightness=0 | change_mode=${True} """ self.window_area = GUIProcess().get_window_area() img = ImageProcessor(self.error_handler, self.screenshot_folder).get_image_to_recognize( zone, cache, resize_percent, contrast, invert, brightness, change_mode, self.window_area) if int(resize) > 0: resize = int(resize) origFile = ImageProcessor( self.error_handler, self.screenshot_folder)._make_up_filename() img.save(origFile) origresize = Image.open(origFile) width, height = origresize.size width_resize = width * int(resize) / width + width height_resize = height * int(resize) / height + height img = origresize.resize( (int(round(width_resize)), int(round(height_resize))), Image.ANTIALIAS) img.save( os.path.join(self.screenshot_folder, 'ImageLibrary_Zone_Image.png')) config = "" if lang: mydir = os.path.abspath(os.path.dirname(__file__)) resdir = os.path.abspath(os.path.join(os.sep, mydir, tessdata_dir)) config += ("--tessdata-dir %s -l %s " % (resdir, lang)).replace( "\\", "//") config += "-psm 8 -c tessedit_char_whitelist=.,0123456789" txt = image_to_string(img, config=config) txt = float(txt) try: return txt except ValueError as e: msg = "Error while parsing number: " + str(e) ErrorHandler(self.screenshot_folder).report_error( msg, ("img", img)) raise
def get_button_state(self, index): screen = ImageProcessor()._get_screenshot() images_to_find = self.states.values() coords = ImageProcessor().find_one_of(images_to_find, screen=screen) if coords is not None: for state_name, state_info in self.states: if state_info[0] is coords.image: return state_name #no one state is found images = [] for state_name, state_info in sorted(self.states.items()): images.append((state_name, state_info[0])) images.append(("screen", screen)) msg = "Button {} not found on screen in all possible states".format( self.name) ErrorHandler().report_error(msg, *images) raise RuntimeError(msg)