GResource is the modern way to embed an image, but old code still expects a plain C byte array, and that is what gdk-pixbuf-csource generates. Feed it a PNG or any other GdkPixbuf-supported format and it writes ready-to-compile C source data. You will also choose a stable symbol name, inspect the generated dimensions, and avoid the older format's traps. Allow about 15 minutes for one image, plus time to integrate the generated source into your build.
This guide uses gdk-pixbuf-csource from the Debian package libgdk-pixbuf2.0-bin, version 2.42.10+dfsg-3ubuntu3.3 on the reference machine. The executable reports itself as gdk-pixbuf-csource-3.0 version 2.42.10. Options and generated boilerplate can differ between releases, so keep the version check with build notes for reproducible projects.
The utility is mainly a compatibility tool. New applications and libraries should normally use GResource for embedded assets. Use this command when you need its established C-data format or are maintaining code that already consumes it.
Start with ordinary, unprivileged commands. Reading an image and writing generated source in your project does not require sudo.
$ command -v gdk-pixbuf-csource
/usr/bin/gdk-pixbuf-csource
$ gdk-pixbuf-csource --version
gdk-pixbuf-csource-3.0 version 2.42.10
$ file /path/to/icon.png
/path/to/icon.png: PNG image data, ...
The input is one image pathname in normal mode. GdkPixbuf must have a loader for its format. If the file cannot be opened or decoded, the command exits non-zero and prints an error; it does not produce useful C output.
Checkpoint: run gdk-pixbuf-csource --help if you are checking a different installation. The local help lists the same modes described below, including --stream, --struct, --macros, --rle, --raw, --extern, --static, --decoder and --build-list.
Redirect the generated source to a new file. The default is a static C byte array using one-byte run-length encoding.
$ gdk-pixbuf-csource /path/to/icon.png > generated-icon.c
$ test -s generated-icon.c && head -n 4 generated-icon.c
/* GdkPixbuf RGBA C-Source image dump 1-byte-run-length-encoded */
#ifdef __SUNPRO_C
#pragma align 4 (my_pixbuf)
The default symbol is based on the input name. Do not treat the generated file as a hand-written source file: regenerate it when the image changes, and review the diff because the binary data can be large.
Shell redirection with > truncates an existing destination before the program runs. To protect a checked-in file, write to a temporary name and replace it only after the command succeeds:
$ gdk-pixbuf-csource /path/to/icon.png > generated-icon.c.new
$ test -s generated-icon.c.new
$ mv generated-icon.c.new generated-icon.c
If generation fails, leave the old file in place and investigate the input or loader. If the final command has not run, the old output is still available. Remove an unwanted .new file only after checking its path.
Use --name when source filenames may change or when a stable identifier matters to the C code. The value is an identifier prefix, not a quoted string and not a pathname.
$ gdk-pixbuf-csource --name=app_logo /path/to/icon.png > app-logo.c
$ rg -m 1 'app_logo' app-logo.c
#ifdef __GNUC__
Names should follow the rules for the generated C identifiers: use letters, digits and underscores, and start with a letter or underscore. Keep the name distinct from other generated assets. The option is useful only for a single image; in build-list mode each pair supplies its own name.
Checkpoint: search the generated file for the chosen name and for the image dimensions. The output contains comments and declarations that make a quick review possible without decoding the pixel data manually.
Run-length encoding is the default. It can reduce generated source for suitable images, but the decoder path is part of the format. Use --raw when you need an unencoded pixel-data macro or want to avoid the encoded representation. --rle explicitly selects the default encoded form.
$ gdk-pixbuf-csource --raw --macros --name=app_logo /path/to/icon.png > app-logo-data.h
$ sed -n '1,8p' app-logo-data.h
/* GdkPixbuf RGBA C-Source image dump */
#define APP_LOGO_ROWSTRIDE (...)
#define APP_LOGO_WIDTH (...)
#define APP_LOGO_HEIGHT (...)
#define APP_LOGO_BYTES_PER_PIXEL (...)
The exact numeric values depend on the image. With --macros, the tool emits row stride, width, height, bytes per pixel and either a raw or RLE pixel-data macro. If you keep the default RLE output, add --decoder when your consumer needs the generated *_RUN_LENGTH_DECODE macro.
Do not assume that --raw resizes or otherwise transforms the image. It changes how pixel data is represented in the generated source. The output still describes the input image's dimensions and row stride.
Most users should first identify how their application loads embedded data. The default output is a byte array. --stream generates a single string containing a serialised GdkPixdata structure in network byte order. --struct generates a GdkPixdata structure and requires the structure definition from gdk-pixdata.h.
$ gdk-pixbuf-csource --stream --name=app_logo /path/to/icon.png > app-logo-stream.c
$ gdk-pixbuf-csource --struct --name=app_logo /path/to/icon.png > app-logo-struct.c
$ rg -n 'GdkPixdata|app_logo|width|height' app-logo-struct.c | head
These modes are output formats, not a request to install headers or link a library. Make sure the code that consumes them matches the mode you selected. A generated structure is not interchangeable with a string or an ordinary byte array just because all three came from the same image.
Use --build-list when one invocation should emit multiple named variables. Supply alternating name and image pairs after the option.
$ gdk-pixbuf-csource --build-list \
toolbar_open /path/to/open.png \
toolbar_save /path/to/save.png \
> toolbar-images.c
$ rg -n 'toolbar_open|toolbar_save' toolbar-images.c
static const guint8 toolbar_open[] ...
static const guint8 toolbar_save[] ...
In this mode the names come from the list, so --name is not the naming mechanism. Keep each pair together and quote a pathname if it contains whitespace. A missing image or an incomplete pair is an input error; check the exit status before replacing a generated file.
The utility only writes generated text to standard output. It does not install files, alter the image, or require elevated privileges. Add the generated source to the same build target as the code that consumes it, then compile with the GdkPixbuf development headers and libraries required by that existing code.
If a compiler reports an unknown GdkPixdata type, revisit the --struct choice and the required gdk-pixdata.h definition. If the generated identifier is not found, inspect the actual name with rg and ensure the consuming source uses the same --name or build-list name. If loading fails, verify that the input format is supported by the installed GdkPixbuf loaders.
The manpage warns about a limitation in the run-length encoder: rowstride padding is included in the encoded stream, which can put the encoder out of sync with pixel boundaries and can produce a suboptimal rowstride. If that matters for your consumer, compare the default output with --raw and test the resulting application with representative images. Do not silently assume encoded output is the best choice for every image.
sudo or system-wide change was needed.