Added a second way to save an image
This commit is contained in:
parent
8103b7fbf4
commit
41869d8cb0
6 changed files with 101 additions and 12 deletions
|
@ -1,11 +1,19 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <chrono>
|
||||||
|
|
||||||
inline bool is_pow_of_two(int n){
|
inline bool is_pow_of_two(int n){
|
||||||
return (n & (n - 1)) == 0;
|
return (n & (n - 1)) == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// calculates integer 2-log such that:
|
||||||
|
// 2^(two_log(x)) >= x > 2^(two_log(x) - 1)
|
||||||
|
unsigned int two_log(unsigned int x){
|
||||||
|
if(x <= 1) return 0;
|
||||||
|
return 8*sizeof(unsigned int) - __builtin_clz(x-1);
|
||||||
|
}
|
||||||
|
|
||||||
inline std::string human_string(int n){
|
inline std::string human_string(int n){
|
||||||
static const std::string names [] = {"", "K", "M", "G"};
|
static const std::string names [] = {"", "K", "M", "G"};
|
||||||
int i = 0;
|
int i = 0;
|
||||||
|
@ -22,3 +30,23 @@ inline std::string field(std::string const & str){
|
||||||
auto add = length - str.size();
|
auto add = length - str.size();
|
||||||
return str + ":" + std::string(add, ' ') + "\t";
|
return str + ":" + std::string(add, ' ') + "\t";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct timer{
|
||||||
|
typedef std::chrono::high_resolution_clock clock;
|
||||||
|
typedef std::chrono::time_point<clock> time;
|
||||||
|
typedef std::chrono::duration<double> seconds;
|
||||||
|
|
||||||
|
std::string name;
|
||||||
|
time begin;
|
||||||
|
|
||||||
|
timer(std::string name)
|
||||||
|
: name(name)
|
||||||
|
, begin(clock::now())
|
||||||
|
{}
|
||||||
|
|
||||||
|
~timer(){
|
||||||
|
time end = clock::now();
|
||||||
|
seconds elapsed = end - begin;
|
||||||
|
std::cout << name << "\t" << elapsed.count() << std::endl;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
|
@ -43,6 +43,9 @@ namespace jcmp {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Way of writing does not matter for performance
|
||||||
|
// timings: http://i.imgur.com/cskC43O.png (300 points per method)
|
||||||
|
// It's not surprising as filebuf is already a buffer
|
||||||
inline void write_to_file(image const & image, std::string filename){
|
inline void write_to_file(image const & image, std::string filename){
|
||||||
std::filebuf file;
|
std::filebuf file;
|
||||||
file.open(filename, std::ios_base::out|std::ios_base::trunc);
|
file.open(filename, std::ios_base::out|std::ios_base::trunc);
|
||||||
|
@ -50,6 +53,23 @@ namespace jcmp {
|
||||||
file.sputn(reinterpret_cast<const char*>(image.data.data()), image.data.size() * sizeof(coefficient));
|
file.sputn(reinterpret_cast<const char*>(image.data.data()), image.data.size() * sizeof(coefficient));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Assumes Iterator points to a coefficient]
|
||||||
|
// length in header is not used
|
||||||
|
template <typename Iterator>
|
||||||
|
inline void write_to_file(header h, Iterator begin, Iterator end, std::string filename){
|
||||||
|
h.length = 0;
|
||||||
|
std::filebuf file;
|
||||||
|
file.open(filename, std::ios_base::out|std::ios_base::trunc);
|
||||||
|
file.sputn(reinterpret_cast<const char*>(&h), sizeof(header));
|
||||||
|
while(begin != end){
|
||||||
|
file.sputn(reinterpret_cast<const char*>(&*begin++), sizeof(coefficient));
|
||||||
|
h.length++;
|
||||||
|
}
|
||||||
|
// http://stackoverflow.com/questions/2530274/how-to-overwrite-only-part-of-a-file-in-c
|
||||||
|
file.pubseekpos(0);
|
||||||
|
file.sputn(reinterpret_cast<const char*>(&h), sizeof(header));
|
||||||
|
}
|
||||||
|
|
||||||
inline image read_from_file(std::string const& filename){
|
inline image read_from_file(std::string const& filename){
|
||||||
std::filebuf file;
|
std::filebuf file;
|
||||||
file.open(filename, std::ios_base::in);
|
file.open(filename, std::ios_base::in);
|
||||||
|
@ -60,5 +80,4 @@ namespace jcmp {
|
||||||
file.sgetn(reinterpret_cast<char*>(image.data.data()), image.data.size() * sizeof(coefficient));
|
file.sgetn(reinterpret_cast<char*>(image.data.data()), image.data.size() * sizeof(coefficient));
|
||||||
return image;
|
return image;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
#include <includes.hpp>
|
#include <includes.hpp>
|
||||||
|
#include <utilities.hpp>
|
||||||
|
|
||||||
#include "compressed_image.hpp"
|
#include "compressed_image.hpp"
|
||||||
namespace jcmp{
|
namespace jcmp{
|
||||||
|
@ -21,22 +22,63 @@ struct gen{
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
int main(){
|
void test_correctness(){
|
||||||
const int w = 1024, h = 512;
|
const int w = 1024, h = 512;
|
||||||
srand(time(0));
|
|
||||||
|
|
||||||
std::vector<jcmp::coefficient> v(w*h / 100);
|
std::vector<jcmp::coefficient> v(w*h / 100);
|
||||||
std::generate(v.begin(), v.end(), gen{w, 0, 0});
|
std::generate(v.begin(), v.end(), gen{w, 0, 0});
|
||||||
|
|
||||||
jcmp::image i(w, h, std::move(v));
|
{ // iterator method
|
||||||
|
jcmp::write_to_file({w, h}, v.begin(), v.end(), "test.jcmp");
|
||||||
|
auto j = jcmp::read_from_file("test.jcmp");
|
||||||
|
|
||||||
jcmp::write_to_file(i, "test.jcmp");
|
assert(w == j.header.width);
|
||||||
auto j = jcmp::read_from_file("test.jcmp");
|
assert(h == j.header.height);
|
||||||
|
assert(v == j.data);
|
||||||
|
}
|
||||||
|
|
||||||
assert(w == j.header.width);
|
{ // copy method
|
||||||
assert(h == j.header.height);
|
jcmp::image i(w, h, std::move(v));
|
||||||
assert(i.data.size() == j.data.size());
|
|
||||||
assert(i.data == j.data);
|
|
||||||
|
|
||||||
std::cout << "Test succeeded" << std::endl;
|
jcmp::write_to_file(i, "test.jcmp");
|
||||||
|
auto j = jcmp::read_from_file("test.jcmp");
|
||||||
|
|
||||||
|
assert(w == j.header.width);
|
||||||
|
assert(h == j.header.height);
|
||||||
|
assert(i.data == j.data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_speed(){
|
||||||
|
const int w = 4000, h = 8000;
|
||||||
|
std::vector<jcmp::coefficient> input(w*h / 20);
|
||||||
|
std::generate(input.begin(), input.end(), gen{w, 0, 0});
|
||||||
|
|
||||||
|
for(int i = 0; i < 10; ++i){
|
||||||
|
{ timer t("stream");
|
||||||
|
jcmp::write_to_file({w, h}, input.begin(), input.end(), "stream.jcmp");
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<jcmp::coefficient> copy(w*h / 20);
|
||||||
|
std::copy(input.begin(), input.end(), copy.begin());
|
||||||
|
|
||||||
|
{ timer t("move");
|
||||||
|
jcmp::image i(w, h, std::move(copy));
|
||||||
|
jcmp::write_to_file(i, "move.jcmp");
|
||||||
|
}
|
||||||
|
|
||||||
|
{ timer t("copy");
|
||||||
|
jcmp::image i(w, h, input);
|
||||||
|
jcmp::write_to_file(i, "copy.jcmp");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(){
|
||||||
|
srand(time(0));
|
||||||
|
|
||||||
|
test_correctness();
|
||||||
|
std::cout << "Test succeeded" << std::endl;
|
||||||
|
|
||||||
|
test_speed();
|
||||||
|
std::cout << "Test completed" << std::endl;
|
||||||
}
|
}
|
||||||
|
|
0
wavelet/file_test.cpp
Normal file
0
wavelet/file_test.cpp
Normal file
0
wavelet/wavelet2.hpp
Normal file
0
wavelet/wavelet2.hpp
Normal file
0
wavelet/wavelet_constants.hpp
Normal file
0
wavelet/wavelet_constants.hpp
Normal file
Reference in a new issue