Initial commit
This commit is contained in:
parent
2b39040a6e
commit
273dbef3da
9
README.md
Normal file
9
README.md
Normal file
@ -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
|
131
decompress.c
Normal file
131
decompress.c
Normal file
@ -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){
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
BIN
download.png
Normal file
BIN
download.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 30 KiB |
153
pixel-count.c
Normal file
153
pixel-count.c
Normal file
@ -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;
|
||||
}
|
BIN
sample.png
Normal file
BIN
sample.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.7 KiB |
Loading…
x
Reference in New Issue
Block a user