txoof / epdlib

Python library for creating and writing modular layouts for e-paper screens
GNU General Public License v3.0
16 stars 8 forks source link

Force larger font size? #58

Open VaporwareII opened 1 year ago

VaporwareII commented 1 year ago

I've been playing with longer and shorter text blocks, but the font seems to skew small in expectation of a longer word or sentence. I was trying to create a square with a single character to see how large it would become and it was surprisingly small. The textblock should be 120ish pixels square, and I requested a crazy 300 pt font size with no padding.

IMG-2561

# import from epdlib
from epdlib import Screen
from epdlib import Layout
#from epdlib import Block
from epdlib import constants

import logging
from time import sleep

# obnoxious levels of debugging output that might help you diagnose problems
logging.root.setLevel('DEBUG')

# create screen and layout objects
my_screen = Screen(epd='epd2in13_V3')
my_layout = Layout(resolution=my_screen.resolution)

# define a layout with a single text block
layout = {
             'Troop1': {
                'type': 'TextBlock',    
                'image': None,
                #'max_lines': 1,
                #'maxchar': 1,
                'width': 1/2,
                'height': 1,
                'padding': 0,
                'abs_coordinates': (0, 0),   # X = 0, Y will be calculated
                'relative': False,           # this block is not relative to any other. It has an ABSOLUTE position (0, 0)
                #'hcenter': True,
                #'vcenter': True,
                'font': str(constants.absolute_path/'../fonts/Font.ttc'),             
                'font_size': 300,            # Calculate the font size because none was provided
                #'text_wrap': True,
                'fill': 'White',
                'bkground': 'Black'
            }
}
# assign the layout definition to the layout property of the Layout() object
my_layout.layout = layout

# tell the layout what to put in the 'title' block
my_layout.update_contents({'Troop1': '5'})

# concatenate all the images in the layout into a single large image (PIL.paste for those keeping score)
# and write it to the EPD
my_screen.writeEPD(my_layout.concat())
print('sleeping for 10 seconds')
sleep(10)
my_screen.clearEPD()

%Run helloworld.py
DEBUG:root:configuring waveshare_epd.epd2in13_V3
DEBUG:root:Clear() function has color parameter
DEBUG:root:args_spec: ['self', 'image']
DEBUG:root:epd configuration {'epd': <waveshare_epd.epd2in13_V3.EPD object at 0x7f87c65580>, 'resolution': [250, 122], 'clear_args': {}, 'one_bit_display': True, 'constants': None, 'mode': '1'}
DEBUG:root:rotation=0, resolution=[250, 122]
DEBUG:root:mirror output: False
DEBUG:root:[[----checking default values for layout----]
DEBUG:root:section: [------------Troop1------------]
DEBUG:root:adding "max_lines: 1"
DEBUG:root:adding "maxchar: None"
DEBUG:root:adding "dimensions: None"
DEBUG:root:[[....calculating layouts....]]
INFO:root:section: [............Troop1............]
DEBUG:root:resolution: [250, 122]
DEBUG:root:width: 0.5, height: 1
DEBUG:root:absolute coordinates provided
DEBUG:root:block coordinates: (0, 0)
DEBUG:root:layout config: resolution, [250, 122], force_onebit: False, mode: 1
INFO:root:[[____SETTING SECTION BLOCKS____]]
INFO:root:setting section: [____________Troop1____________]
DEBUG:root:scaling font size
DEBUG:root:x target size reached
DEBUG:root:calculated font size: 34
DEBUG:root:setting block type: TextBlock
DEBUG:root:set bkground: Black
INFO:root:using WaveShare color: Black
DEBUG:root:converting "(0, 0, 0)" to mode: 1
DEBUG:root:using 0
DEBUG:root:checking fill and background color
DEBUG:root:converting "None" to mode: 1
DEBUG:root:using 0
DEBUG:root:border config: {'fill': 0}
DEBUG:root:converting "0" to mode: 1
DEBUG:root:using 0
DEBUG:root:border config: {'fill': 0, 'width': 0}
DEBUG:root:set fill: White
INFO:root:using WaveShare color: White
DEBUG:root:converting "(255, 255, 255)" to mode: 1
DEBUG:root:using 255
DEBUG:root:checking fill and background color
DEBUG:root:block area: (125, 122)
DEBUG:root:padded area: [125, 122]
DEBUG:root:creating Block
DEBUG:root:resetting font to match size 34
DEBUG:root:calculating maximum characters for font ('WenQuanYi Micro Hei', 'Regular') at size 34
DEBUG:root:calculated average character width: 18.665995975855132
DEBUG:root:maximum characters per line: 7
DEBUG:root:formatting string: NONE
DEBUG:root:text size: (93, 34)
DEBUG:root:paste coordinates: (0, 0)
DEBUG:root:formatting string: 5
DEBUG:root:text size: (19, 33)
DEBUG:root:paste coordinates: (0, 0)
DEBUG:root:initing display

I'm wondering if this is related to just using the default font? It could also be something in my environment since I didn't set up a pipenv.

VaporwareII commented 1 year ago

Not directly related to the Font chosen or the pipenv. I tried both of those, unrelated errors.

Looks like it's tied to the LAYOUT_SCALE_FONT_TEXT in the constants.py document. once I change '9QqMm' to a smaller character such as 'i' then I get a full scale (115 pixels of 122, which is close enough)

I understand that is a safety catch to prevent unusual characters from overlapping, but that calculated font_size seems to override the desired declared block font_size and wrecks this smaller dumber block I'm trying for

txoof commented 1 year ago

Hmm. It looks like the font_size parameter is being trounced. I'll have to look into this. I'm a little busy with some other projects right now.

The problem is definitely in the Block.TextBlock class.

If I had to guess without doing any testing, I'd say that the problem is in the font setter. It should check if there's a font size already set and only run the calculation function if it's not.

If you want to give it a go hacking on it and submit a PR, it would be welcome.

VaporwareII commented 1 year ago

I will look up those things and give it a try, I'm already trying to isolate where exactly that value changes.

I had someone local interested in helping me but he wanted a completely virtual enviroment complete with virtual EPD hardware instead of a real HAT and display? but I don't think such a thing exists? like the WS2812 simulations.

txoof commented 1 year ago

The answer is Juypter notebook. Here's an OK introduction to Jupyter: https://youtu.be/SV4VLrd9USQ?si=nUWmmIHpUW6AHinG The video covers Jupyter in Colab, but you'll get the big ideas.

You'll notice a bunch of ipynb files in the epdlib structure.

I just discovered the create_devel_venv.sh script skips a few steps. Until I can get to fixing them, you'll need to do a few things manually first:

  1. in the root of the epdlib directory: pipenv --python 3
  2. pipenv install ipykernel
  3. pip3 install jupyter
  4. create_devel_venv.sh -j

Once you've done that, you can run the ipynb files in a web browser. Start a notebook server: jupyter notebook --ip=YOUR.IP.ADDRESS --no-browser open the link it provides and browse to the file you want to fiddle with.

In jupyter, you can simply output directly into the notebook instead of writing to the EPD. This is significantly faster. You can't simulate the entire output process easily, but you can definitely run a bit of sample code and check to see what is happening along the way.

The notebooks are broken up by class/function so you can run just the portions you want. For example, I left a little bit of sample code in at the bottom of each class for easy testing.

t = TextBlock(area=(800, 180), font='../fonts/Open_Sans/OpenSans-Regular.ttf', font_size=44, max_lines=1,
             padding=10, fill='BLACK', bkground='YELLOW', inverse=False, hcenter=False, vcenter=True, rand=False, mode='L', align='right',
             border_config={'fill': 'BLUE', 'width': 4, 'sides': ['top', 'right']},
             textwrap=False)
t.mode = 'L'
t.text = 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. QqWYZAXEtiam sed nunc et neque lobortis condimentum. Mauris tortor mi, dictum aliquet sapien auctor, facilisis aliquam metus. Mauris lacinia turpis sit amet ex fringilla aliquet.'
# t.text = 'the quick brown fox jumps over the lazy dog. Pack my boxes with a dozen jugs of liquor.'
t.update()
t.image
image
VaporwareII commented 1 year ago

I'm not sure, but I think the problem is because the layout is initialized before the block, and the font setter runs after that calculated font is already pushed into the textblock. I don't see a way to avoid that unless you initialize the Textblock much earlier.

in Layout.py the set_block function calls at line 140

        # scale the selected font face size into the available area/lines
        if values['type'] == 'TextBlock':
            values['font_size'] = self._scale_font(values)    

but I dont understand how a default value of the layout would be pushed into the block, shouldn't it live at the layout level and when the block is initialized the font_size property argument overrides that default?

The layout is created:

DEBUG:root:[[----checking default values for layout----]
DEBUG:root:section: [------------Troop1------------]
DEBUG:root:adding "max_lines: 1"
DEBUG:root:adding "maxchar: None"
DEBUG:root:adding "dimensions: None"
DEBUG:root:[[....calculating layouts....]]
INFO:root:section: [............Troop1............]
DEBUG:root:resolution: [250, 122]
DEBUG:root:width: 0.5, height: 1
DEBUG:root:absolute coordinates provided
DEBUG:root:block coordinates: (0, 0)
DEBUG:root:layout config: resolution, [250, 122], force_onebit: False, mode: 1

the blocks are laid out, and the text block initialized at the end of this snip (creating block), there is no font_size yet so it defaults to the layout font_size?


INFO:root:[[____SETTING SECTION BLOCKS____]]
INFO:root:setting section: [____________Troop1____________]
DEBUG:root:scaling font size
DEBUG:root:x target size reached
DEBUG:root:calculated font size: 34
DEBUG:root:setting block type: TextBlock
DEBUG:root:set bkground: Black
INFO:root:using WaveShare color: Black
DEBUG:root:converting "(0, 0, 0)" to mode: 1
DEBUG:root:using 0
DEBUG:root:checking fill and background color
DEBUG:root:converting "None" to mode: 1
DEBUG:root:using 0
DEBUG:root:border config: {'fill': 0}
DEBUG:root:converting "0" to mode: 1
DEBUG:root:using 0
DEBUG:root:border config: {'fill': 0, 'width': 0}
DEBUG:root:set fill: White
INFO:root:using WaveShare color: White
DEBUG:root:converting "(255, 255, 255)" to mode: 1
DEBUG:root:using 255
DEBUG:root:checking fill and background color
DEBUG:root:block area: (125, 122)
DEBUG:root:padded area: [125, 122]
DEBUG:root:creating Block
DEBUG:root:resetting font to match size 34