i3lock-color

The world's most popular non-default computer lockscreen.
Index Commits Files Refs README LICENSE
commit aa7984f215d006d66cfce0b3b2f6ac855c11861b
parent 0be11444bc64804ee7e3fd125e701046336704b7
Author: Martin Dørum <martid0311@gmail.com>
Date:   Fri, 24 May 2019 03:03:48 +0200

Add rgbx, xrgb, bgr, etc. formats (#234)


Diffstat:
Mi3lock.1 | 4++--
Mi3lock.c | 65+++++++++++++++++++++++++++++++++++++++++++++++++----------------
2 files changed, 51 insertions(+), 18 deletions(-)
diff --git a/i3lock.1 b/i3lock.1
@@ -79,8 +79,8 @@ Display the given PNG image instead of a blank screen.
 .TP
 .BI \fB\-\-raw= format
 Read the image given by \-\-image as a raw image instead of PNG. The argument is the image's format
-as <width>x<height>:<pixfmt>. The supported pixel formats are 'native' and 'rgb'.
-The "rgb" pixel format expects a pixel to be three bytes; red, green, and blue.
+as <width>x<height>:<pixfmt>. The supported pixel formats are:
+\'native', 'rgb', 'xrgb', 'rgbx', 'bgr', 'xbgr', and 'bgrx'.
 The "native" pixel format expects a pixel as a 32-bit (4-byte) integer in
 the machine's native endianness, with the upper 8 bits unused. Red, green and blue are stored in
 the remaining bits, in that order.
diff --git a/i3lock.c b/i3lock.c
@@ -657,24 +657,32 @@ static ssize_t read_raw_image_native(uint32_t *dest, FILE *src, size_t width, si
     return count;
 }
 
-static ssize_t read_raw_image_rgb(uint32_t *dest, FILE *src, size_t width, size_t height, int pixstride) {
-    unsigned char *buf = malloc(width * 3);
+struct raw_pixel_format {
+    int bpp;
+    int red;
+    int green;
+    int blue;
+};
+
+static ssize_t read_raw_image_fmt(uint32_t *dest, FILE *src, size_t width, size_t height, int pixstride,
+                                  struct raw_pixel_format fmt) {
+    unsigned char *buf = malloc(width * fmt.bpp);
     if (buf == NULL)
         return -1;
 
     ssize_t count = 0;
     for (size_t y = 0; y < height; y++) {
-        size_t n = fread(buf, 1, width * 3, src);
+        size_t n = fread(buf, 1, width * fmt.bpp, src);
         count += n;
-        if (n < (size_t)(width * 3))
+        if (n < (size_t)(width * fmt.bpp))
             break;
 
         for (size_t x = 0; x < width; ++x) {
-            int idx = x * 3;
+            int idx = x * fmt.bpp;
             dest[y * pixstride + x] = 0 |
-                                      (buf[idx + 0] << 16) |
-                                      (buf[idx + 1] << 8) |
-                                      (buf[idx + 2]);
+                                      (buf[idx + fmt.red]) << 16 |
+                                      (buf[idx + fmt.green]) << 8 |
+                                      (buf[idx + fmt.blue]);
         }
     }
 
@@ -682,6 +690,14 @@ static ssize_t read_raw_image_rgb(uint32_t *dest, FILE *src, size_t width, size_
     return count;
 }
 
+// Pre-defind pixel formats (<bytes per pixel>, <red pixel>, <green pixel>, <blue pixel>)
+static const struct raw_pixel_format raw_fmt_rgb = {3, 0, 1, 2};
+static const struct raw_pixel_format raw_fmt_rgbx = {4, 0, 1, 2};
+static const struct raw_pixel_format raw_fmt_xrgb = {4, 1, 2, 3};
+static const struct raw_pixel_format raw_fmt_bgr = {3, 2, 1, 0};
+static const struct raw_pixel_format raw_fmt_bgrx = {4, 2, 1, 0};
+static const struct raw_pixel_format raw_fmt_xbgr = {4, 3, 2, 1};
+
 static cairo_surface_t *read_raw_image(const char *image_path, const char *image_raw_format) {
     cairo_surface_t *img;
 
@@ -727,16 +743,33 @@ static cairo_surface_t *read_raw_image(const char *image_path, const char *image
         /* If the pixfmt is 'native', just read each line directly into the buffer */
         size = w * h * 4;
         count = read_raw_image_native(data, f, w, h, pixstride);
-    } else if (strcmp(pixfmt, "rgb") == 0) {
-        /* If the pixfmt is 'rgb', we have to convert it to the native pixfmt */
-        size = w * h * 3;
-        count = read_raw_image_rgb(data, f, w, h, pixstride);
     } else {
-        fprintf(stderr, "Unknown raw pixel pixfmt: %s\n", pixfmt);
-        fclose(f);
-        cairo_surface_destroy(img);
-        return NULL;
+        const struct raw_pixel_format *fmt = NULL;
+
+        if (strcmp(pixfmt, "rgb") == 0)
+            fmt = &raw_fmt_rgb;
+        else if (strcmp(pixfmt, "rgbx") == 0)
+            fmt = &raw_fmt_rgbx;
+        else if (strcmp(pixfmt, "xrgb") == 0)
+            fmt = &raw_fmt_xrgb;
+        else if (strcmp(pixfmt, "bgr") == 0)
+            fmt = &raw_fmt_bgr;
+        else if (strcmp(pixfmt, "bgrx") == 0)
+            fmt = &raw_fmt_bgrx;
+        else if (strcmp(pixfmt, "xbgr") == 0)
+            fmt = &raw_fmt_xbgr;
+
+        if (fmt == NULL) {
+            fprintf(stderr, "Unknown raw pixel format: %s\n", pixfmt);
+            fclose(f);
+            cairo_surface_destroy(img);
+            return NULL;
+        }
+
+        size = w * h * fmt->bpp;
+        count = read_raw_image_fmt(data, f, w, h, pixstride, *fmt);
     }
+
     cairo_surface_mark_dirty(img);
 
     if (count < size) {