diff --git a/recipes/recipes_emscripten/freetype-py/emscripten-library-path.patch b/recipes/recipes_emscripten/freetype-py/emscripten-library-path.patch new file mode 100644 index 00000000000..fec7796c48e --- /dev/null +++ b/recipes/recipes_emscripten/freetype-py/emscripten-library-path.patch @@ -0,0 +1,19 @@ +--- freetype/raw.py ++++ freetype/raw.py +@@ -11,5 +11,6 @@ + import os + import platform ++import glob + from ctypes import * + import ctypes.util + +@@ -29,4 +30,9 @@ + else: + library_name = 'libfreetype.so' + ++if system == 'Emscripten': ++ libraries = sorted(glob.glob('/lib/libfreetype.so*')) ++ if libraries: ++ library_name = libraries[0] ++ + filename = os.path.join(os.path.dirname(freetype.__file__), library_name) diff --git a/recipes/recipes_emscripten/freetype-py/recipe.yaml b/recipes/recipes_emscripten/freetype-py/recipe.yaml new file mode 100644 index 00000000000..dcef381e832 --- /dev/null +++ b/recipes/recipes_emscripten/freetype-py/recipe.yaml @@ -0,0 +1,52 @@ +context: + version: "2.5.1" + +package: + name: freetype-py + version: ${{ version }} + +source: +- url: https://files.pythonhosted.org/packages/d0/9c/61ba17f846b922c2d6d101cc886b0e8fb597c109cedfcb39b8c5d2304b54/freetype-py-${{ version }}.zip + sha256: cfe2686a174d0dd3d71a9d8ee9bf6a2c23f5872385cf8ce9f24af83d076e2fbd + patches: + - emscripten-library-path.patch + +build: + number: 0 + script: ${{ PYTHON }} -m pip install . --no-deps ${{ PIP_ARGS }} + +requirements: + build: + - cross-python_${{ target_platform }} + - python + - pip + - setuptools + host: + - python + - pip + - setuptools + - freetype-shared + run: + - python + - freetype-shared + +tests: +- script: pytester + files: + recipe: + - test_freetype_py.py + requirements: + build: + - pytester + run: + - pytester-run + +about: + homepage: https://github.com/rougier/freetype-py + license: BSD-3-Clause + license_file: LICENSE.txt + summary: Freetype Python bindings + +extra: + recipe-maintainers: + - Alex-PLACET diff --git a/recipes/recipes_emscripten/freetype-py/test_freetype_py.py b/recipes/recipes_emscripten/freetype-py/test_freetype_py.py new file mode 100644 index 00000000000..acba7c19c3e --- /dev/null +++ b/recipes/recipes_emscripten/freetype-py/test_freetype_py.py @@ -0,0 +1,95 @@ +import freetype + + +_FONT = """\ +STARTFONT 2.1 +FONT -misc-test-medium-r-normal--8-80-75-75-c-50-iso10646-1 +SIZE 8 75 75 +FONTBOUNDINGBOX 5 6 0 0 +STARTPROPERTIES 2 +FONT_ASCENT 6 +FONT_DESCENT 0 +ENDPROPERTIES +CHARS 2 +STARTCHAR H +ENCODING 72 +SWIDTH 625 0 +DWIDTH 5 0 +BBX 5 6 0 0 +BITMAP +88 +88 +F8 +88 +88 +88 +ENDCHAR +STARTCHAR i +ENCODING 105 +SWIDTH 250 0 +DWIDTH 2 0 +BBX 2 6 0 0 +BITMAP +40 +00 +C0 +40 +40 +E0 +ENDCHAR +ENDFONT +""" + + +def test_render_text_to_bitmap(tmp_path): + font_path = tmp_path / "test.bdf" + font_path.write_text(_FONT) + + face = freetype.Face(str(font_path)) + face.set_pixel_sizes(0, 8) + + rendered = [] + pen_positions = [] + pen_x = 0 + for character in "Hi": + face.load_char(character, freetype.FT_LOAD_RENDER) + bitmap = face.glyph.bitmap + pixels = bytes(bitmap.buffer) + + assert bitmap.width > 0 + assert bitmap.rows > 0 + assert any(pixels) + advance = face.glyph.advance.x >> 6 + rendered.append( + ( + face.glyph.bitmap_left, + bitmap.width, + bitmap.rows, + bitmap.pitch, + pixels, + advance, + ) + ) + pen_positions.append(pen_x) + pen_x += advance + + height = max(item[2] for item in rendered) + canvas_width = max( + pen_x + left + bitmap_width + for pen_x, (left, bitmap_width, *_rest) in zip(pen_positions, rendered) + ) + canvas = bytearray(canvas_width * height) + x = 0 + for left, bitmap_width, bitmap_rows, pitch, pixels, advance in rendered: + for row in range(bitmap_rows): + start = row * abs(pitch) + for column in range(bitmap_width): + destination = x + left + column + source = start + column + if 0 <= destination < canvas_width and source < len(pixels): + canvas[row * canvas_width + destination] = pixels[source] + x += advance + + assert x == pen_x + assert len(canvas) == canvas_width * height + assert sum(canvas) > 0