Browse Source

Added a second way to save an image

master
Joshua Moerman 11 years ago
parent
commit
41869d8cb0
  1. 28
      include/utilities.hpp
  2. 21
      wavelet/compressed_image.hpp
  3. 62
      wavelet/compressed_image_test.cpp
  4. 0
      wavelet/file_test.cpp
  5. 0
      wavelet/wavelet2.hpp
  6. 0
      wavelet/wavelet_constants.hpp

28
include/utilities.hpp

@ -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;
}
};

21
wavelet/compressed_image.hpp

@ -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;
} }
} }

62
wavelet/compressed_image_test.cpp

@ -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");
assert(w == j.header.width);
assert(h == j.header.height);
assert(v == j.data);
}
{ // copy method
jcmp::image i(w, h, std::move(v));
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});
jcmp::write_to_file(i, "test.jcmp"); for(int i = 0; i < 10; ++i){
auto j = jcmp::read_from_file("test.jcmp"); { 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());
assert(w == j.header.width); { timer t("move");
assert(h == j.header.height); jcmp::image i(w, h, std::move(copy));
assert(i.data.size() == j.data.size()); jcmp::write_to_file(i, "move.jcmp");
assert(i.data == j.data); }
{ 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; std::cout << "Test succeeded" << std::endl;
test_speed();
std::cout << "Test completed" << std::endl;
} }

0
wavelet/file_test.cpp

0
wavelet/wavelet2.hpp

0
wavelet/wavelet_constants.hpp