summary refs log tree commit diff
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--bin/pngo.c63
1 files changed, 53 insertions, 10 deletions
diff --git a/bin/pngo.c b/bin/pngo.c
index 8f279e8a..4db0d11d 100644
--- a/bin/pngo.c
+++ b/bin/pngo.c
@@ -366,15 +366,12 @@ static void filterData(void) {
 
 static void eliminateAlpha(void) {
     if (!(header.color & ALPHA)) return;
-
-    size_t pixelSize = lineSize() / header.width;
-    size_t alphaSize = header.depth / 8;
-    size_t colorSize = pixelSize - alphaSize;
-
+    size_t sampleSize = header.depth / 8;
+    size_t pixelSize = 4 * sampleSize;
     for (uint32_t y = 0; y < header.height; ++y) {
         for (uint32_t x = 0; x < header.width; ++x) {
-            for (size_t i = 0; i < alphaSize; ++i) {
-                if (lines[y].data[x * pixelSize + colorSize + i] != 0xFF) return;
+            for (size_t i = 0; i < sampleSize; ++i) {
+                if (lines[y].data[x * pixelSize + 3 * sampleSize + i] != 0xFF) return;
             }
         }
     }
@@ -385,16 +382,61 @@ static void eliminateAlpha(void) {
         uint8_t *data = ptr;
         *type = *lines[y].type;
         for (uint32_t x = 0; x < header.width; ++x) {
-            memcpy(ptr, &lines[y].data[x * pixelSize], colorSize);
-            ptr += colorSize;
+            memcpy(ptr, &lines[y].data[x * pixelSize], 3 * sampleSize);
+            ptr += 3 * sampleSize;
         }
         lines[y].type = type;
         lines[y].data = data;
     }
-
     header.color &= ~ALPHA;
 }
 
+static void eliminateColor(void) {
+    if (!(header.color & TRUECOLOR)) return;
+    size_t sampleSize = header.depth / 8;
+    size_t pixelSize = ((header.color & ALPHA) ? 4 : 3) * sampleSize;
+    for (uint32_t y = 0; y < header.height; ++y) {
+        for (uint32_t x = 0; x < header.width; ++x) {
+            if (
+                0 != memcmp(
+                    &lines[y].data[x * pixelSize],
+                    &lines[y].data[x * pixelSize + 1 * sampleSize],
+                    sampleSize
+                )
+            ) return;
+            if (
+                0 != memcmp(
+                    &lines[y].data[x * pixelSize + 1 * sampleSize],
+                    &lines[y].data[x * pixelSize + 2 * sampleSize],
+                    sampleSize
+                )
+            ) return;
+        }
+    }
+
+    uint8_t *ptr = data;
+    for (uint32_t y = 0; y < header.height; ++y) {
+        uint8_t *type = ptr++;
+        uint8_t *data = ptr;
+        *type = *lines[y].type;
+        for (uint32_t x = 0; x < header.width; ++x) {
+            memcpy(ptr, &lines[y].data[x * pixelSize], sampleSize);
+            ptr += sampleSize;
+            if (header.color & ALPHA) {
+                memcpy(
+                    ptr,
+                    &lines[y].data[x * pixelSize + 3 * sampleSize],
+                    sampleSize
+                );
+                ptr += sampleSize;
+            }
+        }
+        lines[y].type = type;
+        lines[y].data = data;
+    }
+    header.color &= ~TRUECOLOR;
+}
+
 static void optimize(const char *inPath, const char *outPath) {
     if (inPath) {
         path = inPath;
@@ -421,6 +463,7 @@ static void optimize(const char *inPath, const char *outPath) {
     scanlines();
     reconData();
     eliminateAlpha();
+    eliminateColor();
     filterData();
     free(lines);