]> git.draconx.ca Git - liblbx.git/commitdiff
Improve lbx_colour structure layout.
authorNick Bowler <nbowler@draconx.ca>
Wed, 22 Sep 2021 06:42:24 +0000 (02:42 -0400)
committerNick Bowler <nbowler@draconx.ca>
Wed, 22 Sep 2021 07:06:23 +0000 (03:06 -0400)
There is no point in using bit-fields for the components of this
structure.  The structure will never be smaller than 4 bytes so
there is no space savings compared to just using four unsigned
char members.  This avoids the compiler needing to do any kind
of bit shuffling.

In the typical case where such a structure has no padding, this
means the layout of these members will now exactly match the PAM
format, enabling a modest speedup.

src/image.h
src/pnm.c

index 454b15b386c078561b9fc875e983c2c7a1b9744d..c375ce9ff51845b37761d53d08367003024da6df 100644 (file)
@@ -11,7 +11,7 @@ struct lbx_image {
 };
 
 struct lbx_colour {
-       unsigned red:6, green:6, blue:6, active:1;
+       unsigned char red, green, blue, active;
 };
 
 struct lbx_image *lbx_img_open(void *f, const struct lbx_file_ops *fops,
index 1596c5a1e85114bfc12e631f429ea2ef46bbbb7e..43108f8e32a7ec3cfc2dbe0a8cb1c090bc0bbe52 100644 (file)
--- a/src/pnm.c
+++ b/src/pnm.c
@@ -20,6 +20,7 @@
 #include <config.h>
 #include <stdio.h>
 #include <stdlib.h>
+#include <string.h>
 #include <stdbool.h>
 #include <stdarg.h>
 #include <assert.h>
@@ -311,6 +312,68 @@ err:
        return -1;
 }
 
+static void pam_format_rgba(unsigned char *rowbuf, const unsigned char *pixels,
+                            unsigned char *mask, unsigned width,
+                            unsigned long offset, struct lbx_colour *palette)
+{
+       unsigned x;
+
+       for (x = 0; x < width; x++) {
+               struct lbx_colour val = palette[pixels[offset+x]];
+               unsigned vis = 1 & ( mask[(offset+x)/CHAR_BIT]
+                                     >> ((offset+x)%CHAR_BIT) );
+
+               if (sizeof val == 4) {
+                       memcpy(rowbuf+4ul*x, &val, 4);
+               } else {
+                       rowbuf[4ul*x+0] = val.red;
+                       rowbuf[4ul*x+1] = val.green;
+                       rowbuf[4ul*x+2] = val.blue;
+               }
+               rowbuf[4ul*x+3] = -vis & 0x3f;
+       }
+}
+
+static void pam_format_rgb(unsigned char *rowbuf, const unsigned char *pixels,
+                           unsigned width, unsigned long offset,
+                           struct lbx_colour *palette)
+{
+       unsigned x;
+
+       for (x = 0; x < width; x++) {
+               struct lbx_colour val = palette[pixels[offset+x]];
+
+               if (sizeof val == 4) {
+                       memcpy(rowbuf+3ul*x, &val, 4);
+               } else {
+                       rowbuf[3ul*x+0] = val.red;
+                       rowbuf[3ul*x+1] = val.green;
+                       rowbuf[3ul*x+2] = val.blue;
+               }
+       }
+}
+
+static void pam_format_ga(unsigned char *rowbuf,
+                          const unsigned char *pixels, const unsigned char *mask,
+                          unsigned width, unsigned long offset)
+{
+       unsigned x;
+
+       for (x = 0; x < width; x++) {
+               unsigned vis = 1 & ( mask[(offset+x)/CHAR_BIT]
+                                     >> ((offset+x)%CHAR_BIT) );
+
+               rowbuf[2ul*x+0] = pixels[offset+x];
+               rowbuf[2ul*x+1] = -vis & 0xff;
+       }
+}
+
+static void pam_format_g(unsigned char *rowbuf, const unsigned char *pixels,
+                         unsigned width, unsigned long offset)
+{
+       memcpy(rowbuf, pixels+offset, width);
+}
+
 /*
  * Output filter for Netpbm's PAM format.  This format combines the features
  * of all the other Netpbm formats, supporting RGB and grayscale images with
@@ -322,12 +385,18 @@ int img_output_pam(FILE *f, const char *filename,
                    struct lbx_colour *palette)
 {
        bool masked = img_is_masked(mask, width, height);
-       unsigned x, y, depth, maxval = palette ? 63 : 255;
        unsigned char *rowbuf;
+       unsigned long offset;
+       unsigned y, depth;
        int rc;
 
        depth = (palette ? 3 : 1) + masked;
-       if (width > (size_t)-1 / depth || !(rowbuf = malloc(width * depth))) {
+       if (width >= (size_t)-1 / depth)
+               goto alloc_err;
+
+       rowbuf = malloc(width * depth + 1);
+       if (!rowbuf) {
+alloc_err:
                tool_err(-1, "failed to allocate memory");
                return -1;
        }
@@ -337,8 +406,9 @@ int img_output_pam(FILE *f, const char *filename,
        if (rc < 0)
                goto write_err;
 
-       rc = fprintf_ascii(f, "MAXVAL %u\nTUPLTYPE %s",
-                             maxval, palette ? "RGB" : "GRAYSCALE");
+       rc = fprintf_ascii(f, "MAXVAL %d\nTUPLTYPE %s",
+                             palette ? 63 : 255,
+                             palette ? "RGB" : "GRAYSCALE");
        if (rc < 0)
                goto write_err;
 
@@ -346,26 +416,20 @@ int img_output_pam(FILE *f, const char *filename,
        if (rc < 0)
                goto write_err;
 
-       for (y = 0; y < height; y++) {
-               for (x = 0; x < width; x++) {
-                       unsigned long offset = (unsigned long) y * width + x;
-                       size_t p = (size_t)depth * x; // pixel start
-
-                       if (palette) {
-                               struct lbx_colour *c = &palette[pixels[offset]];
-                               rowbuf[p+0] = c->red;
-                               rowbuf[p+1] = c->green;
-                               rowbuf[p+2] = c->blue;
-                       } else {
-                               rowbuf[p+0] = pixels[offset];
-                       }
-
-                       if (masked) {
-                               bool vis = 1 & ( mask[offset/CHAR_BIT]
-                                                >> (offset%CHAR_BIT) );
-
-                               rowbuf[p+depth-1] = vis*maxval;
-                       }
+       for (offset = y = 0; y < height; y++, offset += width) {
+               switch (depth) {
+               case 4:
+                       pam_format_rgba(rowbuf, pixels, mask, width, offset, palette);
+                       break;
+               case 3:
+                       pam_format_rgb(rowbuf, pixels, width, offset, palette);
+                       break;
+               case 2:
+                       pam_format_ga(rowbuf, pixels, mask, width, offset);
+                       break;
+               case 1:
+                       pam_format_g(rowbuf, pixels, width, offset);
+                       break;
                }
 
                if (fwrite(rowbuf, depth, width, f) < width)
@@ -376,7 +440,6 @@ int img_output_pam(FILE *f, const char *filename,
        return 0;
 write_err:
        tool_err(0, "error writing %s", filename);
-
        free(rowbuf);
        return -1;
 }