~hp/d2tk

5fb9373a33408e3193d9d34f647c359079b57df5 — Hanspeter Portner a month ago 84d2453
Implement in-memory images
M d2tk/base.h => d2tk/base.h +8 -0
@@ 451,6 451,14 @@ d2tk_base_toggle(d2tk_base_t *base, d2tk_id_t id, const d2tk_rect_t *rect,

D2TK_API void
d2tk_base_image(d2tk_base_t *base, ssize_t path_len, const char *path,
	const d2tk_rect_t *rect, d2tk_align_t align) DEPRECATED;

D2TK_API void
d2tk_base_image_path(d2tk_base_t *base, ssize_t path_len, const char *path,
	const d2tk_rect_t *rect, d2tk_align_t align);

D2TK_API void
d2tk_base_image_blob(d2tk_base_t *base, size_t blob_len, const uint8_t *blob,
	const d2tk_rect_t *rect, d2tk_align_t align);

D2TK_API void

M d2tk/core.h => d2tk/core.h +8 -0
@@ 165,9 165,17 @@ d2tk_core_text(d2tk_core_t *core, const d2tk_rect_t *rect, size_t sz,

D2TK_API void
d2tk_core_image(d2tk_core_t *core, const d2tk_rect_t *rect, size_t sz,
	const char *path, d2tk_align_t align) DEPRECATED;

D2TK_API void
d2tk_core_image_path(d2tk_core_t *core, const d2tk_rect_t *rect, size_t sz,
	const char *path, d2tk_align_t align);

D2TK_API void
d2tk_core_image_blob(d2tk_core_t *core, const d2tk_rect_t *rect, size_t sz,
	const uint8_t *blob, d2tk_align_t align);

D2TK_API void
d2tk_core_bitmap(d2tk_core_t *core, const d2tk_rect_t *rect, uint32_t w,
	uint32_t h, uint32_t stride, const uint32_t *argb, uint64_t rev,
	d2tk_align_t align);

M d2tk/d2tk.h => d2tk/d2tk.h +1 -0
@@ 8,5 8,6 @@

#define D2TK_API
#define UNUSED __attribute__((unused))
#define DEPRECATED __attribute__((deprecated))

#endif /* _D2TK_H */

M example/example.c => example/example.c +189 -3
@@ 77,10 77,191 @@ static const char *bar_lbl [BAR_MAX] = {
	[BAR_BROWSER]    = "Browser"
};

static const uint8_t icon_h [] = {
  0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d,
  0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x40,
  0x08, 0x04, 0x00, 0x00, 0x00, 0x00, 0x60, 0xb9, 0x55, 0x00, 0x00, 0x00,
  0x04, 0x67, 0x41, 0x4d, 0x41, 0x00, 0x00, 0xb1, 0x8f, 0x0b, 0xfc, 0x61,
  0x05, 0x00, 0x00, 0x00, 0x02, 0x62, 0x4b, 0x47, 0x44, 0x00, 0x00, 0xaa,
  0x8d, 0x23, 0x32, 0x00, 0x00, 0x00, 0x09, 0x70, 0x48, 0x59, 0x73, 0x00,
  0x00, 0x9c, 0x40, 0x00, 0x00, 0x9c, 0x40, 0x01, 0xc9, 0x25, 0x0e, 0x11,
  0x00, 0x00, 0x00, 0x07, 0x74, 0x49, 0x4d, 0x45, 0x07, 0xe2, 0x0c, 0x1e,
  0x0c, 0x2f, 0x01, 0x8e, 0x6f, 0x2c, 0x1b, 0x00, 0x00, 0x07, 0x4f, 0x49,
  0x44, 0x41, 0x54, 0x68, 0xde, 0xed, 0x99, 0x6d, 0x6c, 0x95, 0x67, 0x19,
  0xc7, 0x7f, 0xe7, 0xb4, 0xe7, 0x70, 0x0e, 0x1d, 0x7d, 0x01, 0xdb, 0x32,
  0xe8, 0x29, 0x65, 0x2b, 0x14, 0xba, 0xb1, 0x31, 0xdd, 0xea, 0x56, 0x22,
  0x6c, 0xbc, 0x14, 0x14, 0x4a, 0x87, 0x8b, 0x26, 0x26, 0x4b, 0x07, 0x23,
  0x1a, 0x67, 0x21, 0xcb, 0x32, 0x35, 0x31, 0x4b, 0x8c, 0x89, 0x1a, 0xdd,
  0xa6, 0x12, 0xdc, 0xfc, 0xe0, 0x07, 0xc5, 0x18, 0xd9, 0x5c, 0xe8, 0xcb,
  0x50, 0x93, 0x6d, 0x45, 0xd1, 0x25, 0xd2, 0x49, 0xd7, 0xc5, 0x41, 0xa1,
  0x2c, 0x4b, 0x53, 0x65, 0x8c, 0xae, 0x94, 0x75, 0x2d, 0x6d, 0x4f, 0x5f,
  0xce, 0x39, 0xed, 0xdf, 0x0f, 0x7d, 0xce, 0x73, 0x9e, 0xe7, 0x9c, 0xe7,
  0x3c, 0x3d, 0x40, 0x09, 0x26, 0x7a, 0xdd, 0x5f, 0xee, 0xdc, 0xaf, 0xff,
  0xfb, 0xba, 0xaf, 0xeb, 0x7e, 0xfe, 0xd7, 0xf5, 0x78, 0xc4, 0xcd, 0x15,
  0xef, 0x4d, 0xde, 0xff, 0xff, 0x00, 0xc8, 0xbe, 0x86, 0x39, 0xb9, 0x94,
  0xb2, 0x84, 0x42, 0xf2, 0x09, 0xe2, 0x07, 0x22, 0x8c, 0x33, 0xc8, 0xc7,
  0xf4, 0x72, 0x9e, 0x91, 0x1b, 0x0b, 0xa0, 0x8c, 0x4a, 0xca, 0x29, 0x23,
  0x44, 0x31, 0x0b, 0xc9, 0x23, 0x80, 0x0f, 0x88, 0x32, 0xce, 0x30, 0x03,
  0xf4, 0x73, 0x81, 0x7f, 0xd1, 0x4d, 0x17, 0xe7, 0xe7, 0x1e, 0x40, 0x90,
  0x4a, 0xee, 0xe4, 0x3e, 0xaa, 0xb8, 0x83, 0xf9, 0x2e, 0xe3, 0xc6, 0x38,
  0x43, 0x3b, 0x1d, 0x74, 0xd2, 0xc5, 0x44, 0x26, 0x0b, 0x7b, 0x32, 0x70,
  0xc3, 0x00, 0x2b, 0xa8, 0x62, 0x27, 0x9b, 0x5d, 0xb7, 0xb6, 0xc3, 0x68,
  0xe5, 0x8f, 0xb4, 0xd3, 0x9d, 0x01, 0x08, 0xb9, 0x17, 0xaf, 0x8a, 0xb5,
  0x4b, 0x47, 0x15, 0x53, 0xaa, 0x4c, 0x2a, 0xac, 0x51, 0x8d, 0x2a, 0xac,
  0x49, 0x87, 0xde, 0xa8, 0x5e, 0xd5, 0xc3, 0x2a, 0x92, 0xd7, 0x7d, 0x07,
  0x77, 0x0d, 0xf8, 0x29, 0xe7, 0x71, 0x1e, 0xe3, 0x53, 0x96, 0xb6, 0x18,
  0x13, 0x8c, 0x33, 0xc9, 0x30, 0x7d, 0x0c, 0x32, 0x09, 0x04, 0xc8, 0x67,
  0x31, 0x79, 0xcc, 0x23, 0x40, 0xc0, 0x76, 0xa9, 0x97, 0x39, 0xc4, 0x21,
  0x7a, 0x88, 0x5c, 0xdb, 0x15, 0x64, 0xb3, 0x89, 0xa7, 0xd8, 0x48, 0x36,
  0x1e, 0x43, 0x59, 0x51, 0x22, 0xbc, 0xcf, 0xdf, 0x79, 0x8b, 0x53, 0x5c,
  0x24, 0x46, 0x7c, 0xb2, 0x87, 0x6c, 0x4a, 0xb8, 0x9b, 0x07, 0x58, 0xc7,
  0x4a, 0xfc, 0xf8, 0x2c, 0x33, 0x8e, 0x73, 0x80, 0xe3, 0xc4, 0xae, 0xfe,
  0x0a, 0xb2, 0xb4, 0x5b, 0xef, 0x58, 0x54, 0x1f, 0xd3, 0xa0, 0x7e, 0xa7,
  0x1d, 0x0a, 0x29, 0x57, 0x01, 0x65, 0x39, 0x8c, 0x0f, 0x28, 0x57, 0x21,
  0xd5, 0xea, 0xb0, 0x06, 0x6d, 0xf3, 0x3a, 0x54, 0xef, 0x30, 0xde, 0x28,
  0xe9, 0xb7, 0xdf, 0xaf, 0x33, 0x96, 0x65, 0x46, 0xf4, 0x8a, 0x36, 0xab,
  0x44, 0x81, 0x59, 0x6c, 0x06, 0x05, 0x14, 0x52, 0x8d, 0x8e, 0x28, 0x6c,
  0x81, 0xd0, 0xa9, 0x86, 0x74, 0x10, 0x9c, 0x17, 0xc9, 0xd6, 0x1e, 0x9d,
  0xd1, 0x94, 0xb9, 0xc4, 0x59, 0x3d, 0xa1, 0x95, 0xf2, 0xcd, 0xba, 0x79,
  0xbc, 0xf8, 0x54, 0xa1, 0x06, 0x75, 0x99, 0xf3, 0xa7, 0xd4, 0xa9, 0x7a,
  0x65, 0x67, 0x0a, 0xc0, 0xaf, 0xad, 0x16, 0xe5, 0x4f, 0xea, 0x0d, 0xed,
  0x50, 0x5e, 0xc6, 0x9b, 0xc7, 0x4b, 0xbe, 0x6a, 0xd5, 0x6a, 0xfa, 0x47,
  0x4c, 0x6f, 0x6b, 0x8b, 0xfc, 0x99, 0x00, 0xf0, 0xaa, 0x52, 0xaf, 0x9b,
  0xdb, 0x87, 0x75, 0x44, 0xeb, 0xe5, 0xb1, 0xf4, 0x17, 0xe8, 0x2e, 0x2d,
  0xcd, 0x08, 0x82, 0x47, 0xeb, 0xd5, 0xa8, 0x31, 0x13, 0xc2, 0x6b, 0x5a,
  0x95, 0xea, 0x94, 0xa9, 0xd3, 0x8a, 0xf4, 0xbc, 0x22, 0xe6, 0xe9, 0x8f,
  0xe8, 0x7e, 0x5b, 0x6f, 0x89, 0xbe, 0xa5, 0x26, 0xfd, 0x44, 0x55, 0x19,
  0xea, 0xe1, 0x01, 0x35, 0x99, 0x5a, 0x98, 0xd4, 0xb3, 0x2a, 0x9a, 0x0d,
  0x40, 0x40, 0xbb, 0x74, 0x59, 0xd3, 0xc6, 0x94, 0xd7, 0xb5, 0xde, 0xd6,
  0x7b, 0x9b, 0xbe, 0xaf, 0x8f, 0x24, 0x4d, 0xa8, 0x51, 0x9f, 0x73, 0xbe,
  0xd3, 0x94, 0xb2, 0x41, 0xad, 0xc6, 0x6a, 0xd3, 0xea, 0x57, 0x5d, 0xb2,
  0x19, 0x27, 0x0f, 0x5f, 0xa3, 0xa3, 0x16, 0xd3, 0xdb, 0x61, 0x51, 0x7e,
  0x96, 0x56, 0xeb, 0x80, 0x86, 0x4c, 0x85, 0xfe, 0x45, 0x1b, 0x33, 0xf0,
  0x09, 0xe4, 0x51, 0xad, 0xc5, 0x1c, 0x9b, 0x75, 0x87, 0x1b, 0x80, 0xa0,
  0xf6, 0x2a, 0x6a, 0x3a, 0xde, 0x13, 0x16, 0xd3, 0xf3, 0xa8, 0x54, 0x2f,
  0x99, 0xf7, 0x39, 0x63, 0xd9, 0x27, 0xb5, 0x55, 0x39, 0x19, 0x99, 0xe3,
  0x3e, 0xd3, 0x29, 0x23, 0xda, 0x63, 0x87, 0x6d, 0x1f, 0xfa, 0x19, 0xf3,
  0xfc, 0x31, 0xfd, 0x5e, 0x2b, 0x2d, 0x3d, 0xf3, 0xf5, 0x88, 0x06, 0x92,
  0x5e, 0xfb, 0x29, 0xbd, 0xa7, 0x2f, 0x2a, 0xd7, 0x66, 0xa2, 0xce, 0xa5,
  0x42, 0x8d, 0xa6, 0x59, 0xb7, 0xe8, 0x9e, 0xf4, 0x00, 0x76, 0x1b, 0x48,
  0xa7, 0x35, 0xa8, 0xcd, 0x36, 0xbf, 0xf7, 0x6a, 0x85, 0xde, 0xb4, 0x69,
  0x60, 0x06, 0xe6, 0x79, 0xed, 0x55, 0xc1, 0xac, 0x00, 0x7c, 0xaa, 0xd1,
  0x90, 0x61, 0x59, 0xa3, 0xaa, 0xb7, 0xf6, 0x65, 0x7d, 0x2f, 0xf1, 0x2a,
  0x97, 0xf1, 0x25, 0xaa, 0x01, 0x88, 0xd2, 0xc2, 0x2b, 0x0c, 0xd9, 0x5e,
  0xec, 0x11, 0xda, 0x28, 0x25, 0x84, 0xdf, 0xd2, 0xea, 0x65, 0x01, 0x9f,
  0x45, 0xbc, 0x4f, 0xd8, 0xf5, 0x93, 0x3b, 0x4d, 0x84, 0x32, 0x2a, 0xc8,
  0x02, 0xfc, 0x7c, 0xc8, 0x59, 0xae, 0x38, 0x7d, 0x0b, 0xbe, 0xa0, 0x76,
  0xe3, 0x64, 0xc3, 0xda, 0xe1, 0x60, 0x60, 0x5e, 0xad, 0xd0, 0xaf, 0x4d,
  0x33, 0x4c, 0xc8, 0x25, 0xfd, 0x4c, 0xcb, 0x67, 0xd1, 0x41, 0x50, 0x75,
  0x1a, 0x31, 0xc6, 0xff, 0x43, 0xdb, 0x9c, 0xaf, 0x60, 0xbf, 0x71, 0x01,
  0x51, 0x75, 0x28, 0x94, 0x66, 0xa1, 0x72, 0x3d, 0xa7, 0xbe, 0x14, 0x08,
  0x1f, 0xeb, 0x97, 0xc9, 0xd6, 0x9d, 0x52, 0x4a, 0xf5, 0x4f, 0xc3, 0xc0,
  0x47, 0xb4, 0x2f, 0xd1, 0x9e, 0x60, 0xc5, 0xb9, 0x2c, 0x37, 0x18, 0xcf,
  0x04, 0x27, 0x2c, 0x2a, 0xb2, 0x4b, 0x37, 0xbf, 0xe0, 0x05, 0x7a, 0x92,
  0x5a, 0x17, 0xf1, 0x65, 0xbe, 0xc3, 0xfd, 0xae, 0xd7, 0x30, 0x44, 0x9b,
  0xc1, 0x8f, 0x6e, 0xa1, 0x8c, 0x5b, 0x12, 0xb7, 0x18, 0x97, 0x65, 0x84,
  0x8c, 0xda, 0x38, 0x6d, 0x2e, 0x14, 0xe2, 0x3c, 0xbf, 0xe2, 0x45, 0xce,
  0x25, 0xb5, 0xe6, 0xb3, 0x8b, 0x6f, 0xf3, 0x90, 0x0b, 0x80, 0x28, 0x27,
  0x4c, 0x82, 0x56, 0xca, 0xb2, 0x78, 0x73, 0x82, 0xbf, 0xdc, 0x4a, 0xb1,
  0x51, 0x9b, 0xe4, 0x34, 0x51, 0x97, 0xa5, 0xfa, 0xf8, 0x2d, 0x61, 0xbe,
  0xce, 0x3d, 0xb6, 0xd6, 0xf9, 0x6c, 0x27, 0x87, 0x20, 0x7f, 0x4e, 0x03,
  0x3e, 0xc2, 0x29, 0x26, 0x8d, 0x7a, 0x31, 0x4b, 0x38, 0x9b, 0x0c, 0xa0,
  0x90, 0x85, 0x46, 0x6d, 0x98, 0x5e, 0xa6, 0x5c, 0xd5, 0x39, 0xc0, 0x61,
  0x86, 0x78, 0x9a, 0x7b, 0x6d, 0x81, 0x8d, 0x9f, 0x2d, 0xe4, 0xe1, 0xe7,
  0x98, 0xa3, 0x4f, 0x4c, 0x71, 0xd1, 0x8c, 0x1a, 0x16, 0x26, 0x48, 0x5e,
  0x62, 0x81, 0x02, 0xf2, 0x0c, 0xa4, 0x7d, 0xae, 0xe7, 0x9f, 0x91, 0x30,
  0x47, 0xf9, 0x2e, 0x27, 0xcd, 0x33, 0xcd, 0x88, 0x87, 0x2a, 0x7e, 0xc0,
  0x76, 0x0a, 0x0c, 0x4a, 0x96, 0xac, 0x83, 0xf8, 0xca, 0x79, 0x14, 0xa4,
  0x02, 0x08, 0x10, 0x00, 0x20, 0xc6, 0x27, 0x64, 0x12, 0x32, 0x4f, 0x72,
  0x9c, 0x27, 0x69, 0x23, 0x6c, 0x1b, 0xed, 0xa1, 0x92, 0x9f, 0xb2, 0x8b,
  0x5c, 0x87, 0x19, 0xe2, 0x13, 0x83, 0x1b, 0x06, 0x08, 0xa6, 0x02, 0xf0,
  0xe3, 0x03, 0x60, 0x9a, 0xf1, 0x0c, 0xb6, 0x07, 0x88, 0xf2, 0x2e, 0x4f,
  0x72, 0x2a, 0x49, 0x5f, 0x1e, 0x96, 0xf2, 0x43, 0xd6, 0xda, 0x1e, 0xac,
  0xb8, 0x8c, 0x19, 0x57, 0xeb, 0x4b, 0xf4, 0xde, 0xf4, 0xe0, 0x34, 0x01,
  0x20, 0x62, 0x9c, 0xc4, 0x9b, 0x71, 0xfc, 0xe3, 0x63, 0x2d, 0x07, 0xb9,
  0xdb, 0xd0, 0x5c, 0x5c, 0xc4, 0x45, 0x9e, 0xe1, 0x5d, 0x47, 0x5f, 0x98,
  0x4f, 0x96, 0xa1, 0x3b, 0xb3, 0x37, 0x01, 0x60, 0xc2, 0xf0, 0xd2, 0xec,
  0x34, 0x26, 0x94, 0x2c, 0xf3, 0xd8, 0xc8, 0x41, 0xaa, 0xc9, 0xb1, 0x8d,
  0x16, 0x5d, 0x3c, 0x4d, 0x0b, 0xc3, 0x0e, 0x33, 0x3c, 0x2c, 0x34, 0xbc,
  0x6e, 0x22, 0x71, 0xcd, 0x09, 0x37, 0x1c, 0xe4, 0x0a, 0x25, 0x80, 0x9f,
  0x5b, 0x93, 0xce, 0xe4, 0x24, 0x39, 0x6c, 0x4f, 0x71, 0x43, 0x10, 0xed,
  0xfc, 0x38, 0x8d, 0x1b, 0x82, 0x9f, 0xc5, 0xc6, 0xca, 0x57, 0x18, 0x4c,
  0x05, 0x70, 0x99, 0x01, 0xa3, 0x96, 0xcb, 0x52, 0x46, 0x5d, 0x5f, 0x82,
  0x45, 0x3c, 0x92, 0xf2, 0x10, 0x41, 0x84, 0xbf, 0x71, 0x30, 0xed, 0x43,
  0x94, 0xc5, 0x52, 0x16, 0x18, 0xf5, 0x01, 0x2e, 0xa7, 0x02, 0xe8, 0xa5,
  0xdf, 0x44, 0x7a, 0x17, 0x3d, 0x2e, 0x00, 0x16, 0xf3, 0x15, 0xbe, 0xca,
  0xea, 0xa4, 0xd6, 0x31, 0xde, 0xe0, 0x05, 0xfe, 0x9a, 0x76, 0x96, 0x9f,
  0xb5, 0xcc, 0x33, 0xea, 0x97, 0xe8, 0x8d, 0x37, 0x27, 0x54, 0x78, 0x9e,
  0x0b, 0x46, 0x2d, 0x48, 0xb5, 0xa3, 0x13, 0xcd, 0xc8, 0x32, 0xf6, 0xb2,
  0x2f, 0x65, 0xfb, 0x21, 0x5a, 0x78, 0xce, 0x65, 0x7b, 0xf0, 0xb3, 0xce,
  0x78, 0x69, 0xe0, 0x02, 0x1f, 0xa4, 0x6a, 0x60, 0x84, 0x1e, 0xc2, 0xe4,
  0x00, 0x01, 0xd6, 0x91, 0xe7, 0x68, 0x46, 0x50, 0xce, 0xd7, 0xa8, 0x37,
  0xbf, 0x1a, 0x71, 0x19, 0xa0, 0x89, 0x9f, 0xc7, 0x5f, 0xf7, 0x34, 0x92,
  0x47, 0xb5, 0x01, 0x20, 0xcc, 0xbf, 0x19, 0x35, 0xdb, 0x2d, 0x5f, 0xec,
  0xcf, 0xeb, 0xa4, 0x49, 0x48, 0x6b, 0x6f, 0x20, 0x21, 0x79, 0x4b, 0x5b,
  0x9d, 0x09, 0x49, 0x99, 0x5e, 0x34, 0x43, 0x88, 0xc3, 0x29, 0x94, 0xc4,
  0xa7, 0xd5, 0x6a, 0x32, 0x17, 0x49, 0x10, 0xd3, 0x8f, 0xf4, 0x8c, 0x8a,
  0x67, 0x65, 0x85, 0x21, 0xbd, 0x6c, 0x06, 0x28, 0x07, 0x55, 0x9a, 0x8e,
  0x94, 0x3e, 0x66, 0x21, 0xa5, 0x35, 0x49, 0xa4, 0x74, 0xe5, 0x75, 0x90,
  0x52, 0xbf, 0xb6, 0xa5, 0x23, 0xa5, 0xf6, 0x81, 0x9f, 0xd6, 0xab, 0xe6,
  0xd2, 0x47, 0xe6, 0x90, 0x96, 0xaf, 0x52, 0x8b, 0x49, 0xcb, 0x9b, 0xdd,
  0x68, 0x79, 0x40, 0x8f, 0x9b, 0x81, 0xc9, 0xa8, 0x1a, 0x94, 0x6f, 0xf6,
  0x5c, 0x4f, 0x60, 0x52, 0x60, 0xb2, 0x4d, 0x29, 0xa2, 0xdd, 0x6e, 0x81,
  0x09, 0xba, 0xd3, 0xd4, 0x81, 0xd4, 0xa5, 0xda, 0x39, 0x08, 0xcd, 0xbc,
  0xaa, 0xd3, 0x7b, 0xe6, 0x9a, 0x4d, 0xee, 0xa1, 0x19, 0x0a, 0xe8, 0x61,
  0xf5, 0x9b, 0xc1, 0x69, 0xab, 0x36, 0xd8, 0x7a, 0xaf, 0x25, 0x38, 0x7d,
  0x50, 0xc7, 0x8c, 0xd5, 0xa6, 0xd5, 0xa7, 0x9d, 0x9a, 0xe7, 0x0e, 0x00,
  0x15, 0xe9, 0x59, 0x4b, 0x40, 0xdd, 0xa4, 0x6a, 0x5b, 0x6f, 0x89, 0xbe,
  0xa9, 0x46, 0x3d, 0x9f, 0x71, 0x78, 0x5e, 0xad, 0x26, 0x4b, 0xb0, 0xff,
  0x23, 0x15, 0x26, 0x8f, 0x70, 0x52, 0xd9, 0x2a, 0xbd, 0x66, 0x49, 0x50,
  0x34, 0x69, 0x43, 0x4a, 0x82, 0x62, 0x49, 0x46, 0x9b, 0x7b, 0xf5, 0xa0,
  0x9a, 0x4d, 0xbb, 0x89, 0xea, 0x4f, 0xaa, 0xc8, 0x24, 0x41, 0x81, 0xfc,
  0xaa, 0x51, 0x87, 0x25, 0x45, 0xd3, 0xaa, 0x5a, 0x8b, 0x39, 0x66, 0x5a,
  0x0a, 0x54, 0xa7, 0x63, 0xe6, 0xe9, 0x63, 0x6a, 0xd7, 0x26, 0xa7, 0x2c,
  0x93, 0xf3, 0xe4, 0x6c, 0xd5, 0xab, 0xd3, 0x92, 0xa4, 0xea, 0x52, 0x83,
  0x2a, 0xae, 0x22, 0x49, 0xe5, 0xd7, 0x2a, 0xed, 0xb7, 0x98, 0xde, 0x94,
  0x4e, 0xeb, 0xd1, 0xcc, 0x93, 0x54, 0x33, 0x36, 0xdf, 0xa0, 0x4e, 0x4b,
  0x9a, 0x2e, 0xac, 0x46, 0xd5, 0x28, 0xa4, 0xe0, 0xac, 0x9b, 0x07, 0x15,
  0xd2, 0x36, 0x35, 0xdb, 0xd2, 0x74, 0xa7, 0xf5, 0x8d, 0xab, 0x4b, 0xd3,
  0xcd, 0x40, 0xa8, 0x57, 0x87, 0xf9, 0x2a, 0x48, 0x31, 0x0d, 0xe9, 0x25,
  0xd5, 0xa9, 0x54, 0xb9, 0x0a, 0x3a, 0x26, 0x2a, 0x83, 0xca, 0x53, 0xa9,
  0xea, 0xf4, 0xb2, 0x86, 0x2c, 0xd0, 0xa3, 0x6a, 0xd7, 0xa3, 0xe9, 0x13,
  0x95, 0xee, 0xa9, 0xda, 0x87, 0x78, 0x8a, 0x4d, 0xb6, 0xc4, 0x6b, 0x84,
  0x6e, 0x4e, 0xd0, 0xc6, 0x29, 0x3e, 0x24, 0x4a, 0x22, 0x55, 0xeb, 0xa3,
  0x84, 0xb5, 0xac, 0xa3, 0x9a, 0xdb, 0x93, 0x52, 0xb5, 0xc7, 0x38, 0xc0,
  0x9b, 0xe9, 0x53, 0xb5, 0xb3, 0x25, 0xab, 0x6f, 0x63, 0x0f, 0x7b, 0x28,
  0xb4, 0xb4, 0xc5, 0x98, 0x60, 0xc2, 0x48, 0x56, 0x0f, 0x31, 0x0e, 0x04,
  0x29, 0xa0, 0x98, 0x5c, 0x87, 0x64, 0xf5, 0x25, 0x0e, 0xf1, 0x1b, 0x7a,
  0x5c, 0x03, 0x9d, 0x59, 0x5d, 0xa9, 0x48, 0x75, 0x6a, 0x36, 0xad, 0xd9,
  0x2a, 0x11, 0x8d, 0x69, 0x54, 0xa3, 0x1a, 0x4b, 0xd3, 0xdb, 0xa4, 0x9d,
  0x2a, 0xbc, 0xbe, 0x74, 0xfd, 0x8c, 0x04, 0xb8, 0x9d, 0x2a, 0x76, 0xb2,
  0x85, 0x9c, 0xd9, 0x07, 0x1b, 0x94, 0xa3, 0x95, 0x3f, 0xf0, 0x36, 0xdd,
  0x49, 0xa1, 0xdb, 0x55, 0x5f, 0x81, 0x15, 0xc4, 0x6a, 0xd6, 0x70, 0x2f,
  0xf7, 0xb1, 0xc6, 0x15, 0xc6, 0x28, 0x67, 0x68, 0xe7, 0x1d, 0x3a, 0x39,
  0x37, 0x77, 0xbf, 0x6c, 0x12, 0x52, 0x4a, 0x25, 0xe5, 0x2c, 0x27, 0x44,
  0x11, 0x8b, 0x2c, 0x3f, 0xad, 0x26, 0xb8, 0xc2, 0x00, 0x97, 0x8c, 0x9f,
  0x56, 0xe7, 0x12, 0x8c, 0x6f, 0xae, 0x01, 0xcc, 0xc8, 0x02, 0x87, 0xdf,
  0x76, 0x43, 0xf4, 0xd3, 0xcb, 0x07, 0x16, 0xae, 0x77, 0x03, 0x01, 0xcc,
  0xa9, 0xfc, 0x17, 0x05, 0xa7, 0xff, 0xab, 0x00, 0xfe, 0x03, 0x2f, 0xc9,
  0x2a, 0x23, 0x69, 0xf3, 0x98, 0x66, 0x00, 0x00, 0x00, 0x25, 0x74, 0x45,
  0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x63, 0x72, 0x65, 0x61, 0x74,
  0x65, 0x00, 0x32, 0x30, 0x31, 0x38, 0x2d, 0x31, 0x32, 0x2d, 0x33, 0x30,
  0x54, 0x31, 0x31, 0x3a, 0x34, 0x37, 0x3a, 0x30, 0x31, 0x2b, 0x30, 0x31,
  0x3a, 0x30, 0x30, 0x8d, 0x24, 0x23, 0x25, 0x00, 0x00, 0x00, 0x25, 0x74,
  0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x6d, 0x6f, 0x64, 0x69,
  0x66, 0x79, 0x00, 0x32, 0x30, 0x31, 0x38, 0x2d, 0x31, 0x32, 0x2d, 0x33,
  0x30, 0x54, 0x31, 0x31, 0x3a, 0x34, 0x37, 0x3a, 0x30, 0x31, 0x2b, 0x30,
  0x31, 0x3a, 0x30, 0x30, 0xfc, 0x79, 0x9b, 0x99, 0x00, 0x00, 0x00, 0x19,
  0x74, 0x45, 0x58, 0x74, 0x53, 0x6f, 0x66, 0x74, 0x77, 0x61, 0x72, 0x65,
  0x00, 0x77, 0x77, 0x77, 0x2e, 0x69, 0x6e, 0x6b, 0x73, 0x63, 0x61, 0x70,
  0x65, 0x2e, 0x6f, 0x72, 0x67, 0x9b, 0xee, 0x3c, 0x1a, 0x00, 0x00, 0x00,
  0x00, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
};

static inline void
_render_c_mix(d2tk_base_t *base, const d2tk_rect_t *rect)
{
#define N 15
#define N 16
#define M 24
	static val_t value [N*M];



@@ 205,11 386,16 @@ _render_c_mix(d2tk_base_t *base, const d2tk_rect_t *rect)
			} break;
			case 12:
			{
				d2tk_base_image(base, -1, "libre-gui-folder.png", bnd,
				d2tk_base_image_path(base, -1, "libre-gui-folder.png", bnd,
					D2TK_ALIGN_CENTERED);
			} break;
			case 13:
			{
				d2tk_base_image_blob(base, sizeof(icon_h), icon_h, bnd,
					D2TK_ALIGN_CENTERED);
			} break;
			case 14:
			{
				static const uint32_t argb [4] = {
					0xffffcf00, 0x7f7f6700,
					0x7f7f6700, 0x00000000


@@ 219,7 405,7 @@ _render_c_mix(d2tk_base_t *base, const d2tk_rect_t *rect)
				d2tk_base_bitmap(base, 2, 2, 2*sizeof(uint32_t), argb, rev, bnd,
					D2TK_ALIGN_CENTERED);
			} break;
			case 14:
			case 15:
			{
				char lbl [32];
				const size_t lbl_len = snprintf(lbl, sizeof(lbl), "%03X", k);

M meson_options.txt => meson_options.txt +1 -1
@@ 51,4 51,4 @@ option('use-vterm',
	value : 'disabled',
	yield : true)

option('version', type : 'string', value : '0.9.93')
option('version', type : 'string', value : '0.9.95')

M src/backend_cairo.c => src/backend_cairo.c +42 -31
@@ 720,54 720,65 @@ d2tk_cairo_process(void *data, d2tk_core_t *core, const d2tk_com_t *com,
		{
			const d2tk_body_image_t *body = &com->body->image;

			const uint64_t hash = d2tk_hash(body->path, body->len);
			const uint8_t *data = body->blob ? body->ptr : (const uint8_t *)body->path;
			const uint64_t hash = d2tk_hash(data, body->len);
			uintptr_t *sprite = d2tk_core_get_sprite(core, hash, SPRITE_TYPE_SURF);
			assert(sprite);

			if(!*sprite)
			{
				char *img_path = _absolute_path(backend, body->path);
				assert(img_path);
				int W, H, N;
				uint8_t *pixels = NULL;

				struct stat st;
				if(stat(img_path, &st) == 0)
				if(body->blob)
				{
					int W, H, N;
					uint8_t *pixels = NULL;

					stbi_set_unpremultiply_on_load(1);
					stbi_convert_iphone_png_to_rgb(1);
					pixels = stbi_load(img_path, &W, &H, &N, 4);
					pixels = stbi_load_from_memory(body->ptr, body->len,
						&W, &H, &N, 4);
				}
				else
				{
					char *img_path = _absolute_path(backend, body->path);
					assert(img_path);

					if(pixels)
					struct stat st;
					if(stat(img_path, &st) == 0)
					{
						// bitswap and premultiply pixel data
						for(unsigned i = 0; i < W*H*sizeof(uint32_t); i += sizeof(uint32_t))
						{
							// get alpha channel
							const uint8_t a = pixels[i+3];

							// premultiply with alpha channel
							const uint8_t r = ( (uint16_t)pixels[i+0] * a ) >> 8;
							const uint8_t g = ( (uint16_t)pixels[i+1] * a ) >> 8;
							const uint8_t b = ( (uint16_t)pixels[i+2] * a ) >> 8;
						stbi_set_unpremultiply_on_load(1);
						stbi_convert_iphone_png_to_rgb(1);
						pixels = stbi_load(img_path, &W, &H, &N, 4);
					}

							// merge and byteswap to correct endianness
							uint32_t *pix = (uint32_t *)&pixels[i];
							*pix = (a << 24) | (r << 16) | (g << 8) | b;
						}
					free(img_path);
				}

						cairo_surface_t *surf = cairo_image_surface_create_for_data(pixels,
							CAIRO_FORMAT_ARGB32, W, H, W*sizeof(uint32_t));
				if(pixels)
				{
					// bitswap and premultiply pixel data
					for(unsigned i = 0; i < W*H*sizeof(uint32_t); i += sizeof(uint32_t))
					{
						// get alpha channel
						const uint8_t a = pixels[i+3];

						const cairo_user_data_key_t key = { 0 };
						cairo_surface_set_user_data(surf, &key, pixels, _d2tk_cairo_img_free);
						// premultiply with alpha channel
						const uint8_t r = ( (uint16_t)pixels[i+0] * a ) >> 8;
						const uint8_t g = ( (uint16_t)pixels[i+1] * a ) >> 8;
						const uint8_t b = ( (uint16_t)pixels[i+2] * a ) >> 8;

						*sprite = (uintptr_t)surf;
						// merge and byteswap to correct endianness
						uint32_t *pix = (uint32_t *)&pixels[i];
						*pix = (a << 24) | (r << 16) | (g << 8) | b;
					}
				}

				free(img_path);
					cairo_surface_t *surf = cairo_image_surface_create_for_data(pixels,
						CAIRO_FORMAT_ARGB32, W, H, W*sizeof(uint32_t));

					const cairo_user_data_key_t key = { 0 };
					cairo_surface_set_user_data(surf, &key, pixels, _d2tk_cairo_img_free);

					*sprite = (uintptr_t)surf;
				}
			}

			cairo_surface_t *surf = (cairo_surface_t *)*sprite;

M src/backend_nanovg.c => src/backend_nanovg.c +17 -8
@@ 732,22 732,31 @@ d2tk_nanovg_process(void *data, d2tk_core_t *core, const d2tk_com_t *com,
		{
			const d2tk_body_image_t *body = &com->body->image;

			const uint64_t hash = d2tk_hash(body->path, body->len);
			const uint8_t *data = body->blob ? body->ptr : (const uint8_t *)body->path;
			const uint64_t hash = d2tk_hash(data, body->len);
			uintptr_t *sprite = d2tk_core_get_sprite(core, hash, SPRITE_TYPE_IMG);
			assert(sprite);

			if(!*sprite)
			{
				char *img_path = _absolute_path(backend, body->path);
				assert(img_path);

				struct stat st;
				if(stat(img_path, &st) == 0)
				if(body->blob)
				{
					*sprite = nvgCreateImage(ctx, img_path, NVG_IMAGE_GENERATE_MIPMAPS);
					*sprite = nvgCreateImageMem(ctx, NVG_IMAGE_GENERATE_MIPMAPS,
						(uint8_t *)body->ptr, body->len);
				}
				else
				{
					char *img_path = _absolute_path(backend, body->path);
					assert(img_path);

					struct stat st;
					if(stat(img_path, &st) == 0)
					{
						*sprite = nvgCreateImage(ctx, img_path, NVG_IMAGE_GENERATE_MIPMAPS);
					}

				free(img_path);
					free(img_path);
				}
			}

			const int img = *sprite;

M src/base_button.c => src/base_button.c +1 -1
@@ 86,7 86,7 @@ _d2tk_base_draw_button(d2tk_core_t *core, ssize_t lbl_len, const char *lbl,

			const size_t ref = d2tk_core_bbox_push(core, true, rect);

			d2tk_core_image(core, &bnd_inner, path_len, path, img_align);
			d2tk_core_image_path(core, &bnd_inner, path_len, path, img_align);

			d2tk_core_bbox_pop(core, ref);
		}

M src/base_image.c => src/base_image.c +36 -1
@@ 11,6 11,13 @@ D2TK_API void
d2tk_base_image(d2tk_base_t *base, ssize_t path_len, const char *path,
	const d2tk_rect_t *rect, d2tk_align_t align)
{
	d2tk_base_image_path(base, path_len, path, rect, align);
}

D2TK_API void
d2tk_base_image_path(d2tk_base_t *base, ssize_t path_len, const char *path,
	const d2tk_rect_t *rect, d2tk_align_t align)
{
	const bool has_img = path_len && path;

	if(has_img && (path_len == -1) ) // zero-terminated string


@@ 33,7 40,35 @@ d2tk_base_image(d2tk_base_t *base, ssize_t path_len, const char *path,
		{
			const size_t ref = d2tk_core_bbox_push(core, true, rect);

			d2tk_core_image(core, rect, path_len, path, align);
			d2tk_core_image_path(core, rect, path_len, path, align);

			d2tk_core_bbox_pop(core, ref);
		}
	}
}

D2TK_API void
d2tk_base_image_blob(d2tk_base_t *base, size_t blob_len, const uint8_t *blob,
	const d2tk_rect_t *rect, d2tk_align_t align)
{
	const bool has_img = blob_len && blob;

	const d2tk_hash_dict_t dict [] = {
		{ rect, sizeof(d2tk_rect_t) },
		{ (blob ? blob : NULL), (blob ? blob_len : 0) },
		{ NULL, 0 }
	};
	const uint64_t hash = d2tk_hash_dict(dict);

	d2tk_core_t *core = base->core;;

	D2TK_CORE_WIDGET(core, hash, widget)
	{
		if(has_img)
		{
			const size_t ref = d2tk_core_bbox_push(core, true, rect);

			d2tk_core_image_blob(core, rect, blob_len, blob, align);

			d2tk_core_bbox_pop(core, ref);
		}

M src/core.c => src/core.c +33 -0
@@ 1060,6 1060,13 @@ D2TK_API void
d2tk_core_image(d2tk_core_t *core, const d2tk_rect_t *rect, size_t sz,
	const char *path, d2tk_align_t align)
{
	d2tk_core_image_path(core, rect, sz, path, align);
}

D2TK_API void
d2tk_core_image_path(d2tk_core_t *core, const d2tk_rect_t *rect, size_t sz,
	const char *path, d2tk_align_t align)
{
	const size_t len = sizeof(d2tk_body_image_t) + sz;
	d2tk_body_t *body = _d2tk_append_request(core, len, D2TK_INSTR_IMAGE);



@@ 1071,6 1078,7 @@ d2tk_core_image(d2tk_core_t *core, const d2tk_rect_t *rect, size_t sz,
		body->image.h = rect->h;
		body->image.align = align;
		body->image.len = sz;
		body->image.blob = false;
		memcpy(body->image.path, path, sz);
		body->image.path[sz] = '\0';



@@ 1082,6 1090,31 @@ d2tk_core_image(d2tk_core_t *core, const d2tk_rect_t *rect, size_t sz,
}

D2TK_API void
d2tk_core_image_blob(d2tk_core_t *core, const d2tk_rect_t *rect, size_t sz,
	const uint8_t *blob, d2tk_align_t align)
{
	const size_t len = sizeof(d2tk_body_image_t);
	d2tk_body_t *body = _d2tk_append_request(core, len, D2TK_INSTR_IMAGE);

	if(body)
	{
		body->image.x = rect->x;
		body->image.y = rect->y;
		body->image.w = rect->w;
		body->image.h = rect->h;
		body->image.align = align;
		body->image.len = sz;
		body->image.blob = true;
		body->image.ptr = blob;

		body->image.x -= core->ref.x;
		body->image.y -= core->ref.y;

		_d2tk_append_advance(core, len);
	}
}

D2TK_API void
d2tk_core_bitmap(d2tk_core_t *core, const d2tk_rect_t *rect, uint32_t w,
	uint32_t h, uint32_t stride, const uint32_t *argb, uint64_t rev,
	d2tk_align_t align)

M src/core_internal.h => src/core_internal.h +5 -1
@@ 162,7 162,11 @@ struct _d2tk_body_image_t {
	d2tk_coord_t h;
	d2tk_align_t align;
	size_t len;
	char path [1]; // at least zero-terminator
	bool blob;
	union {
		const uint8_t *ptr;
		char path [1]; // at least zero-terminator
	};
};

struct _d2tk_body_bitmap_surf_t {

M test/base.c => test/base.c +21 -3
@@ 1783,7 1783,7 @@ _test_toggle(void)
}

static void
_test_image(void)
_test_image_path(void)
{
	d2tk_mock_ctx_t ctx = {
		.check = NULL


@@ 1793,7 1793,24 @@ _test_image(void)
	const d2tk_rect_t rect = D2TK_RECT(0, 0, DIM_W, DIM_H);
	assert(base);

	d2tk_base_image(base, -1, "image.png", &rect, D2TK_ALIGN_CENTERED);
	d2tk_base_image_path(base, -1, "image.png", &rect, D2TK_ALIGN_CENTERED);

	d2tk_base_free(base);
}

static void
_test_image_blob(void)
{
	d2tk_mock_ctx_t ctx = {
		.check = NULL
	};
	const uint8_t image_blob [] = { 0x1, 0x2, 0x3 };

	d2tk_base_t *base = d2tk_base_new(&d2tk_mock_driver_lazy, &ctx);
	const d2tk_rect_t rect = D2TK_RECT(0, 0, DIM_W, DIM_H);
	assert(base);

	d2tk_base_image_blob(base, sizeof(image_blob), image_blob, &rect, D2TK_ALIGN_CENTERED);

	d2tk_base_free(base);
}


@@ 2530,7 2547,8 @@ main(int argc __attribute__((unused)), char **argv __attribute__((unused)))
	_test_button();
	_test_toggle_label();
	_test_toggle();
	_test_image();
	_test_image_path();
	_test_image_blob();
	_test_bitmap();
	_test_custom();
	_test_meter();

M test/core.c => test/core.c +56 -6
@@ 1084,9 1084,10 @@ _test_text(void)
#define IMAGE_H 40
#define IMAGE_PATH "./libre-sugar-skull.png"
#define IMAGE_ALIGN D2TK_ALIGN_LEFT
static const uint8_t image_h [] = { 0x1, 0x2, 0x3 };

static void
_check_image(const d2tk_com_t *com, const d2tk_clip_t *clip)
_check_image_path(const d2tk_com_t *com, const d2tk_clip_t *clip)
{
	assert(clip->x0 == CLIP_X);
	assert(clip->y0 == CLIP_Y);


@@ 1101,16 1102,17 @@ _check_image(const d2tk_com_t *com, const d2tk_clip_t *clip)
	assert(com->body->image.y == IMAGE_Y - CLIP_Y);
	assert(com->body->image.w == IMAGE_W);
	assert(com->body->image.h == IMAGE_H);
	assert(strcmp(com->body->image.path , IMAGE_PATH) == 0);
	assert(strcmp(com->body->image.path, IMAGE_PATH) == 0);
	assert(com->body->image.align == IMAGE_ALIGN);
	assert(com->body->image.blob == false);
	assert(com->body->image.len == strlen(IMAGE_PATH));
}

static void
_test_image(void)
_test_image_path(void)
{
	d2tk_mock_ctx_t ctx = {
		.check = _check_image
		.check = _check_image_path
	};

	d2tk_core_t *core = d2tk_core_new(&d2tk_mock_driver, &ctx);


@@ 1123,7 1125,7 @@ _test_image(void)
		&D2TK_RECT(CLIP_X, CLIP_Y, CLIP_W, CLIP_H));
	assert(ref >= 0);

	d2tk_core_image(core, &D2TK_RECT(IMAGE_X, IMAGE_Y, IMAGE_W, IMAGE_H),
	d2tk_core_image_path(core, &D2TK_RECT(IMAGE_X, IMAGE_Y, IMAGE_W, IMAGE_H),
		strlen(IMAGE_PATH), IMAGE_PATH, IMAGE_ALIGN);

	d2tk_core_bbox_pop(core, ref);


@@ 1131,6 1133,53 @@ _test_image(void)
	d2tk_core_free(core);
}

static void
_check_image_blob(const d2tk_com_t *com, const d2tk_clip_t *clip)
{
	assert(clip->x0 == CLIP_X);
	assert(clip->y0 == CLIP_Y);
	assert(clip->x1 == CLIP_X + CLIP_W);
	assert(clip->y1 == CLIP_Y + CLIP_H);
	assert(clip->w == CLIP_W);
	assert(clip->h == CLIP_H);

	assert(com->size == sizeof(d2tk_body_image_t));
	assert(com->instr == D2TK_INSTR_IMAGE);
	assert(com->body->image.x == IMAGE_X - CLIP_X);
	assert(com->body->image.y == IMAGE_Y - CLIP_Y);
	assert(com->body->image.w == IMAGE_W);
	assert(com->body->image.h == IMAGE_H);
	assert(com->body->image.ptr == image_h);
	assert(com->body->image.align == IMAGE_ALIGN);
	assert(com->body->image.blob == true);
	assert(com->body->image.len == sizeof(image_h));
}

static void
_test_image_blob(void)
{
	d2tk_mock_ctx_t ctx = {
		.check = _check_image_blob
	};

	d2tk_core_t *core = d2tk_core_new(&d2tk_mock_driver, &ctx);
	assert(core);

	d2tk_core_set_dimensions(core, DIM_W, DIM_H);

	d2tk_core_pre(core);
	const ssize_t ref = d2tk_core_bbox_push(core, true,
		&D2TK_RECT(CLIP_X, CLIP_Y, CLIP_W, CLIP_H));
	assert(ref >= 0);

	d2tk_core_image_blob(core, &D2TK_RECT(IMAGE_X, IMAGE_Y, IMAGE_W, IMAGE_H),
		sizeof(image_h), image_h, IMAGE_ALIGN);

	d2tk_core_bbox_pop(core, ref);
	d2tk_core_post(core);
	d2tk_core_free(core);
}

#undef IMAGE_X
#undef IMAGE_Y
#undef IMAGE_W


@@ 1446,7 1495,8 @@ main(int argc __attribute__((unused)), char **argv __attribute__((unused)))
	_test_font_size();
	_test_font_face();
	_test_text();
	_test_image();
	_test_image_path();
	_test_image_blob();
	_test_bitmap();
	_test_custom();
	_test_stroke_width();