def check_web_color_contrast(self, settings): """ Verify that the web primary and secondary color both contrast well on white, as these colors will serve as button backgrounds with white test, as well as text color on white backgrounds. """ primary = flask.request.form.get( Configuration.WEB_PRIMARY_COLOR, Configuration.DEFAULT_WEB_PRIMARY_COLOR) secondary = flask.request.form.get( Configuration.WEB_SECONDARY_COLOR, Configuration.DEFAULT_WEB_SECONDARY_COLOR) def hex_to_rgb(hex): hex = hex.lstrip("#") return tuple(int(hex[i:i + 2], 16) / 255.0 for i in (0, 2, 4)) primary_passes = wcag_contrast_ratio.passes_AA( wcag_contrast_ratio.rgb(hex_to_rgb(primary), hex_to_rgb("#ffffff"))) secondary_passes = wcag_contrast_ratio.passes_AA( wcag_contrast_ratio.rgb(hex_to_rgb(secondary), hex_to_rgb("#ffffff"))) if not (primary_passes and secondary_passes): primary_check_url = ("https://contrast-ratio.com/#%23" + secondary[1:] + "-on-%23" + "#ffffff"[1:]) secondary_check_url = ("https://contrast-ratio.com/#%23" + secondary[1:] + "-on-%23" + "#ffffff"[1:]) return INVALID_CONFIGURATION_OPTION.detailed( _( "The web primary and secondary colors don't have enough contrast to pass the WCAG 2.0 AA guidelines and will be difficult for some patrons to read. Check contrast for primary <a href='%(primary_check_url)s' target='_blank'>here</a> and secondary <a href='%(primary_check_url)s' target='_blank'>here</a>.", primary_check_url=primary_check_url, secondary_check_url=secondary_check_url, ))
def text_color(color): rgb = tuple(int(color[i:i + 2], 16) / 255.0 for i in (0, 2, 4)) white = (1.0, 1.0, 1.0) black = (0.0, 0.0, 0.0) if contrast.rgb(rgb, white) > contrast.rgb(rgb, black): return "FFFFFF" else: return "000000"
def contrast_color(hex_color): rgb_color = colors.hex2color(hex_color) black = (0.0, 0.0, 0.0) black_contrast = contrast.rgb(rgb_color, black) white = (1.0, 1.0, 1.0) white_contrast = contrast.rgb(rgb_color, white) if white_contrast > black_contrast: return "#ffffff" else: return "#000000"
def check_web_color_contrast(self, settings): """Verify that the web background color and web foreground color go together. """ background = flask.request.form.get(Configuration.WEB_BACKGROUND_COLOR, Configuration.DEFAULT_WEB_BACKGROUND_COLOR) foreground = flask.request.form.get(Configuration.WEB_FOREGROUND_COLOR, Configuration.DEFAULT_WEB_FOREGROUND_COLOR) def hex_to_rgb(hex): hex = hex.lstrip("#") return tuple(int(hex[i:i+2], 16)/255.0 for i in (0, 2 ,4)) if not wcag_contrast_ratio.passes_AA(wcag_contrast_ratio.rgb(hex_to_rgb(background), hex_to_rgb(foreground))): contrast_check_url = "https://contrast-ratio.com/#%23" + foreground[1:] + "-on-%23" + background[1:] return INVALID_CONFIGURATION_OPTION.detailed( _("The web background and foreground colors don't have enough contrast to pass the WCAG 2.0 AA guidelines and will be difficult for some patrons to read. Check contrast <a href='%(contrast_check_url)s' target='_blank'>here</a>.", contrast_check_url=contrast_check_url))
def get_style_contrasts(style_cls): return [ ( round( wcag_contrast_ratio.rgb( hex2rgb(style["bgcolor"] or style_cls.background_color), hex2rgb(style["color"] or "#000000") # we default to black because browsers also do ), 1, ), ttype, ) for ttype, style in style_cls.list_styles() if ttype != pygments.token.Whitespace ]
def colorChecker(backgroundColor, textColor): if backgroundColor is None: backgroundColor = "Gray" if textColor is None: textColor = "Black" # convert color name to rgb for contrast check textRGB = ([i / 255 for i in webcolors.name_to_rgb(textColor)]) # convert color name to rgb for contrast check backgroundRGB = ([i / 255 for i in webcolors.name_to_rgb(backgroundColor)]) # check contrast ratio if contrast.passes_AA(contrast.rgb(textRGB, backgroundRGB)): return webcolors.name_to_hex(backgroundColor), webcolors.name_to_hex( textColor) # if failed, set color to default return webcolors.name_to_hex("Gray"), webcolors.name_to_hex("Black")
def black_or_white(color): """give the contrast between white/black and color and give wich of black or white give the best contrast (return black or white)""" # input are number between 0 and 1 black = (1, 1, 1) white = (0, 0, 0) color[:] = color[:] / 255 # calculate the contrast between black and color b_c = contrast.rgb(black, color) # calculate the contrast between white and color w_c = contrast.rgb(black, color) output_color = 'empty' if (b_c > w_c): output_color = 'black' else: output_color = 'white' return (output_color)
def choose_tint_color(dominant_colors, background_color): # The minimum contrast ratio for text and background to meet WCAG AA # is 4.5:1, so discard any dominant colours with a lower contrast. sufficient_contrast_colors = [ col for col in dominant_colors if contrast.rgb(col, background_color) >= 4.5 ] # If none of the dominant colours meet WCAG AA with the background, # try again with black and white -- every colour in the RGB space # has a contrast ratio of 4.5:1 with at least one of these, so we'll # get a tint colour, even if it's not a good one. # # Note: you could modify the dominant colours until one of them # has sufficient contrast, but that's omitted here because it adds # a lot of complexity for a relatively unusual case. if not sufficient_contrast_colors: return choose_tint_color(dominant_colors=dominant_colors + [(0, 0, 0), (1, 1, 1)], background_color=background_color) # Of the colours with sufficient contrast, pick the one with the # closest brightness (in the HSV colour space) to the background # colour. This means we don't get very dark or very light colours, # but more bright, vibrant colours. hsv_background = colorsys.rgb_to_hsv(*background_color) hsv_candidates = { tuple(rgb_col): colorsys.rgb_to_hsv(*rgb_col) for rgb_col in sufficient_contrast_colors } candidates_by_brightness_diff = { rgb_col: abs(hsv_col[2] - hsv_background[2]) for rgb_col, hsv_col in hsv_candidates.items() } rgb_choice, _ = min(candidates_by_brightness_diff.items(), key=lambda t: t[1]) assert rgb_choice in dominant_colors return rgb_choice
def check_web_color_contrast(self, settings): """Verify that the web background color and web foreground color go together. """ background = flask.request.form.get( Configuration.WEB_BACKGROUND_COLOR, Configuration.DEFAULT_WEB_BACKGROUND_COLOR) foreground = flask.request.form.get( Configuration.WEB_FOREGROUND_COLOR, Configuration.DEFAULT_WEB_FOREGROUND_COLOR) def hex_to_rgb(hex): hex = hex.lstrip("#") return tuple(int(hex[i:i + 2], 16) / 255.0 for i in (0, 2, 4)) if not wcag_contrast_ratio.passes_AA( wcag_contrast_ratio.rgb(hex_to_rgb(background), hex_to_rgb(foreground))): contrast_check_url = "https://contrast-ratio.com/#%23" + foreground[ 1:] + "-on-%23" + background[1:] return INVALID_CONFIGURATION_OPTION.detailed( _("The web background and foreground colors don't have enough contrast to pass the WCAG 2.0 AA guidelines and will be difficult for some patrons to read. Check contrast <a href='%(contrast_check_url)s' target='_blank'>here</a>.", contrast_check_url=contrast_check_url))
def plot_map(stations, connections, lines, area, output_path="./output/plot/"): """ Plot all the lines on a Map and save as png-file parameters: stations - all stations in database; connections - all connections in database; lines - the lines that are plotted; area - geographical area of lines; output_path - folder where plot is saved; """ # Create Figure and Axe fig = plt.figure(dpi=600) fig, ax = plt.subplots() plt.axis("off") # Format Options of Holland and others if area == "Holland": land_color = tuple(i / 255. for i in ImageColor.getrgb("#0AE")) marker_size = 10 line_size = 1 else: # if area == "Nationaal": land_color = tuple(i / 255. for i in ImageColor.getrgb("#E06")) marker_size = 5 line_size = .75 # predefine used colors used_colors = [] # Plot Background using geopandas gpd_map(area).plot(ax=ax, color=land_color) # For-loop to get each individual connection between stations for connection in connections: # Create tuples of x and y using coordinates of begin- and end station connect_long = [station.position[0] for station in connection.section] connect_lat = [station.position[1] for station in connection.section] # Plot connection ax.plot(connect_long, connect_lat, linewidth=line_size, color="lightgrey", alpha=0.5, zorder=1) # Create lists of x and y values from the coordinates of all stations station_long = [station.position[0] for station in stations.values()] station_lat = [station.position[1] for station in stations.values()] # Calculate the ratio between the longitude and latitude ratio = aspect_ratio(station_lat) # Create a dictionary of connections that need ofset ofset = ofset_dict(lines) # For-loop to get each single line for line_number in range(len(lines)): # generate random color color = random_color() # generate new color the contrast is high enough no double colors while (rgb(color, land_color) >= 10 and color not in used_colors): color = random_color() # add color to used color used_colors.append(color) # For-loop to get each connection in a line for connection in list(set(lines[line_number].connections)): # Get the adjusted longitude and latitude longitude, latitude = line_coords(connection, ofset, ratio, line_number) # Plot connection ax.plot(longitude, latitude, c=color, linewidth=line_size, zorder=2) # Plot all stations ax.scatter(station_long, station_lat, s=marker_size, marker="o", color="black", zorder=3) # Set aspect using ratio value ax.set_aspect(ratio) # Save plot to png file plt.savefig(f"{output_path}Map-{area}.png", dpi=300, format="png", transparent=True) print(f"Map-{area} is created.")
def get_contrast_ratio(color_1, color_2): return contrast.rgb(color_1, color_2)
def score_contrast(a, b, large, AAA): contrast = cr.rgb(a, b) # Between 1 and 21 return contrast \ + int((AAA and cr.passes_AAA(contrast, large=large))) * 100 \ + int(not AAA and cr.passes_AA(contrast, large=large)) * 100
def get_contrast(color_1, color_2): return contrast.rgb(get_rgb_from_color(color_1), get_rgb_from_color(color_2))
def run(tag_data): """ Modifies the background and foreground color of text content and background to increase the contrast. Parameters: html <list> Dictionaries with HTML snippets as strings and hexadecimal color of the background and foreground Return: <list> List of beautiful soup tags with proper CSS contrast elements and their path """ back = hex_to_rgb(tag_data["colors"]["background"]) fore = hex_to_rgb(tag_data["colors"]["foreground"]) # Text color # True if the background is closer to white than black backLight = is_light(back) # Set initial conditions for the foreground text color cond = { "contrast": not contrast.passes_AA( contrast.rgb([v / RGB_LIMIT for v in back], [v / RGB_LIMIT for v in fore])), "notLightest": max(fore) < RGB_LIMIT or backLight, "notDarkest": all(fore) or not backLight, } # Loop to adjust the foreground colors while all(cond.values()): fore = [ color + (-min(COLOR_STEP, color) if backLight else min( COLOR_STEP, RGB_LIMIT - color)) for color in fore ] cond["contrast"] = not contrast.passes_AA( contrast.rgb([v / RGB_LIMIT for v in back], [v / RGB_LIMIT for v in fore])) cond["notLightest"] = max(fore) < RGB_LIMIT or backLight cond["notDarkest"] = all(fore) or not backLight # Now we adjust the conditions to the background colors cond["notLightest"] = max(back) < RGB_LIMIT or not backLight cond["notDarkest"] = all(back) or backLight # Loop to adjust the background colors while all(cond.values()): back = [ color + (min(COLOR_STEP, RGB_LIMIT - color) if backLight else -min(COLOR_STEP, color)) for color in back ] cond["contrast"] = not contrast.passes_AA( contrast.rgb([v / RGB_LIMIT for v in back], [v / RGB_LIMIT for v in fore])) cond["notLightest"] = max(back) < RGB_LIMIT or not backLight cond["notDarkest"] = all(back) or backLight snippet = tag_data["snippet"] if not snippet.has_attr("style"): snippet["style"] = "" backChanged = rgb_to_hex(back) != tag_data["colors"]["background"] # Remove "background-color" styles if its color was changed if backChanged and "background-color" in snippet["style"]: start = snippet["style"].find("background-color") end = snippet["style"].find(";", start) + 1 snippet["style"] = snippet["style"].replace( snippet["style"][start:end], "") # Remove "background" styles if its color was changed if backChanged and "background" in snippet["style"]: start = snippet["style"].find("background") end = snippet["style"].find(";", start) + 1 snippet["style"] = snippet["style"].replace( snippet["style"][start:end], "") # Remove "color" styles if "color" in snippet["style"]: start = snippet["style"].find("color") end = snippet["style"].find(";", start) + 1 snippet["style"] = snippet["style"].replace( snippet["style"][start:end], "") # Add the new calculated styles snippet["style"] += f"color: #{rgb_to_hex(fore)}; " snippet[ "style"] += f"background: #{rgb_to_hex(back)}; " if backChanged else "" tag_data["snippet"] = snippet return tag_data
def test_hypothesis_contrast(rgb1, rgb2): c1 = contrast.rgb(rgb1, rgb2) c2 = contrast.rgb(rgb2, rgb1) assert 1.0 <= c1 <= 21.0 assert c1 == c2
def test_contrast(rgb1, rgb2, expected): c1 = contrast.rgb(rgb1, rgb2) c2 = contrast.rgb(rgb2, rgb1) assert c1 == expected assert c2 == expected