PuzzleD

D Interface to libpuzzle
git clone git://xatko.vsos.ethz.ch/PuzzleD.git
Log | Files | Refs

commit 45a2ad4060d9b717c5ad0ea68a94131c58dfb9ee
parent 1d11a26ceb1458791883218a2889d0e9e802900e
Author: Dominik Schmidt <das1993@hotmail.com>
Date:   Thu, 27 Aug 2015 12:40:38 +0200

Move puzzle.d in src/ subdirectory

Diffstat:
puzzle.d | 435-------------------------------------------------------------------------------
src/puzzle.d | 435+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 435 insertions(+), 435 deletions(-)

diff --git a/puzzle.d b/puzzle.d @@ -1,435 +0,0 @@ -module puzzle; - -version(unittest){ - static immutable string testimage="iVBORw0KGgoAAAANSUhEUgAAAE4AAAASAQMAAADPKHrSAAAABlBMVEX///8AAABVwtN+AAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH3wgbCSsvSqRkugAAAGxJREFUCNdjYEAAGyYDMH2AgUGCSQDMdAAyGTCZDQwSbLL9yRL//jkrANVKHDPk6OlxEwBpcxHkkJCAMwUE3H9AmQYGbkATlEDMhAQwE6htxqFDTgIM9s+3tz549+/f5wcg01kQLkJi8jHgAQA3KhrFG5DorwAAAABJRU5ErkJggg=="; - ubyte[] testimagedat(){ - import std.base64; - return cast(ubyte[])Base64.decode(testimage); - } -} - -extern(C){ - struct PuzzleContext { - uint puzzle_max_width; - uint puzzle_max_height; - uint puzzle_lambdas; - double puzzle_p_ratio; - double puzzle_noise_cutoff; - double puzzle_contrast_barrier_for_cropping; - double puzzle_max_cropping_ratio; - int puzzle_enable_autocrop; - ulong magic; - }; - struct PuzzleDvec { - size_t sizeof_vec; - size_t sizeof_compressed_vec; - double *vec; - }; - - struct PuzzleCvec { - size_t sizeof_vec; - char *vec; - }; - struct PuzzleCompressedCvec { - size_t sizeof_compressed_vec; - ubyte *vec; -}; - - void - puzzle_init_context(PuzzleContext *context); - - void - puzzle_free_context(PuzzleContext *context); - - void - puzzle_init_cvec(PuzzleContext *context, PuzzleCvec *cvec); - - void - puzzle_init_dvec(PuzzleContext *context, PuzzleDvec *dvec); - - int - puzzle_fill_dvec_from_file(PuzzleContext *context, PuzzleDvec * dvec, const char *file); - - int - puzzle_fill_cvec_from_file(PuzzleContext *context, PuzzleCvec * cvec, const char *file); - - int - puzzle_fill_dvec_from_mem(PuzzleContext *context, PuzzleDvec * dvec, const void *mem, - size_t size); - - int - puzzle_fill_cvec_from_mem(PuzzleContext *context, PuzzleCvec * cvec, const void *mem, - size_t size); - - int - puzzle_fill_cvec_from_dvec(PuzzleContext *context, PuzzleCvec * cvec, - const PuzzleDvec *dvec); - - void - puzzle_free_cvec(PuzzleContext *context, PuzzleCvec *cvec); - - void - puzzle_free_dvec(PuzzleContext *context, PuzzleDvec *dvec); - - void - puzzle_init_compressed_cvec(PuzzleContext *context, - PuzzleCompressedCvec * compressed_cvec); - - void - puzzle_free_compressed_cvec(PuzzleContext *context, - PuzzleCompressedCvec * compressed_cvec); - - int - puzzle_compress_cvec(PuzzleContext *context, PuzzleCompressedCvec * compressed_cvec, - const PuzzleCvec * cvec); - - int - puzzle_uncompress_cvec(PuzzleContext *context, PuzzleCompressedCvec * compressed_cvec, - const(PuzzleCvec *) cvec); - - double - puzzle_vector_normalized_distance(PuzzleContext *context, const PuzzleCvec * cvec1, - const PuzzleCvec * cvec2, int fix_for_texts); - -} -import std.string; - -static bool valid(in PuzzleContext ctx){ - return (ctx.magic==0xdeadbeef); -} -static bool valid(in PuzzleContext *ctx){ - return (ctx!=null && valid(*ctx)); -} - -class PuzzleException : Exception{ - pure nothrow @safe this(string msg, string file = __FILE__, size_t line = __LINE__, Throwable next = null){ - super(msg,file,line,next); - } -} - -/** - * PuzzleContext wrapper - * - * Has to be inititialized with `Puzzle.initialize();` - * and frees the context on destruction. - * - * Be careful, when you stack-allocate it, the object gets - * rendered unusable once the scope has been left. - * - */ -struct Puzzle{ - PuzzleContext ctx; - /** - * Initializes the Puzzle-context. - * - */ - void initialize() - out{ - assert(ctx.valid()); - } - body{ - puzzle_init_context(&ctx); - } - - ///Frees the PuzzleContext (If there is one) - ~this(){ - if(ctx.valid){ - puzzle_free_context(&ctx); - } - } - /** - * Returns a newly allocated DVec-Structure - * - * $(DDOC_SEE_ALSO struct DVec) - * - */ - DVec dvec(){ - return DVec(&ctx); - } - - /** - * Returns a newly allocated CVec-Structure - * - * $(DDOC_SEE_ALSO struct CVec) - * - */ - CVec cvec(){ - return CVec(&ctx); - } -} -/// -unittest{ - Puzzle p; - assert(!p.ctx.valid); - p.initialize(); - assert(p.ctx.valid); - - DVec d=p.dvec(); - assert(d.ctx.valid); - - DVec c=p.dvec(); - assert(c.ctx.valid); -} - -/** - * Wraps the PuzzleDVec-structure - * - */ -struct DVec{ - PuzzleDvec vec; - PuzzleContext *ctx; - @disable this(); - - ///Initializes the DVec - this(PuzzleContext *ctx) - in{ - assert(ctx.valid(), "Context invalid"); - } - body{ - this.ctx=ctx; - puzzle_init_dvec(ctx,&vec); - } - - ///Frees the DVec (If it has been allocated by the library); - ~this(){ - if(ctx!=null){ - puzzle_free_dvec(ctx,&vec); - } - } - - /** - * Generates the vector from a file. - * Params: - * f = File to read the data from. - * Throws: - * PuzzleException if the puzzle-function fails to load the image - */ - void load(string f){ - if(puzzle_fill_dvec_from_file(ctx, &vec, toStringz(f))!=0){ - throw new PuzzleException("Couldn't read from file"); - } - } - - /** - * Generates the vector from memory - * Params: - * mem = The memory of an Image - * Throws: - * PuzzleException if the memory couldn't be read. - */ - void load(void mem[]){ - if(puzzle_fill_dvec_from_mem(ctx, &vec, cast(void*)mem, mem.length)!=0){ - throw new PuzzleException("Couldn't read from memory"); - } - } - /** - * Get the CVec derived from this DVector. - * Returns: - * The corresponding(and comparable) CVector to this DVector - */ - CVec cvec(){ - CVec cvec=CVec(ctx); - puzzle_fill_cvec_from_dvec(ctx,&cvec.vec,&vec); - return cvec; - } - - /** - * Get the length of the vector - * Returns: - * The length of the vector - */ - @safe @nogc @property size_t length(){ - return vec.sizeof_vec; - } -} - -/// -struct CVec{ - PuzzleCvec vec; - PuzzleContext *ctx; - @disable this(); - this(ref CVec_Compressed c){ - this(c.ctx); - puzzle_uncompress_cvec(ctx, &c.vec, &vec); - } - /** - * Generates a Vector by hand. - * - * This can be used to save a Vector and reload it again. - * - * Params: - * a = The array of data to fill the vector with. - */ - @nogc pure nothrow this(byte[] a){ - this(cast(char*)a.ptr, a.length); - } - ///ditto - @nogc pure nothrow this(char *a, size_t length){ - vec.vec=a; - vec.sizeof_vec=length; - } - - /// - unittest{ - Puzzle p; - p.initialize(); - CVec c=p.cvec(); - - c.load(testimagedat()); - assert(c.length>0); - - CVec c2=CVec(c.vec.vec,c.length); - assert(std.math.approxEqual(c.compare(c2),0)); - } - - ///Initializes a Vector - this(PuzzleContext *ctx) - in{ - assert(ctx.valid(), "Context invalid"); - } - body{ - this.ctx=ctx; - puzzle_init_cvec(ctx,&vec); - } - ///Frees the vector(If it was allocated by the library) - ~this(){ - if(ctx!=null){ - puzzle_free_cvec(ctx,&vec); - } - } - - /** - * Generates the vector from a file. - * Params: - * f = File to read the data from. - * Throws: - * PuzzleException if the puzzle-function fails to load the image - */ - void load(string f){ - if(puzzle_fill_cvec_from_file(ctx, &vec, toStringz(f))!=0){ - throw new PuzzleException("Couldn't read from file"); - } - } - - /** - * Generates the vector from memory - * Params: - * mem = The memory of an Image - * Throws: - * PuzzleException if the memory couldn't be read. - */ - void load(void mem[]){ - if(puzzle_fill_cvec_from_mem(ctx, &vec, cast(void*)mem, mem.length)!=0){ - throw new PuzzleException("Couldn't read from memory"); - } - } - - /** - * Compare two CVectors. - * Params: - * b = The second vector to compare to - * hasText = Wether one of the images had any text in it. - * Returns: - * The distance of both vectors. - */ - double compare(in ref CVec b, bool hasText=false){ - return puzzle_vector_normalized_distance(ctx,&vec,&b.vec,(hasText) ? 1 : 0); - } - - - /** - * Compresses a CVector - * Returns: - * A compressed CVector - */ - CVec_Compressed compress(){ - return CVec_Compressed(this); - } - - /** - * Get the length of the vector - * Returns: - * The length of the vector - */ - @nogc @safe @property size_t length(){ - return vec.sizeof_vec; - } -} - -/// -unittest{ - Puzzle p; - p.initialize(); - CVec c=p.cvec(); - c.load(testimagedat()); - - assert(std.math.approxEqual(c.compare(c),0)); -} - -///A compressed CVector -struct CVec_Compressed{ - PuzzleCompressedCvec vec; - PuzzleContext *ctx; - @disable this(); - - ///Generates a compressed CVector corresponding to c - this(ref CVec c){ - this(c.ctx); - puzzle_compress_cvec(ctx, &vec, &c.vec); - } - - /** - * Generates a Vector by hand. - * - * Params: - * a = The array of data to fill the vector with. - */ - this(ubyte[] a){ - this(a.ptr,a.length); - } - - ///ditto - this(ubyte* a, size_t length){ - vec.vec=a; - vec.sizeof_compressed_vec=length; - } - - ///Allocates a new Compressed CVector in the library - this(PuzzleContext *ctx) - in{ - assert(ctx.valid(), "Context invalid"); - } - body{ - this.ctx=ctx; - puzzle_init_compressed_cvec(ctx,&vec); - } - - ///Frees the Vector, if it was allocated by the library - ~this(){ - if(ctx!=null){ - puzzle_free_compressed_cvec(ctx,&vec); - } - } - - ///Returns the corresponding uncompressed CVector - CVec uncompress(){ - return CVec(this); - } - - /// - @safe @nogc @property size_t length(){ - return vec.sizeof_compressed_vec; - } -} - -/// -unittest{ - Puzzle p; - p.initialize(); - CVec c=p.cvec(); - c.load(testimagedat()); - CVec_Compressed cc=c.compress(); - CVec c2=cc.uncompress(); - - assert(std.math.approxEqual(c.compare(c2),0)); -} diff --git a/src/puzzle.d b/src/puzzle.d @@ -0,0 +1,435 @@ +module puzzle; + +version(unittest){ + static immutable string testimage="iVBORw0KGgoAAAANSUhEUgAAAE4AAAASAQMAAADPKHrSAAAABlBMVEX///8AAABVwtN+AAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH3wgbCSsvSqRkugAAAGxJREFUCNdjYEAAGyYDMH2AgUGCSQDMdAAyGTCZDQwSbLL9yRL//jkrANVKHDPk6OlxEwBpcxHkkJCAMwUE3H9AmQYGbkATlEDMhAQwE6htxqFDTgIM9s+3tz549+/f5wcg01kQLkJi8jHgAQA3KhrFG5DorwAAAABJRU5ErkJggg=="; + ubyte[] testimagedat(){ + import std.base64; + return cast(ubyte[])Base64.decode(testimage); + } +} + +extern(C){ + struct PuzzleContext { + uint puzzle_max_width; + uint puzzle_max_height; + uint puzzle_lambdas; + double puzzle_p_ratio; + double puzzle_noise_cutoff; + double puzzle_contrast_barrier_for_cropping; + double puzzle_max_cropping_ratio; + int puzzle_enable_autocrop; + ulong magic; + }; + struct PuzzleDvec { + size_t sizeof_vec; + size_t sizeof_compressed_vec; + double *vec; + }; + + struct PuzzleCvec { + size_t sizeof_vec; + char *vec; + }; + struct PuzzleCompressedCvec { + size_t sizeof_compressed_vec; + ubyte *vec; +}; + + void + puzzle_init_context(PuzzleContext *context); + + void + puzzle_free_context(PuzzleContext *context); + + void + puzzle_init_cvec(PuzzleContext *context, PuzzleCvec *cvec); + + void + puzzle_init_dvec(PuzzleContext *context, PuzzleDvec *dvec); + + int + puzzle_fill_dvec_from_file(PuzzleContext *context, PuzzleDvec * dvec, const char *file); + + int + puzzle_fill_cvec_from_file(PuzzleContext *context, PuzzleCvec * cvec, const char *file); + + int + puzzle_fill_dvec_from_mem(PuzzleContext *context, PuzzleDvec * dvec, const void *mem, + size_t size); + + int + puzzle_fill_cvec_from_mem(PuzzleContext *context, PuzzleCvec * cvec, const void *mem, + size_t size); + + int + puzzle_fill_cvec_from_dvec(PuzzleContext *context, PuzzleCvec * cvec, + const PuzzleDvec *dvec); + + void + puzzle_free_cvec(PuzzleContext *context, PuzzleCvec *cvec); + + void + puzzle_free_dvec(PuzzleContext *context, PuzzleDvec *dvec); + + void + puzzle_init_compressed_cvec(PuzzleContext *context, + PuzzleCompressedCvec * compressed_cvec); + + void + puzzle_free_compressed_cvec(PuzzleContext *context, + PuzzleCompressedCvec * compressed_cvec); + + int + puzzle_compress_cvec(PuzzleContext *context, PuzzleCompressedCvec * compressed_cvec, + const PuzzleCvec * cvec); + + int + puzzle_uncompress_cvec(PuzzleContext *context, PuzzleCompressedCvec * compressed_cvec, + const(PuzzleCvec *) cvec); + + double + puzzle_vector_normalized_distance(PuzzleContext *context, const PuzzleCvec * cvec1, + const PuzzleCvec * cvec2, int fix_for_texts); + +} +import std.string; + +static bool valid(in PuzzleContext ctx){ + return (ctx.magic==0xdeadbeef); +} +static bool valid(in PuzzleContext *ctx){ + return (ctx!=null && valid(*ctx)); +} + +class PuzzleException : Exception{ + pure nothrow @safe this(string msg, string file = __FILE__, size_t line = __LINE__, Throwable next = null){ + super(msg,file,line,next); + } +} + +/** + * PuzzleContext wrapper + * + * Has to be inititialized with `Puzzle.initialize();` + * and frees the context on destruction. + * + * Be careful, when you stack-allocate it, the object gets + * rendered unusable once the scope has been left. + * + */ +struct Puzzle{ + PuzzleContext ctx; + /** + * Initializes the Puzzle-context. + * + */ + void initialize() + out{ + assert(ctx.valid()); + } + body{ + puzzle_init_context(&ctx); + } + + ///Frees the PuzzleContext (If there is one) + ~this(){ + if(ctx.valid){ + puzzle_free_context(&ctx); + } + } + /** + * Returns a newly allocated DVec-Structure + * + * $(DDOC_SEE_ALSO struct DVec) + * + */ + DVec dvec(){ + return DVec(&ctx); + } + + /** + * Returns a newly allocated CVec-Structure + * + * $(DDOC_SEE_ALSO struct CVec) + * + */ + CVec cvec(){ + return CVec(&ctx); + } +} +/// +unittest{ + Puzzle p; + assert(!p.ctx.valid); + p.initialize(); + assert(p.ctx.valid); + + DVec d=p.dvec(); + assert(d.ctx.valid); + + DVec c=p.dvec(); + assert(c.ctx.valid); +} + +/** + * Wraps the PuzzleDVec-structure + * + */ +struct DVec{ + PuzzleDvec vec; + PuzzleContext *ctx; + @disable this(); + + ///Initializes the DVec + this(PuzzleContext *ctx) + in{ + assert(ctx.valid(), "Context invalid"); + } + body{ + this.ctx=ctx; + puzzle_init_dvec(ctx,&vec); + } + + ///Frees the DVec (If it has been allocated by the library); + ~this(){ + if(ctx!=null){ + puzzle_free_dvec(ctx,&vec); + } + } + + /** + * Generates the vector from a file. + * Params: + * f = File to read the data from. + * Throws: + * PuzzleException if the puzzle-function fails to load the image + */ + void load(string f){ + if(puzzle_fill_dvec_from_file(ctx, &vec, toStringz(f))!=0){ + throw new PuzzleException("Couldn't read from file"); + } + } + + /** + * Generates the vector from memory + * Params: + * mem = The memory of an Image + * Throws: + * PuzzleException if the memory couldn't be read. + */ + void load(void mem[]){ + if(puzzle_fill_dvec_from_mem(ctx, &vec, cast(void*)mem, mem.length)!=0){ + throw new PuzzleException("Couldn't read from memory"); + } + } + /** + * Get the CVec derived from this DVector. + * Returns: + * The corresponding(and comparable) CVector to this DVector + */ + CVec cvec(){ + CVec cvec=CVec(ctx); + puzzle_fill_cvec_from_dvec(ctx,&cvec.vec,&vec); + return cvec; + } + + /** + * Get the length of the vector + * Returns: + * The length of the vector + */ + @safe @nogc @property size_t length(){ + return vec.sizeof_vec; + } +} + +/// +struct CVec{ + PuzzleCvec vec; + PuzzleContext *ctx; + @disable this(); + this(ref CVec_Compressed c){ + this(c.ctx); + puzzle_uncompress_cvec(ctx, &c.vec, &vec); + } + /** + * Generates a Vector by hand. + * + * This can be used to save a Vector and reload it again. + * + * Params: + * a = The array of data to fill the vector with. + */ + @nogc pure nothrow this(byte[] a){ + this(cast(char*)a.ptr, a.length); + } + ///ditto + @nogc pure nothrow this(char *a, size_t length){ + vec.vec=a; + vec.sizeof_vec=length; + } + + /// + unittest{ + Puzzle p; + p.initialize(); + CVec c=p.cvec(); + + c.load(testimagedat()); + assert(c.length>0); + + CVec c2=CVec(c.vec.vec,c.length); + assert(std.math.approxEqual(c.compare(c2),0)); + } + + ///Initializes a Vector + this(PuzzleContext *ctx) + in{ + assert(ctx.valid(), "Context invalid"); + } + body{ + this.ctx=ctx; + puzzle_init_cvec(ctx,&vec); + } + ///Frees the vector(If it was allocated by the library) + ~this(){ + if(ctx!=null){ + puzzle_free_cvec(ctx,&vec); + } + } + + /** + * Generates the vector from a file. + * Params: + * f = File to read the data from. + * Throws: + * PuzzleException if the puzzle-function fails to load the image + */ + void load(string f){ + if(puzzle_fill_cvec_from_file(ctx, &vec, toStringz(f))!=0){ + throw new PuzzleException("Couldn't read from file"); + } + } + + /** + * Generates the vector from memory + * Params: + * mem = The memory of an Image + * Throws: + * PuzzleException if the memory couldn't be read. + */ + void load(void mem[]){ + if(puzzle_fill_cvec_from_mem(ctx, &vec, cast(void*)mem, mem.length)!=0){ + throw new PuzzleException("Couldn't read from memory"); + } + } + + /** + * Compare two CVectors. + * Params: + * b = The second vector to compare to + * hasText = Wether one of the images had any text in it. + * Returns: + * The distance of both vectors. + */ + double compare(in ref CVec b, bool hasText=false){ + return puzzle_vector_normalized_distance(ctx,&vec,&b.vec,(hasText) ? 1 : 0); + } + + + /** + * Compresses a CVector + * Returns: + * A compressed CVector + */ + CVec_Compressed compress(){ + return CVec_Compressed(this); + } + + /** + * Get the length of the vector + * Returns: + * The length of the vector + */ + @nogc @safe @property size_t length(){ + return vec.sizeof_vec; + } +} + +/// +unittest{ + Puzzle p; + p.initialize(); + CVec c=p.cvec(); + c.load(testimagedat()); + + assert(std.math.approxEqual(c.compare(c),0)); +} + +///A compressed CVector +struct CVec_Compressed{ + PuzzleCompressedCvec vec; + PuzzleContext *ctx; + @disable this(); + + ///Generates a compressed CVector corresponding to c + this(ref CVec c){ + this(c.ctx); + puzzle_compress_cvec(ctx, &vec, &c.vec); + } + + /** + * Generates a Vector by hand. + * + * Params: + * a = The array of data to fill the vector with. + */ + this(ubyte[] a){ + this(a.ptr,a.length); + } + + ///ditto + this(ubyte* a, size_t length){ + vec.vec=a; + vec.sizeof_compressed_vec=length; + } + + ///Allocates a new Compressed CVector in the library + this(PuzzleContext *ctx) + in{ + assert(ctx.valid(), "Context invalid"); + } + body{ + this.ctx=ctx; + puzzle_init_compressed_cvec(ctx,&vec); + } + + ///Frees the Vector, if it was allocated by the library + ~this(){ + if(ctx!=null){ + puzzle_free_compressed_cvec(ctx,&vec); + } + } + + ///Returns the corresponding uncompressed CVector + CVec uncompress(){ + return CVec(this); + } + + /// + @safe @nogc @property size_t length(){ + return vec.sizeof_compressed_vec; + } +} + +/// +unittest{ + Puzzle p; + p.initialize(); + CVec c=p.cvec(); + c.load(testimagedat()); + CVec_Compressed cc=c.compress(); + CVec c2=cc.uncompress(); + + assert(std.math.approxEqual(c.compare(c2),0)); +}