summaryrefslogtreecommitdiff
path: root/tools
diff options
context:
space:
mode:
authorCyrille Bagard <nocbos@gmail.com>2025-06-01 13:27:50 (GMT)
committerCyrille Bagard <nocbos@gmail.com>2025-06-01 13:27:50 (GMT)
commit07333983ff99b22994a79c8a7cbf4fad0b80158f (patch)
treeea38a27b114212b662f31feadfe2db1347a53148 /tools
parentbde358e3a0b8333fd796c89a3be998d8ad5b1826 (diff)
Build a static image for the About dialog box background.gtk4
Diffstat (limited to 'tools')
-rw-r--r--tools/about/build.py120
-rw-r--r--tools/about/courier-10-pitch-bold_EQ97V.zipbin0 -> 21114 bytes
-rw-r--r--tools/about/courier10point.zipbin0 -> 61784 bytes
-rwxr-xr-xtools/about/gen.sh52
-rw-r--r--tools/about/logo.pngbin0 -> 633982 bytes
-rw-r--r--tools/about/noise.pngbin0 -> 136944 bytes
-rw-r--r--tools/about/ttf.py111
7 files changed, 283 insertions, 0 deletions
diff --git a/tools/about/build.py b/tools/about/build.py
new file mode 100644
index 0000000..2267492
--- /dev/null
+++ b/tools/about/build.py
@@ -0,0 +1,120 @@
+
+# apt install libcairo2-dev pkg-config python3-dev
+# pip install pycairo
+
+import cairo
+import math
+import sys
+
+from enum import IntEnum
+
+from ttf import create_cairo_font_face_for_file
+
+
+WIDTH = 350
+HEIGHT = 430
+
+
+def deg2rad(degrees):
+ return degrees * (math.pi / 180)
+
+
+class TextAlignment(IntEnum):
+ LEFT = 1
+ CENTER = 2
+ RIGHT = 3
+
+
+def draw_text(ctx, text, pos, fsize, noise, theta = 0.0, align = TextAlignment.CENTER):
+ """Dessine un texte en respectant des propriétées."""
+
+ ctx.save()
+
+ ctx.set_font_size(fsize)
+
+ fascent, fdescent, fheight, fxadvance, fyadvance = ctx.font_extents()
+ x_off, y_off, tw, th = ctx.text_extents(text)[:4]
+
+ if align == TextAlignment.LEFT:
+ nx = 0
+ elif align == TextAlignment.RIGHT:
+ nx = -tw
+ else:
+ nx = -tw / 2.0
+
+ ny = fheight / 2
+
+ ctx.translate(pos[0], pos[1])
+ ctx.rotate(theta)
+ ctx.translate(nx, ny)
+ ctx.move_to(0,0)
+
+ ctx.text_path(text)
+ ctx.set_source_surface(noise, 0, -fheight)
+ ctx.fill_preserve()
+ ctx.set_source_rgb(1.0, 1.0, 1.0)
+ ctx.set_line_width(1)
+ ctx.stroke()
+
+ ctx.restore()
+
+
+if __name__ == '__main__':
+ """Point d'entrée du script."""
+
+ surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, WIDTH, HEIGHT)
+
+ cr = cairo.Context(surface)
+
+ face = create_cairo_font_face_for_file('cour10p_b.ttf')
+ cr.set_font_face(face)
+
+ noise = cairo.ImageSurface.create_from_png('noise.png')
+
+ # Type d'édition
+
+ if len(sys.argv) > 2:
+
+ draw_text(cr, sys.argv[2], [ 300, 25 ], 32, noise,
+ theta = deg2rad(270), align = TextAlignment.RIGHT)
+
+ cr.set_source_rgb(0, 0, 0)
+ cr.paint_with_alpha(0.4)
+
+ # Numéro de version
+
+ draw_text(cr, sys.argv[1], [ 149, 10 + 259 + 14 + 42 + 2 ], 23, noise, align=TextAlignment.LEFT)
+
+ cr.set_source_rgb(0, 0, 0)
+ cr.paint_with_alpha(0.5)
+
+ # Logo
+
+ logo = cairo.ImageSurface.create_from_png('logo.png')
+
+ scale_y = 259 / logo.get_height()
+
+ cr.save()
+
+ cr.translate((WIDTH - (logo.get_width() * scale_y)) / 2, 12)
+
+ cr.scale(scale_y, scale_y)
+
+ cr.set_source_surface(logo, 0, 0)
+ cr.paint()
+
+ cr.restore()
+
+ # Titre
+
+ draw_text(cr, 'Chrysalide', [ WIDTH / 2, 10 + 259 + 14 + 4 ], 42, noise)
+
+ # cr.rectangle(265, 30, 10, 10)
+ # cr.set_source_rgb(1, 0, 0)
+ # cr.fill()
+
+ # cr.rectangle(265, 255, 10, 10)
+ # cr.set_source_rgb(1, 0, 0)
+ # cr.fill()
+
+ surface.write_to_png('bg.png')
diff --git a/tools/about/courier-10-pitch-bold_EQ97V.zip b/tools/about/courier-10-pitch-bold_EQ97V.zip
new file mode 100644
index 0000000..0585fe6
--- /dev/null
+++ b/tools/about/courier-10-pitch-bold_EQ97V.zip
Binary files differ
diff --git a/tools/about/courier10point.zip b/tools/about/courier10point.zip
new file mode 100644
index 0000000..82cd0de
--- /dev/null
+++ b/tools/about/courier10point.zip
Binary files differ
diff --git a/tools/about/gen.sh b/tools/about/gen.sh
new file mode 100755
index 0000000..c22ec59
--- /dev/null
+++ b/tools/about/gen.sh
@@ -0,0 +1,52 @@
+#!/bin/bash
+
+
+# Cf. https://stackoverflow.com/questions/59895/how-do-i-get-the-directory-where-a-bash-script-is-located-from-within-the-script/246128#246128
+SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )
+
+pushd $SCRIPT_DIR > /dev/null
+
+
+# Obtention de la police Courier-10-Pitch-Bold
+# --------------------------------------------
+
+# https://fontsgeek.com/fonts/Courier-10-Pitch-Bold
+# https://fontsgeek.com/terms-and-conditions
+
+# => courier-10-pitch-bold_EQ97V.zip
+
+
+# Courier 10 Pitch font missing after upgrade to 17.04?
+# https://askubuntu.com/questions/914352/courier-10-pitch-font-missing-after-upgrade-to-17-04
+
+# https://groups.google.com/g/trelby/c/CGkpcMBXW9U
+# -> http://www.trelby.org/files/release/font/courier10point.zip
+# --> https://web.archive.org/web/20140326080337/http://www.trelby.org/files/release/font/courier10point.zip
+
+# https://news.ycombinator.com/item?id=18802628
+# -> https://www.trelby.org/assets/courier10point.zip
+
+# => courier10point.zip
+
+if [ ! -f cour10p_b.ttf ]; then
+
+ unzip -p courier10point.zip courier10point/cour10p_b.ttf > cour10p_b.ttf
+
+fi
+
+
+# Construction de l'image de fond
+#--------------------------------
+
+if [ $# -lt 1 -o $# -gt 2 ]; then
+
+ echo "Usage: $0 <version> <edition>"
+ exit 123
+
+fi
+
+python3 ./build.py $*
+
+cp bg.png ../../src/data/images/about-bg.png
+
+popd > /dev/null
diff --git a/tools/about/logo.png b/tools/about/logo.png
new file mode 100644
index 0000000..9bf9969
--- /dev/null
+++ b/tools/about/logo.png
Binary files differ
diff --git a/tools/about/noise.png b/tools/about/noise.png
new file mode 100644
index 0000000..b5d6b91
--- /dev/null
+++ b/tools/about/noise.png
Binary files differ
diff --git a/tools/about/ttf.py b/tools/about/ttf.py
new file mode 100644
index 0000000..eb6c027
--- /dev/null
+++ b/tools/about/ttf.py
@@ -0,0 +1,111 @@
+
+# Source: https://www.cairographics.org/cookbook/freetypepython/
+
+import ctypes as ct
+import cairo
+
+_initialized = False
+def create_cairo_font_face_for_file (filename, faceindex=0, loadoptions=0):
+ "given the name of a font file, and optional faceindex to pass to FT_New_Face" \
+ " and loadoptions to pass to cairo_ft_font_face_create_for_ft_face, creates" \
+ " a cairo.FontFace object that may be used to render text with that font."
+ global _initialized
+ global _freetype_so
+ global _cairo_so
+ global _ft_lib
+ global _ft_destroy_key
+ global _surface
+
+ CAIRO_STATUS_SUCCESS = 0
+ FT_Err_Ok = 0
+
+ if not _initialized:
+ # find shared objects
+ _freetype_so = ct.CDLL("libfreetype.so.6")
+ _cairo_so = ct.CDLL("libcairo.so.2")
+ _cairo_so.cairo_ft_font_face_create_for_ft_face.restype = ct.c_void_p
+ _cairo_so.cairo_ft_font_face_create_for_ft_face.argtypes = [ ct.c_void_p, ct.c_int ]
+ _cairo_so.cairo_font_face_get_user_data.restype = ct.c_void_p
+ _cairo_so.cairo_font_face_get_user_data.argtypes = (ct.c_void_p, ct.c_void_p)
+ _cairo_so.cairo_font_face_set_user_data.argtypes = (ct.c_void_p, ct.c_void_p, ct.c_void_p, ct.c_void_p)
+ _cairo_so.cairo_set_font_face.argtypes = [ ct.c_void_p, ct.c_void_p ]
+ _cairo_so.cairo_font_face_status.argtypes = [ ct.c_void_p ]
+ _cairo_so.cairo_font_face_destroy.argtypes = (ct.c_void_p,)
+ _cairo_so.cairo_status.argtypes = [ ct.c_void_p ]
+ # initialize freetype
+ _ft_lib = ct.c_void_p()
+ status = _freetype_so.FT_Init_FreeType(ct.byref(_ft_lib))
+ if status != FT_Err_Ok :
+ raise RuntimeError("Error %d initializing FreeType library." % status)
+ #end if
+
+ class PycairoContext(ct.Structure):
+ _fields_ = \
+ [
+ ("PyObject_HEAD", ct.c_byte * object.__basicsize__),
+ ("ctx", ct.c_void_p),
+ ("base", ct.c_void_p),
+ ]
+ #end PycairoContext
+
+ _surface = cairo.ImageSurface(cairo.FORMAT_A8, 0, 0)
+ _ft_destroy_key = ct.c_int() # dummy address
+ _initialized = True
+ #end if
+
+ ft_face = ct.c_void_p()
+ cr_face = None
+ try :
+ # load FreeType face
+ status = _freetype_so.FT_New_Face(_ft_lib, filename.encode("utf-8"), faceindex, ct.byref(ft_face))
+ if status != FT_Err_Ok :
+ raise RuntimeError("Error %d creating FreeType font face for %s" % (status, filename))
+ #end if
+
+ # create Cairo font face for freetype face
+ cr_face = _cairo_so.cairo_ft_font_face_create_for_ft_face(ft_face, loadoptions)
+ status = _cairo_so.cairo_font_face_status(cr_face)
+ if status != CAIRO_STATUS_SUCCESS :
+ raise RuntimeError("Error %d creating cairo font face for %s" % (status, filename))
+ #end if
+ # Problem: Cairo doesn't know to call FT_Done_Face when its font_face object is
+ # destroyed, so we have to do that for it, by attaching a cleanup callback to
+ # the font_face. This only needs to be done once for each font face, while
+ # cairo_ft_font_face_create_for_ft_face will return the same font_face if called
+ # twice with the same FT Face.
+ # The following check for whether the cleanup has been attached or not is
+ # actually unnecessary in our situation, because each call to FT_New_Face
+ # will return a new FT Face, but we include it here to show how to handle the
+ # general case.
+ if _cairo_so.cairo_font_face_get_user_data(cr_face, ct.byref(_ft_destroy_key)) == None :
+ status = _cairo_so.cairo_font_face_set_user_data \
+ (
+ cr_face,
+ ct.byref(_ft_destroy_key),
+ ft_face,
+ _freetype_so.FT_Done_Face
+ )
+ if status != CAIRO_STATUS_SUCCESS :
+ raise RuntimeError("Error %d doing user_data dance for %s" % (status, filename))
+ #end if
+ ft_face = None # Cairo has stolen my reference
+ #end if
+
+ # set Cairo font face into Cairo context
+ cairo_ctx = cairo.Context(_surface)
+ cairo_t = PycairoContext.from_address(id(cairo_ctx)).ctx
+ _cairo_so.cairo_set_font_face(cairo_t, cr_face)
+ status = _cairo_so.cairo_font_face_status(cairo_t)
+ if status != CAIRO_STATUS_SUCCESS :
+ raise RuntimeError("Error %d creating cairo font face for %s" % (status, filename))
+ #end if
+
+ finally :
+ _cairo_so.cairo_font_face_destroy(cr_face)
+ _freetype_so.FT_Done_Face(ft_face)
+ #end try
+
+ # get back Cairo font face as a Python object
+ face = cairo_ctx.get_font_face()
+ return face
+#end create_cairo_font_face_for_file