Skip to content

Instantly share code, notes, and snippets.

@tagoh

tagoh/mix.c Secret

Last active March 11, 2024 10:52
Show Gist options
  • Save tagoh/447f847f3f651695482508bb40980a33 to your computer and use it in GitHub Desktop.
Save tagoh/447f847f3f651695482508bb40980a33 to your computer and use it in GitHub Desktop.
/*
* gcc -o mix mix.c `pkg-config --cflags --libs freetype2 x11 xrender`
*/
#include <stdio.h>
#include <stdlib.h>
#include <X11/Xlib.h>
#include <X11/extensions/Xrender.h>
#include <ft2build.h>
#include FT_FREETYPE_H
FT_Library library;
GlyphSet
load_glyphset(Display *dpy, char *filename, int size, char *s, int *x)
{
FT_Face face;
XRenderPictFormat *fmt = XRenderFindStandardFormat(dpy, PictStandardA8);
GlyphSet gs = XRenderCreateGlyphSet(dpy, fmt);
int i, idx;
if (FT_New_Face(library, filename, 0, &face) != FT_Err_Ok) {
printf("Unable to open %s\n", filename);
return 0;
}
if (FT_Set_Char_Size(face, 0, size /* pt */ << 6 /* 1/64 */,
96 /* dpi */, 96) != FT_Err_Ok) {
printf("Unable to set size for Noto Sans\n");
gs = 0;
goto bail;
}
for (i = 0; s[i] != 0; i++) {
FT_Bitmap *bitmap;
XGlyphInfo ginfo;
Glyph gid;
int stride;
char *tmp;
int y;
idx = FT_Get_Char_Index(face, s[i]);
if (FT_Load_Glyph(face, idx, FT_LOAD_RENDER) != FT_Err_Ok) {
printf("Unable to load a glyph %02X\n", s[i]);
continue;
}
bitmap = &face->glyph->bitmap;
ginfo.x = -face->glyph->bitmap_left;
ginfo.y = face->glyph->bitmap_left;
ginfo.width = bitmap->width;
ginfo.height = bitmap->rows;
ginfo.xOff = face->glyph->advance.x >> 6;
ginfo.yOff = face->glyph->advance.y >> 6;
gid = s[i];
stride = (ginfo.width + 3) & ~3;
tmp = malloc(stride * ginfo.height);
for (y = 0; y < ginfo.height; y++)
memcpy(tmp+y*stride, bitmap->buffer+y*ginfo.width, ginfo.width);
XRenderAddGlyphs(dpy, gs, &gid, &ginfo, 1, tmp, stride*ginfo.height);
XSync(dpy, 0);
*x += face->glyph->advance.x >> 6;
free(tmp);
}
bail:
FT_Done_Face(face);
return gs;
}
int
main(void)
{
FT_Error fterr;
FT_Face facea, facen;
char a[] = "ABCD";
char n[] = "0123";
Display *dpy;
int screen, xa = 0, xn = 0;
Window root, w;
XRenderPictureAttributes pict_attr, pict_attr_pen;
XRenderPictFormat *fmt, *fmt_pen;
Picture pict, fg_pen;
XRenderColor color = { .red = 0, .green = 0, .blue = 0, .alpha = 0xffff};
XRenderColor bg_color = { .red = 0xffff, .green = 0xffff, .blue = 0xffff, .alpha = 0xffff};
Pixmap pixmap;
GlyphSet gsa, gsn;
dpy = XOpenDisplay(NULL);
screen = DefaultScreen(dpy);
root = DefaultRootWindow(dpy);
w = XCreateWindow(dpy, root, 0, 0, 640, 480, 0,
DefaultDepth(dpy, screen), InputOutput,
DefaultVisual(dpy, screen), 0, NULL);
pict_attr.poly_edge = PolyEdgeSmooth;
pict_attr.poly_mode = PolyModeImprecise;
fmt = XRenderFindStandardFormat(dpy, PictStandardRGB24);
pict = XRenderCreatePicture(dpy, w, fmt, CPPolyEdge|CPPolyMode, &pict_attr);
XSelectInput(dpy, w, KeyPressMask|KeyReleaseMask|ExposureMask|ButtonPressMask|StructureNotifyMask);
fmt_pen = XRenderFindStandardFormat(dpy, PictStandardARGB32);
pixmap = XCreatePixmap(dpy, root, 1, 1, 32);
pict_attr_pen.repeat = 1;
fg_pen = XRenderCreatePicture(dpy, pixmap, fmt_pen, CPRepeat, &pict_attr_pen);
XRenderFillRectangle(dpy, PictOpOver, fg_pen, &color, 0, 0, 1, 1);
XFreePixmap(dpy, pixmap);
fterr = FT_Init_FreeType(&library);
if (fterr) {
printf("Failed to initialize FreeType\n");
return 1;
}
gsa = load_glyphset(dpy, "/usr/share/fonts/google-noto-vf/NotoSans[wght].ttf", 24, a, &xa);
gsn = load_glyphset(dpy, "/usr/share/fonts/google-noto-vf/NotoSansArabic[wght].ttf", 24, n, &xn);
XMapWindow(dpy, w);
while (1) {
XEvent event;
XNextEvent(dpy, &event);
switch (event.type) {
case Expose:
XRenderFillRectangle(dpy, PictOpOver, pict, &bg_color, 0, 0, 1640, 1640);
XRenderCompositeString8(dpy, PictOpOver,
fg_pen, pict, 0, gsa,
0, 0, 20, 50, a, 4);
XRenderCompositeString8(dpy, PictOpOver,
fg_pen, pict, 0, gsn,
0, 0, 20+xa, 50, n, 4);
break;
case DestroyNotify:
printf("Destroying\n");
return 0;
}
}
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment