Skip to content

Commit 6796c54

Browse files
committed
Updated and renamed jxl source
1 parent 8a57f63 commit 6796c54

File tree

6 files changed

+501
-309
lines changed

6 files changed

+501
-309
lines changed

mrf_apps/Makefile

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ GDAL_INCLUDE = -I $(PREFIX)/include -I $(GDAL_ROOT)
1111
LIBDIR = $(PREFIX)/lib
1212
BINDIR = $(PREFIX)/bin
1313
CP=cp
14-
JXL_LIBS = -lbrunslienc-c -lbrunslidec-c
14+
BRUNSLI_LIBS = -lbrunslienc-c -lbrunslidec-c
1515

1616
INCLUDES = $(GDAL_INCLUDE)
1717

@@ -23,8 +23,8 @@ mrf_insert: mrf_insert.cpp
2323
can: can.cpp
2424
$(CXX) $(CXXFLAGS) $(INCLUDES) -o $@ $<
2525

26-
jxl: jxl.cpp
27-
$(CXX) $(CXXFLAGS) $(INCLUDES) -o $@ $< -L $(LIBDIR) $(JXL_LIBS)
26+
brn: brn.cpp
27+
$(CXX) $(CXXFLAGS) $(INCLUDES) -o $@ $< -L $(LIBDIR) $(BRUNSLI_LIBS)
2828

2929
install: $(TARGETS)
3030
$(CP) $^ $(BINDIR)

mrf_apps/brn.cpp

Lines changed: 321 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,321 @@
1+
#include <brunsli/encode.h>
2+
#include <brunsli/decode.h>
3+
#include <string>
4+
#include <iostream>
5+
#include <vector>
6+
#include <algorithm>
7+
#include <cassert>
8+
#include <cstdio>
9+
#include <sys/stat.h>
10+
#include <cstdlib>
11+
#include <fcntl.h>
12+
#include <sys/types.h>
13+
14+
#if defined(_WIN32)
15+
#if !defined(_WIN64)
16+
#error "Need 64bit support"
17+
#endif
18+
#include <Windows.h>
19+
#include <io.h>
20+
21+
#define FSEEK _fseeki64
22+
#define FTELL _ftelli64
23+
24+
// Windows is always little endian, supply functions to swap bytes
25+
// These are defined in <cstdlib>
26+
#define htobe64 _byteswap_uint64
27+
#define be64toh _byteswap_uint64
28+
29+
#else // Linux
30+
31+
#include <unistd.h>
32+
#include <endian.h>
33+
// Check that we can seek large files
34+
static_assert(sizeof(off_t) == 8);
35+
#define FSEEK fseeko
36+
#define FTELL ftello
37+
#endif
38+
39+
using namespace std;
40+
41+
int Usage(const string &s) {
42+
std::cerr << s << endl << endl
43+
<< "Synopsis: brn [OPTIONS] <source-file>\n"
44+
<< "\t-r\tReverse, convert BRUNSLI input to JFIF\n"
45+
<< "\t-b\tBundle (esri v2) input, default is MRF\n"
46+
<< "\t-s\tSingle image, input is a JFIF or BRUNSLI (with -r)\n";
47+
return 1;
48+
}
49+
50+
static size_t out_fun(vector<uint8_t> *output, const uint8_t *data, size_t size) {
51+
copy(data, data+size, back_inserter(*output));
52+
return size;
53+
}
54+
55+
// Big Endian native
56+
struct tinfo {
57+
uint64_t offset;
58+
uint64_t size;
59+
void toh() {
60+
offset = be64toh(offset);
61+
size = be64toh(size);
62+
}
63+
void tonative() {
64+
offset = htobe64(offset);
65+
size = htobe64(size);
66+
}
67+
};
68+
69+
// Single file, either BRUNSLI or JFIF
70+
int single_to_brn(const string &inname, bool reverse = false) {
71+
auto outname = inname + (reverse ? ".jfif" : ".brn");
72+
auto fin = fopen(inname.c_str(), "rb");
73+
if (!fin) return Usage("Can't open input file");
74+
FSEEK(fin, 0, SEEK_END);
75+
auto insize = ftell(fin);
76+
rewind(fin);
77+
// Check a max size of 128MB
78+
if (insize > (1ull << 27)) return Usage("Input file too large, limit is 128MB");
79+
vector<uint8_t> input(insize);
80+
fread(input.data(), insize, 1, fin);
81+
fclose(fin);
82+
auto fout = fopen(outname.c_str(), "wb");
83+
if (!fout) return Usage("Can't open output file");
84+
// Convert
85+
vector<uint8_t> tilebuf;
86+
int result = reverse ?
87+
DecodeBrunsli(insize, input.data(), &tilebuf, (DecodeBrunsliSink)out_fun)
88+
: EncodeBrunsli(insize, input.data(), &tilebuf, (DecodeBrunsliSink)out_fun);
89+
if (!result) return Usage(reverse ? "Error decoding BRUNSLI" : "Error encoding BRUNSLI");
90+
fwrite(tilebuf.data(), tilebuf.size(), 1, fout);
91+
fclose(fout);
92+
return 0;
93+
}
94+
95+
// From MRF, separate files, inname is the data file
96+
int mrf_to_brn(const string &inname, const string &outname, bool reverse = false) {
97+
// Assume three letter data file extension
98+
if ('.' != inname[inname.size() - 4])
99+
return Usage("Expect mrf data file with three letter file name extension");
100+
101+
struct stat statb;
102+
if (stat(inname.c_str(), &statb))
103+
return Usage("Can't stat input file");
104+
auto insize = statb.st_size;
105+
106+
// Indes should be same file with extension changed
107+
string inidxname(inname);
108+
inidxname.resize(inidxname.size() - 3);
109+
inidxname += "idx";
110+
// cout << "Opening " << inname << " and " << inidxname << endl;
111+
auto finidx = fopen(inidxname.c_str(), "rb");
112+
auto fin = fopen(inname.c_str(), "rb");
113+
if (!finidx || !fin)
114+
return Usage("Can't open input data or index file");
115+
116+
string outidxname(outname.substr(0, outname.size() - 4) + ".idx");
117+
// cout << "Opening " << outname << " and " << outidxname << endl;
118+
auto fout = fopen(outname.c_str(), "wb");
119+
auto foutidx = fopen(outidxname.c_str(), "wb");
120+
tinfo tile;
121+
vector<uint8_t> input;
122+
vector<uint8_t> tilebuf;
123+
uint64_t ooff = 0;
124+
125+
// Stats, saving ratio
126+
double min_rat = 1;
127+
double max_rat = -100;
128+
while (fread(&tile, sizeof(tile), 1, finidx)) {
129+
if (0 == tile.size) continue;
130+
tile.toh();
131+
FSEEK(fin, tile.offset, SEEK_SET);
132+
input.resize(tile.size);
133+
if (!fread(input.data(), tile.size, 1, fin)) {
134+
std::cerr << "Location " << hex << tile.offset << " size " << tile.size << dec << endl;
135+
return Usage("Failed to read input tile");
136+
}
137+
tilebuf.clear();
138+
139+
int result = reverse ?
140+
DecodeBrunsli(tile.size, input.data(), &tilebuf, (DecodeBrunsliSink)out_fun)
141+
: EncodeBrunsli(tile.size, input.data(), &tilebuf, (DecodeBrunsliSink)out_fun);
142+
if (!result) {
143+
std::cerr << "Location " << hex << tile.offset << " size " << tile.size << dec << endl;
144+
return Usage(reverse ? "Error decoding BRUNSLI" : "Error encoding BRUNSLI");
145+
}
146+
147+
double rat = 1 - double(tilebuf.size()) / tile.size;
148+
min_rat = min(rat, min_rat);
149+
max_rat = max(rat, max_rat);
150+
151+
// Prepare the output tinfo
152+
tile.offset = ooff;
153+
tile.size = tilebuf.size();
154+
ooff += tile.size;
155+
if (!fwrite(tilebuf.data(), tilebuf.size(), 1, fout))
156+
return Usage("Error writing data");
157+
tile.tonative();
158+
fwrite(&tile, sizeof(tile), 1, foutidx);
159+
}
160+
fclose(fin);
161+
fclose(finidx);
162+
fclose(fout);
163+
fclose(foutidx);
164+
165+
std::cerr << "Used to be " << insize << " now " << ooff << ", saved " << (1 - double(ooff)/insize) * 100 << "%\n";
166+
std::cerr << "Individual tile saving between " << min_rat * 100 << "% and " << max_rat * 100 << "%\n";
167+
168+
return 0;
169+
}
170+
171+
struct bundle_index {
172+
uint64_t offset : 40;
173+
uint64_t size : 24;
174+
//bool operator<(const bundle_index& other) {
175+
// return offset < other.offset;
176+
//}
177+
};
178+
179+
static_assert(sizeof(bundle_index) == 8);
180+
181+
constexpr size_t BSZ = 128;
182+
constexpr size_t BSZ2 = BSZ * BSZ;
183+
constexpr size_t HDRSZ = 64;
184+
constexpr size_t IDXSZ = BSZ2 * sizeof(bundle_index);
185+
186+
int bundle_to_brn(const string &inname, const string &outname, bool reverse = false)
187+
{
188+
struct stat statb;
189+
if (stat(inname.c_str(), &statb))
190+
return Usage("Can't stat input file");
191+
auto insize = statb.st_size;
192+
if (insize < (HDRSZ + IDXSZ))
193+
return Usage("Input file too small, can't be a bundle");
194+
195+
auto fin = fopen(inname.c_str(), "rb");
196+
if (!fin) return Usage("Can't open input file");
197+
198+
// TODO: define header as struct
199+
char header[64];
200+
if (1 != fread(header, sizeof(header), 1, fin))
201+
return Usage("Can't read from input bundle file");
202+
203+
// Read compact bundle index
204+
vector<bundle_index> idx(BSZ2);
205+
if (BSZ2 != fread(idx.data(), sizeof(bundle_index), BSZ2, fin))
206+
return Usage("Can't read bundle index");
207+
208+
// TODO: Swap after reading if not little endian
209+
210+
// Check for out of bounds
211+
for (auto &v : idx)
212+
if ((v.offset + v.size) > insize)
213+
return Usage("Corrupt bundle, index points past the end of the file");
214+
215+
// Prepare output
216+
FILE *fout = fopen(outname.c_str(), "wb");
217+
if (!fout)
218+
return Usage("Can't open output file");
219+
// Write the input header + index, to have the right placement
220+
size_t ooff = HDRSZ + IDXSZ;
221+
FSEEK(fout, ooff, SEEK_SET);
222+
223+
// Convert, writing output as we go, reusing the index
224+
vector<uint8_t> input;
225+
vector<uint8_t> tilebuf;
226+
size_t maxsz = 0;
227+
// Stats, saving ratio
228+
double min_rat = 1;
229+
double max_rat = -100;
230+
231+
for (auto &tile : idx) {
232+
if (0 == tile.size) continue;
233+
tilebuf.clear();
234+
235+
FSEEK(fin, tile.offset, SEEK_SET);
236+
input.resize(tile.size);
237+
if (!fread(input.data(), tile.size, 1, fin)) {
238+
std::cerr << "Location " << hex << tile.offset << " size " << tile.size << dec << endl;
239+
return Usage("Failed to read input tile");
240+
}
241+
242+
int result = reverse ?
243+
DecodeBrunsli(tile.size, input.data(), &tilebuf, (DecodeBrunsliSink)out_fun)
244+
: EncodeBrunsli(tile.size, input.data(), &tilebuf, (DecodeBrunsliSink)out_fun);
245+
if (!result) {
246+
cerr << "Location " << hex << tile.offset << " size " << tile.size << endl;
247+
return Usage(reverse ? "Error decoding BRUNSLI" : "Error encoding BRUNSLI");
248+
}
249+
250+
// Check that the output tile size fits on 24bits
251+
uint32_t tilesz = uint32_t(tilebuf.size());
252+
if (tilesz >= (1 << 24) || static_cast<size_t>(tilesz) != tilebuf.size()) {
253+
cerr << "Location " << hex << tile.offset << " size " << tile.size <<
254+
" converted to " << tilebuf.size() << endl;
255+
return Usage("Output tile size too big");
256+
}
257+
258+
double rat = 1 - double(tilesz) / tile.size;
259+
min_rat = min(rat, min_rat);
260+
max_rat = max(rat, max_rat);
261+
tile.offset = ooff + 4;
262+
tile.size = tilebuf.size();
263+
ooff += tile.size + 4;
264+
265+
// Looks good, write the output tile, prefixed by size
266+
uint32_t size_prefix = tile.size;
267+
if (!fwrite(&size_prefix, sizeof(size_prefix), 1, fout) ||
268+
!fwrite(tilebuf.data(), tilebuf.size(), 1, fout))
269+
return Usage("Failed to write output data");
270+
271+
// Collect stats
272+
maxsz = max(maxsz, static_cast<size_t>(tile.size));
273+
}
274+
// Done with the input
275+
fclose(fin);
276+
277+
// Update header and index at the start of the output bundle
278+
rewind(fout);
279+
// Modify maxtilesize and file size only
280+
memcpy(header + 8, &maxsz, 4); // Assume little endian
281+
memcpy(header + 24, &ooff, sizeof(ooff));
282+
fwrite(header, sizeof(header), 1, fout);
283+
fwrite(idx.data(), IDXSZ, 1, fout);
284+
fclose(fout);
285+
286+
std::cerr << "Used to be " << insize << " now " << ooff
287+
<< ", saved " << (1 - double(ooff)/insize) * 100 << "%\n";
288+
std::cerr << "Individual tile saving between " << min_rat * 100
289+
<< "% and " << max_rat * 100 << "%\n";
290+
std::cerr << "Maxtile " << maxsz << endl;
291+
return 0;
292+
}
293+
294+
int main(int argc, char **argv)
295+
{
296+
bool reverse = false; // defaults to JPEG -> BRUNSLI
297+
bool bundle = false; // defaults to MRF
298+
bool single = false; // single jpeg
299+
string input_name;
300+
while(--argc) {
301+
string this_arg(argv[argc]);
302+
if (this_arg == "-r") {
303+
reverse = true;
304+
} else if (this_arg == "-b") {
305+
bundle = true;
306+
} else if (this_arg == "-s") {
307+
single = true;
308+
} else {
309+
input_name = this_arg;
310+
}
311+
}
312+
313+
if (input_name.empty())
314+
return Usage("Needs input file name");
315+
316+
if (single)
317+
return single_to_brn(input_name, reverse);
318+
if (bundle)
319+
return bundle_to_brn(input_name, input_name + ".brn", reverse);
320+
return mrf_to_brn(input_name, input_name + ".brn", reverse);
321+
}

0 commit comments

Comments
 (0)