+/* Return true iff a divides b. */
+static bool divides(unsigned a, unsigned b)
+{
+ if (b == 0)
+ return true;
+ if (a == 0)
+ return false;
+
+ return b % a == 0;
+}
+
+/* Set n bits starting from offset in the bitmap. */
+static void
+set_bits(unsigned char *bitmap, unsigned long offset, unsigned long n)
+{
+ if (offset % CHAR_BIT) {
+ bitmap[offset/CHAR_BIT] |= (n >= CHAR_BIT ? -1u : (1u << n) - 1)
+ << offset%CHAR_BIT;
+
+ n -= MIN(n, CHAR_BIT - offset%CHAR_BIT);
+ offset += CHAR_BIT - offset%CHAR_BIT;
+ }
+
+ if (n > CHAR_BIT) {
+ memset(&bitmap[offset/CHAR_BIT], -1, n/CHAR_BIT);
+
+ offset += n - n%CHAR_BIT;
+ n %= CHAR_BIT;
+ }
+
+ if (n) {
+ bitmap[offset/CHAR_BIT] |= (1u << n) - 1;
+ }
+}
+
+static int decode_frame(struct lbx_image *img, unsigned n,
+ unsigned char *pixels, unsigned char *pixel_mask)
+{
+ unsigned x, y;
+ long rc;
+
+ rc = lbx_img_seek(img, n);
+ if (rc < 0) {
+ tool_err(-1, "frame %u: invalid frame: %s\n", n, lbx_errmsg());
+ return -1;
+ }
+
+ while ((rc = lbx_img_read_row_header(img, &x, &y)) != 0) {
+ unsigned long offset;
+
+ if (rc < 0) {
+ tool_err(-1, "frame %u: invalid row: %s", n, lbx_errmsg());
+ return -1;
+ }
+
+ offset = (unsigned long) y * img->width + x;
+ rc = lbx_img_read_row_data(img, pixels+offset);
+ if (rc < 0) {
+ tool_err(-1, "frame %u: error reading row: %s\n", n, lbx_errmsg());
+ return -1;
+ }
+
+ set_bits(pixel_mask, offset, rc);
+ }
+
+ return 0;
+}
+