有没有办法让 kivy 中的 TextInput 中的文本颜色依赖于背景?

Posted

技术标签:

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

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

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

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

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

再次感谢!

【问题讨论】:

【参考方案1】:

一般算法可能如下:

    查找图像的平均颜色

    寻找互补色或对比色

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

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

    找出图像的主色:
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 颜色。

    寻找互补色/对比色。
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 更新中发生更改,则无法保证它仍然有效。

【讨论】:

谢谢!这是围绕文本输入类的好方法。我会用那个:)

以上是关于有没有办法让 kivy 中的 TextInput 中的文本颜色依赖于背景?的主要内容,如果未能解决你的问题,请参考以下文章

Kivy:Shift+Tab 不适用于 TextInput

Kivy TextInput如何更改hint_text字体大小

TextInput中的kivy ScrollView实现

Python kivy - 如何减少 TextInput 的高度

如何让 kivy Window.softinput_mode = 'below_target' 将 TextInput 框移动到虚拟键盘上方?

将 kivy 的 TextInput 限制为仅 ascii 字符