-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathpixel-count.c
153 lines (121 loc) · 3.66 KB
/
pixel-count.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
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;
}