struct lbx_colour *palette)
{
bool masked = img_is_masked(mask, width, height);
- unsigned x, y, depth;
+ unsigned x, y, depth, maxval = palette ? 63 : 255;
+ unsigned char *rowbuf;
+ int rc;
- if (fprintf_ascii(f, "P7\nWIDTH %u\nHEIGHT %u\n", width, height) < 0)
- goto err;
+ depth = (palette ? 3 : 1) + masked;
+ if (width > (size_t)-1 / depth || !(rowbuf = malloc(width * depth))) {
+ tool_err(-1, "failed to allocate memory");
+ return -1;
+ }
- if (palette) {
- depth = masked ? 4 : 3;
+ rc = fprintf_ascii(f, "P7\nWIDTH %u\nHEIGHT %u\nDEPTH %u\n",
+ width, height, depth);
+ if (rc < 0)
+ goto write_err;
- if (fprintf_ascii(f, "DEPTH %u\nMAXVAL 63\n"
- "TUPLTYPE RGB%s\nENDHDR\n",
- depth, masked ? "_ALPHA" : "") < 0)
- goto err;
+ rc = fprintf_ascii(f, "MAXVAL %u\nTUPLTYPE %s",
+ maxval, palette ? "RGB" : "GRAYSCALE");
+ if (rc < 0)
+ goto write_err;
- for (x = y = 0; y < height; ++x < width || (x = 0, y++)) {
- unsigned long offset = (unsigned long) y * width + x;
- struct lbx_colour *c = &palette[pixels[offset]];
- unsigned char buf[4];
- bool vis;
-
- vis = mask[offset/CHAR_BIT] & (1u << offset%CHAR_BIT);
- buf[0] = c->red;
- buf[1] = c->green;
- buf[2] = c->blue;
- buf[3] = vis ? 63 : 0;
-
- if (fwrite(buf, 1, depth, f) < depth)
- goto err;
- }
- } else {
- depth = masked ? 2 : 1;
+ rc = fprintf_ascii(f, "_ALPHA\nENDHDR\n" + 6*!masked);
+ if (rc < 0)
+ goto write_err;
- if (fprintf_ascii(f, "DEPTH %u\nMAXVAL 255\n"
- "TUPLTYPE GRAYSCALE%s\nENDHDR\n",
- depth, masked ? "_ALPHA" : "") < 0)
- goto err;
-
- for (x = y = 0; y < height; ++x < width || (x = 0, y++)) {
+ for (y = 0; y < height; y++) {
+ for (x = 0; x < width; x++) {
unsigned long offset = (unsigned long) y * width + x;
- unsigned char buf[2];
- bool vis;
-
- vis = mask[offset/CHAR_BIT] & (1u << offset%CHAR_BIT);
- buf[0] = pixels[offset];
- buf[1] = vis ? 255 : 0;
-
- if (fwrite(buf, 1, depth, f) < depth)
- goto err;
+ 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;
+ }
}
+
+ if (fwrite(rowbuf, depth, width, f) < width)
+ goto write_err;
}
+ free(rowbuf);
return 0;
-err:
+write_err:
tool_err(0, "error writing %s", filename);
+
+ free(rowbuf);
return -1;
}