-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathpng.hpp
141 lines (136 loc) · 4.43 KB
/
png.hpp
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
#pragma once
#include "Filter.hpp"
#include "../file/File.hpp"
#include <cstdint>
/**
* 8/24/32-bit png image data encode/decode
* filter bytes from individual lines go to a separate header
*/
class PngFilter : public Filter {
private:
int stride = 3; //1: Gray/Indexed, 3: RGB, 4: RGBA
int width = 0;
public:
void setWidth(int w) {
this->width = w;
}
void setStride(int stride) {
this->stride = stride;
}
void encode(File *in, File *out, uint64_t size, int width, int & headerSize) override {
int lineWidth = width + 1; //including filter byte
headerSize = static_cast<int>(size / lineWidth); // = number of rows
RingBuffer<uint8_t> filterBuffer(nextPowerOf2(headerSize));
RingBuffer<uint8_t> pixelBuffer(nextPowerOf2(size - headerSize));
assert(filterBuffer.size() >= headerSize);
assert(pixelBuffer.size() >= size - headerSize);
for( int line = 0; line < headerSize; line++ ) {
uint8_t filter = in->getchar();
filterBuffer.add(filter);
for (int x = 0; x < width; x++) {
uint8_t c1 = in->getchar();
switch (filter) {
case 0: {
break;
}
case 1: {
c1=(static_cast<uint8_t>(c1 + (x < stride ? 0 : pixelBuffer(stride))));
break;
}
case 2: {
c1=(static_cast<uint8_t>(c1 + (line == 0 ? 0 : pixelBuffer(width))));
break;
}
case 3: {
c1 = (static_cast<uint8_t>(c1 + (((line == 0 ? 0 : pixelBuffer(width)) + (x < stride ? 0 : pixelBuffer(stride))) >> 1)));
break;
}
case 4: {
c1 = (static_cast<uint8_t>(c1 + paeth(
x < stride ? 0 : pixelBuffer(stride),
line == 0 ? 0 : pixelBuffer(width),
line == 0 || x < stride ? 0 : pixelBuffer(width + stride))));
break;
}
default:
//fail: unexpected filter code.
return;
}
pixelBuffer.add(c1);
}
}
uint32_t len1 = filterBuffer.getpos();
uint32_t len2 = pixelBuffer.getpos();
for (uint32_t i = 0; i < len1; i++)
out->putChar(filterBuffer[i]);
for (uint32_t i = 0; i < len2; i++)
out->putChar(pixelBuffer[i]);
}
uint64_t decode(File *in, File *out, FMode fMode, uint64_t size, uint64_t &diffFound) override {
int lineWidth = width + 1; //including filter byte
int headerSize = static_cast<int>(size / lineWidth); // = number of rows
RingBuffer<uint8_t> filterBuffer(nextPowerOf2(headerSize));
RingBuffer<uint8_t> pixelBuffer(nextPowerOf2(size - headerSize));
assert(filterBuffer.size() >= headerSize);
assert(pixelBuffer.size() >= size - headerSize);
for (int line = 0; line < headerSize; line++) {
uint8_t filter = in->getchar();
filterBuffer.add(filter);
}
uint32_t p = 0;
for (int line = 0; line < headerSize; line++) {
uint8_t filter = filterBuffer[line];
if (fMode == FMode::FDECOMPRESS) {
out->putChar(filter);
}
else if (fMode == FMode::FCOMPARE) {
p++;
if (filter != out->getchar() && (diffFound == 0)) {
diffFound = p;
}
}
for (int x = 0; x < width; x++) {
uint8_t c1 = in->getchar();
uint8_t c = c1;
switch (filter) {
case 0: {
break;
}
case 1: {
c1 = (static_cast<uint8_t>(c1 - (x < stride ? 0 : pixelBuffer(stride))));
break;
}
case 2: {
c1 = (static_cast<uint8_t>(c1 - (line == 0 ? 0 : pixelBuffer(width))));
break;
}
case 3: {
c1 = (static_cast<uint8_t>(c1 - (((line == 0 ? 0 : pixelBuffer(width)) + (x < stride ? 0 : pixelBuffer(stride))) >> 1)));
break;
}
case 4: {
c1 = (static_cast<uint8_t>(c1 - paeth(
x < stride ? 0 : pixelBuffer(stride),
line == 0 ? 0 : pixelBuffer(width),
line == 0 || x < stride ? 0 : pixelBuffer(width + stride))));
break;
}
default:
//fail: unexpected filter code.
break;
}
pixelBuffer.add(c);
if (fMode == FMode::FDECOMPRESS) {
out->putChar(c1);
}
else if (fMode == FMode::FCOMPARE) {
p++;
if (c1 != out->getchar() && (diffFound == 0)) {
diffFound = p;
}
}
}
}
return size;
}
};