]> git.xolatile.top Git - soikk-pixel-count.git/commitdiff
Initial commit
authorSoikk <76824648+Soikk@users.noreply.github.com>
Wed, 22 Jun 2022 20:59:27 +0000 (22:59 +0200)
committerSoikk <76824648+Soikk@users.noreply.github.com>
Wed, 22 Jun 2022 20:59:27 +0000 (22:59 +0200)
README.md [new file with mode: 0644]
decompress.c [new file with mode: 0644]
download.png [new file with mode: 0644]
pixel-count.c [new file with mode: 0644]
sample.png [new file with mode: 0644]

diff --git a/README.md b/README.md
new file mode 100644 (file)
index 0000000..1854ed1
--- /dev/null
+++ b/README.md
@@ -0,0 +1,9 @@
+# Pixel count
+ Counts the number of pixels of one color in a PNG image encoded in RBG.
+ Preferably with just one IDAT chunk.
+
+ Built with
+    gcc pixel-count.c -lz [-lm]
+    
+ lm flag is optional, you might or might not need to link the math library
\ No newline at end of file
diff --git a/decompress.c b/decompress.c
new file mode 100644 (file)
index 0000000..dae888d
--- /dev/null
@@ -0,0 +1,131 @@
+/*
+
+Not implemented yet
+
+Currently using zlib's decompress (sane)
+
+
+
+
+
+uint8_t getCM(uint8_t b){
+       uint8_t r = b<<4;
+       return r>>4;
+}
+
+uint8_t getCINFO(uint8_t b){
+       return b>>4;
+}
+
+bool validateCMFFLG(uint8_t CMF, uint8_t FLG){
+       uint16_t CMFFLGcheck = (CMF<<8) + FLG;
+       return getCM(CMF) == 8 && CMFFLGcheck%31 == 0;
+}
+
+typedef bool bit;
+
+
+bool getBit(int n, int bit){
+       return n & (1 << bit);
+}
+
+void printBinary(uint8_t n){
+    for(int i = 7; i >= 0; --i)
+        printf("%d", getBit(n, i));
+}
+
+uint8_t reverseBits(uint8_t n){
+       uint8_t r = 0;
+       for(int i = 0; i < 8; ++i)
+               r |= ((bool)(n&(1<<(7-i))))<<i;
+       return r;
+}
+
+uint8_t read8(bit *data, uint32_t *i){
+       // This function is used for decompression
+       // The first bit is the LSB
+       uint8_t r = 0;
+       for(int j = 0; j < 8; ++j){
+               r += data[(*i)+j]<<j;
+       }
+       (*i) += 8;
+       return r;
+}
+
+uint16_t read16(bit *data, uint32_t *i){
+       // This function is used for decompression
+       // The first bit is the LSB
+       uint16_t r = 0;
+       for(int j = 0; j < 16; ++j){
+               r += data[(*i)+j]<<j;
+       }
+       (*i) += 16;
+       return r;
+}
+
+typedef enum compressionType{
+       NONE, FIXED, DYNAMIC, ERROR,
+} compressionType;
+
+bit *decompressData(bit *data, uint32_t len){
+       // we have to decompress with zlib
+                               // in zlib the first bit is the least significant
+                               // (b0 b1 b2 b3)
+                               // ftp://ftp.isi.edu/in-notes/rfc1950.txt
+                               // https://www.ietf.org/rfc/rfc1950.txt
+                               // https://stackoverflow.com/questions/42934720/understanding-the-zlib-header-cmf-cm-cinfo-flg-fdict-dictid-flevel-rfc
+                               
+                               /*uint8_t CMF = data[0], FLG = data[1], FDICT, FLEVEL;
+                               if(!validateCMFFLG(CMF, FLG)){
+                                       fprintf(stderr, "Invalid CMF+FLG check\n");
+                                       fclose(fp);
+                                       return 0;
+                               }
+                               uint32_t LZ77size = (1<<getCINFO(CMF))<<8;
+                               FDICT = getBit(FLG, 5);
+                               FLEVEL = getBit(FLG, 6) + (getBit(FLG, 7)<<1);
+                               if(FDICT){
+                                       fprintf(stderr, "I dont know how to deal with DICT\n");
+                                       fclose(fp);
+                                       return 0;
+                               }
+                               
+                               // Deflate data
+                               // https://www.ietf.org/rfc/rfc1951.txt
+                               /*
+                               Data elements are packed into bytes in order of
+                                       increasing bit number within the byte, i.e., starting
+                                       with the least-significant bit of the byte.
+                               Data elements other than Huffman codes are packed
+                                       starting with the least-significant bit of the data
+                                       element.
+                               Huffman codes are packed starting with the most-
+                                       significant bit of the code.
+                               *
+                               /
+
+                               // Adler32
+       bit *out = malloc(len);
+       bit BFINAL;
+       uint8_t BTYPE;
+       uint32_t ii = 0, oi = 0;
+       while(!BFINAL){
+               BFINAL = data[ii++];
+               if(BFINAL){
+                       // TODO: exit
+               }
+               BTYPE = (data[ii]<<1) + data[ii+1];
+               ii += 2;
+               if(BTYPE == NONE){
+                       ii += 8-(ii%8);
+               }
+               uint16_t LEN, NLEN;
+               LEN = read16(data, &ii);
+               NLEN = read16(data, &ii);
+
+               for(uint16_t j = 0; j < LEN; ++j){
+
+               }
+       }
+}
+*/
\ No newline at end of file
diff --git a/download.png b/download.png
new file mode 100644 (file)
index 0000000..1173610
Binary files /dev/null and b/download.png differ
diff --git a/pixel-count.c b/pixel-count.c
new file mode 100644 (file)
index 0000000..50cdeac
--- /dev/null
@@ -0,0 +1,153 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <inttypes.h>
+#include <stdbool.h>
+#include <math.h>
+#include "zlib.h"
+
+#define HSIZE 8
+#define CSIZE 4
+
+
+int byteArrayEquals(uint8_t *b1, uint8_t *b2, uint32_t size){
+       uint32_t i = 0;
+       while(i < size && b1[i] == b2[i])
+               ++i;
+       return i == size;
+}
+
+uint8_t paethPredictor(uint8_t a, uint8_t b, uint8_t c){
+       uint8_t p = (a + b - c)%256;    // initial estimate
+       uint8_t pa = abs(p - a);                // distances to a, b, c
+       uint8_t pb = abs(p - b);
+       uint8_t pc = abs(p - c);
+       // return nearest of a,b,c,
+       // breaking ties in order a,b,c.
+       if(pa <= pb && pa <= pc)
+               return a;
+       else if(pb <= pc)
+               return b;
+       else
+               return c;
+}
+
+bool matchRGB(uint8_t c1[3], uint8_t c2[3]){
+       return (c1[0] == c2[0]) && (c1[1] == c2[1]) && (c1[2] == c2[2]);
+}
+
+
+uint8_t PNG[HSIZE] = {0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A};
+uint8_t IHDR[CSIZE] = {0x49, 0x48, 0x44, 0x52};
+uint8_t IDAT[CSIZE] = {0x49, 0x44, 0x41, 0x54};
+uint8_t        IEND[CSIZE] = {0x49, 0x45, 0x4E, 0x44};
+
+
+int main(){
+
+       uint32_t pixels = 0;
+
+       FILE *fp = fopen("download.png", "rb"); // File to read
+       uint8_t red[3] = {0xFF, 0x00, 0x00};    // Color to look for
+
+       // Read PNG header
+       uint8_t header[HSIZE];
+       fread(header, sizeof(uint8_t), HSIZE, fp);
+       if(!byteArrayEquals(header, PNG, HSIZE)){
+               fprintf(stderr, "Invalid PNG signature\n");
+               fclose(fp);
+               return 0;
+       }
+       
+       uint32_t width = 0, height = 0;
+       uint8_t bitDepth, colorType, compressionMethod, filterMethod, interlaceMethod;
+
+       // Start reading file
+       while(!feof(fp)){
+
+               uint8_t lenbuf[CSIZE], ctype[CSIZE], crcbuf[CSIZE];
+
+               // Read length of chunk
+               fread(lenbuf, sizeof(uint8_t), CSIZE, fp);
+               uint32_t len = 0;
+               for(int i = 0; i < CSIZE; ++i){
+                       len += lenbuf[i]<<(8*(3-i));
+               }
+               uint8_t *data = calloc(len, sizeof(uint8_t));
+
+               // Read chunk type
+               fread(ctype, sizeof(uint8_t), CSIZE, fp);
+
+               // Read data according to type
+               fread(data, sizeof(uint8_t), len, fp);
+               if(byteArrayEquals(ctype, IHDR, CSIZE)){
+                       for(int i = 0; i < 4; ++i){
+                               width += data[i]<<(8*(3-i));
+                               height += data[i+4]<<(8*(3-i));
+                       }
+                       bitDepth = data[8];
+                       colorType = data[9];
+                       compressionMethod = data[10];
+                       filterMethod = data[11];
+                       interlaceMethod = data[12];
+               }else if(byteArrayEquals(ctype, IDAT, CSIZE)){
+
+                       // Only implementing RGB
+                       if(colorType == 2){
+
+                               uint8_t *d = malloc(height*(1 + width*3)*sizeof(uint8_t));
+                               uLongf nlen;
+                               uncompress((Bytef *)d, &nlen, (Bytef *)data, len);
+
+                               for(uint16_t i = 0; i < height; ++i){
+
+                                       uint8_t color[3] = {0x00, 0x00, 0x00};
+                                       uint8_t filterType = d[i*(1+width*3) + 0];
+                                       uint8_t bpp = 3*(bitDepth/8);
+
+                                       for(uint16_t j = 1; j < 1+width*3; ++j){
+                                               
+                                               uint8_t ant = (j-bpp < 1) ? 0 : d[i*(1+width*3) + j-bpp];
+                                               uint8_t prev = (i == 0) ? 0 : d[(i-1)*(1+width*3) + j];
+                                               uint8_t antprev = (j-bpp < 1 || i == 0) ? 0 : d[(i-1)*(1+width*3) + j-bpp];
+
+                                               switch(filterType){
+                                                       case 1:
+                                                               d[i*(1+width*3) + j] = (d[i*(1+width*3) + j] + ant)%256;
+                                                               break;
+                                                       case 2:
+                                                               d[i*(1+width*3) + j] = (d[i*(1+width*3) + j] + prev)%256;
+                                                               break;
+                                                       case 3:
+                                                               d[i*(1+width*3) + j] = (d[i*(1+width*3) + j] + (uint8_t)floor((ant + prev)/2))%256;
+                                                               break;
+                                                       case 4:
+                                                               d[i*(1+width*3) + j] = (d[i*(1+width*3) + j] + paethPredictor(ant, prev, antprev))%256;
+                                                               break;
+                                               }
+                                               
+                                               // Stores pixels in pixels array
+                                               color[(j-1)%3] = d[i*(1+width*3) + j];
+
+                                               // Counts red pixels
+                                               if(j%3 == 0 && matchRGB(color, red)){
+                                                       ++pixels;
+                                               }
+                                       }
+                               }       
+                       }
+               }
+
+               // Read CRC checksum
+               fread(crcbuf, sizeof(uint8_t), CSIZE, fp);
+
+               if(byteArrayEquals(ctype, IEND, CSIZE)){
+                       break;  
+               }
+       }
+       
+       fclose(fp);
+
+       printf("Pixels: %d\n", pixels);
+
+       return 0;
+}
\ No newline at end of file
diff --git a/sample.png b/sample.png
new file mode 100644 (file)
index 0000000..a9c6385
Binary files /dev/null and b/sample.png differ