Skip to content

Instantly share code, notes, and snippets.

@marendowski
Created July 27, 2023 13:17
Show Gist options
  • Save marendowski/8aeff776caae41be9e96a7c3a2380b36 to your computer and use it in GitHub Desktop.
Save marendowski/8aeff776caae41be9e96a7c3a2380b36 to your computer and use it in GitHub Desktop.
C demo displaying a PNG image on X server using Xlib and libspng libraries
/* requires Xlib and libspng *
* gcc -o demo demo.c -l X11 -l spng -g */
#include <stdio.h>
#include <string.h>
#include <X11/Xlib.h>
#include <spng.h>
unsigned char *process_png_image(char *filename);
int main(void)
{
XImage *ximage;
/* defaults */
int width = 64;
int height = 64;
char *filename = "firefox.png";
char *path = "/usr/share/icons/hicolor/64x64/apps/";
char full_path[strlen(path) + strlen(filename) + 1];
strcpy(full_path, path);
strcat(full_path, filename);
/* get everything set up */
Display *display = XOpenDisplay(NULL);
Visual *visual = DefaultVisual(display, 0);
Window window = XCreateSimpleWindow(display, RootWindow(display, 0), 0, 0, width, height, 1, 0, 0);
/* get image */
ximage = XCreateImage(display, visual, DefaultDepth(display,DefaultScreen(display)), ZPixmap, 0, process_png_image(full_path), width, height, 32, 0);
XMapWindow(display, window);
while (1) {
/* draw image */
XPutImage(display, window, DefaultGC(display, 0), ximage, 0, 0, 0, 20, width, height);
/* draw text */
XSetForeground(display, DefaultGC(display, 0), 0xffffffff); /* set white foreground for text */
XDrawString(display, window, DefaultGC(display, 0), 10, 15, full_path, strlen(full_path));
}
return 0;
}
unsigned char *process_png_image(char *filename)
{
FILE *png;
int i;
spng_ctx *ctx = NULL;
unsigned char *image32 = NULL, *p, temp;
size_t image_size;
png = fopen(filename, "rb");
if (png == NULL)
fprintf(stderr, "error while opening %s\n", filename);
ctx = spng_ctx_new(0);
if (ctx == NULL)
fprintf(stderr, "spng_ctx_new() failed\n");
/* Ignore and don't calculate chunk CRC's */
spng_set_crc_action(ctx, SPNG_CRC_USE, SPNG_CRC_USE);
/* Set memory usage limits for storing standard and unknown chunks,
this is important when reading untrusted files! */
size_t limit = 1024 * 1024 * 32;
spng_set_chunk_limits(ctx, limit, limit);
/* Set source PNG */
spng_set_png_file(ctx, png); /* or _buffer(), _stream() */
/* Get image header
* return non-zero if fail */
struct spng_ihdr ihdr;
if (spng_get_ihdr(ctx, &ihdr))
fprintf(stderr, "spng_get_ihdr() error\n");
/* get image size */
if (spng_decoded_image_size(ctx, SPNG_FMT_RGBA8, &image_size))
fprintf(stderr, "spng_decoded_image_size() error\n");
/* allocate image */
image32 = malloc(image_size);
/* Decode the image in one go
* return non-zero if fail */
if (spng_decode_image(ctx, image32, image_size, SPNG_FMT_PNG, 0))
fprintf(stderr, "spng_decode_image() error\n");
/* perform a byteswap to swap red and blue colors
* every pixel is 4 bytes long (RGBA) */
p = image32;
for (i = 0; i < image_size; i += 4)
{
temp = p[i];
p[i] = p[i + 2]; /* replace the red byte with the blue byte */
p[i + 2] = temp; /* replace the blue byte with the red byte */
}
return image32;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment