diff options
| author | Soikk | 2022-06-22 22:59:27 +0200 |
|---|---|---|
| committer | Soikk | 2022-06-22 22:59:27 +0200 |
| commit | 273dbef3da4a60a85db24bf7efd22ec411037dcf (patch) | |
| tree | 838b5fd3da056ea96e5e45a2f3b9357eb901c2b1 /pixel-count.c | |
| parent | 2b39040a6e10bdb6ed990579fa2095580b67c606 (diff) | |
| download | soikk-pixel-count-273dbef3da4a60a85db24bf7efd22ec411037dcf.tar.xz soikk-pixel-count-273dbef3da4a60a85db24bf7efd22ec411037dcf.tar.zst | |
Initial commit
Diffstat (limited to 'pixel-count.c')
| -rw-r--r-- | pixel-count.c | 153 |
1 files changed, 153 insertions, 0 deletions
diff --git a/pixel-count.c b/pixel-count.c new file mode 100644 index 0000000..50cdeac --- /dev/null +++ b/pixel-count.c @@ -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 |
