【问题标题】:Is there a way to make the text color in a TextInput in kivy to be dependent on the background?有没有办法让 kivy 中的 TextInput 中的文本颜色依赖于背景?
【发布时间】:2019-10-01 07:26:36
【问题描述】:

我正在使用 Kivy 的 TextInput,并且我在它后面有一个背景图像。 由于有背景图片 - 上面的文字不清楚(即黑色背景上的黑色文字等)。

有没有办法让文字颜色与它背后的背景颜色相反?

请注意,背景不是纯色图像,而是常规图像。谢谢!

另外,我想有文本大纲,这样它会更易读。尝试了 text_outline 属性,但它是用于标签而不是用于 textInputs,是否有替代方案?

再次感谢!

【问题讨论】:

    标签: python kivy


    【解决方案1】:

    一般算法可能如下:

    1. 查找图像的平均颜色
    2. 寻找互补色或对比色

    3. 将 text_input 的颜色设置为对比色。

    1 和 2 的实现可能相当复杂。 在这个例子中,我将只展示一个粗略的草图。当然,您可以找到或实现更高效的功能。

    1. 找出图像的主色:
    from PIL import Image as I
    
    def average_color(image_fn):
        im = I.open(image_fn)
        im = im.convert('RGB')
        #comment the above if you don't use images with opacity
    
        new_im = im.resize((1, 1))
        pixels = new_im.getpixel((0, 0))
        print pixels
        return pixels
    
    

    这是非常非常粗暴的方式。 我建议图像具有类似正方形的形状。 然后使用 PIL,我简单地将其大小更改为 1 像素 (1x1),然后我得到了该像素的 rgb 颜色。

    1. 寻找互补色/对比色。
    from colorsys import rgb_to_hls as rgb2hls
    from colorsys import hls_to_rgb as hls2rgb
    
    def contrast(rgb):
        h,l,s = rgb2hls(*rgb)
        new_l = 0 if l>=0.5 else 1
        new_rgb = hls2rgb(h, new_l,s)
        return new_rgb
    

    此函数获取一个 RGB 像素,然后将其转换为 HLS,然后将 Lightness 设置为 0 或 1(尽可能远离当前值),然后将其转换回 RGB,并返回此值。所以我们得到白色或黑色的文本颜色,这取决于哪一种与当前图像的对比度更高。

    现在让我们将这些算法添加到 kivy 应用程序中:

    from __future__ import division
    
    from kivy.app import App
    from kivy.lang import Builder
    from kivy.uix.image import Image
    from kivy.core.window import Window
    
    from PIL import Image as I
    
    from colorsys import rgb_to_hls as rgb2hls
    from colorsys import hls_to_rgb as hls2rgb
    
    
    KV = """
    FloatLayout
        MyImage
            id: image
            text_input:text_input
            #source: 'im.png'
    
        MyTextInput
            id: text_input
    
    <MyTextInput@TextInput>
        font_size: 40
        background_normal : ''
        background_active: ''
        background_color: 0,0,0,0
        text: 'this is some text. Drag and drop an image here. '*20
    """
    
    
    
    def average_color(image_fn):
        im = I.open(image_fn)
        im = im.convert('RGB')
        #comment the above if you don't use images with opacity
    
        new_im = im.resize((1, 1))
        pixels = new_im.getpixel((0, 0))
        print pixels
        return pixels
    
    
    
    
    def contrast(rgb):
        h,l,s = rgb2hls(*rgb)
        new_l = 0 if l>=0.5 else 1
        new_rgb = hls2rgb(h, new_l,s)
        return new_rgb
    
    
    class MyImage(Image):
        def on_source(self, inst, fn): 
            aver = [i/255 for i in average_color(fn)]
            contrast_rgba = [i for i in contrast(aver)]+[1]
            self.text_input.foreground_color = contrast_rgba
    
    
    class MyApp(App):
        def build(self):
            self.root = Builder.load_string(KV)
            Window.bind(on_dropfile=self.manage_dropfile)
    
        def is_image(self, fn):
            if fn[-4:] in ['.png', '.jpg', 'jpeg']: return True
            return False
    
        def manage_dropfile(self, window, fn):
            fn = fn.decode('UTF-8')
            if self.is_image(fn):
                self.root.ids.image.source = fn
    
    MyApp().run()
    

    最重要的是我们创建了一个 MyImage 类,其中在 on_source() 方法中(每次更改图像源时)我们获取平均颜色值,然后是对比色,最后我们更改 foreground_color。

    我还实现了图像的拖放。您可以从计算机上的某个文件夹中删除任何 jpg/png 图像文件,文本会自动将其颜色更改为黑色或白色。

    【讨论】:

    • 谢谢好心的陌生人!这个解决方案很棒!
    【解决方案2】:

    不确定如何更改您描述的文本颜色。您的意思是您希望文本颜色根据其背后的内容而变化吗?就像E 的顶部可以是白色的,而E 的底部可以是黑色的?

    但我认为您可以通过子类化将 outline 属性添加到 TextInput

    from kivy.core.text import Label
    from kivy.properties import NumericProperty, ListProperty
    from kivy.uix.textinput import TextInput
    
    class TextInputOutline(TextInput):
        outline_width = NumericProperty(0)
        outline_color = ListProperty((0,0,0))
    
        def _get_line_options(self):
            # Get or create line options, to be used for Label creation
            if self._line_options is None:
                self._line_options = kw = {
                    'font_size': self.font_size,
                    'font_name': self.font_name,
                    'anchor_x': 'left',
                    'anchor_y': 'top',
                    'padding_x': 0,
                    'padding_y': 0,
                    'padding': (0, 0),
                    'outline_width': self.outline_width,
                    'outline_color': self.outline_color}
                self._label_cached = Label(**kw)
            return self._line_options
    

    上面的_get_line_options 方法覆盖TextInput 中的相同方法。唯一的区别是包含outline 属性。使用此TextInputOutline,您可以指定轮廓粗细和颜色,例如:

    TextInputOutline:
        text: 'This is a Test'
        foreground_color: (1, 1, 1, 1)
        outline_color: (0, 0, 0)
        outline_width: 1
    

    请注意,这会覆盖以_ 开头的方法,因此如果TextInput 在将来的Kivy 更新中发生更改,则无法保证它仍然有效。

    【讨论】:

    • 谢谢!这是围绕文本输入类的好方法。我会用那个:)
    猜你喜欢
    • 2020-12-10
    • 2023-02-10
    • 1970-01-01
    • 2019-01-14
    • 1970-01-01
    • 1970-01-01
    • 2020-07-13
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多