1 module main; 2 3 import std.stdio; 4 import std.file; 5 import std.conv; 6 import std.path; 7 import std.string; 8 import std.algorithm; 9 import gamut; 10 import core.stdc.stdlib: free; 11 12 void usage() 13 { 14 writeln(); 15 writeln("Usage: qoix\n"); 16 writeln(" This just run the test suite."); 17 writeln; 18 } 19 20 int main(string[] args) 21 { 22 // Encore all image in test suite in QOI 23 auto files = filter!`endsWith(a.name,".png")`(dirEntries("test-images",SpanMode.depth)); 24 25 double mean_encode_mpps = 0; 26 double mean_decode_mpps = 0; 27 double mean_bpp = 0; 28 29 long timeStart = getTickUs(); 30 31 int N = 0; 32 foreach(f; files) 33 { 34 writeln(); 35 36 ubyte[] originalImage = cast(ubyte[]) std.file.read(f); 37 38 double original_size_kb = originalImage.length / 1024.0; 39 writefln("*** image of size %.1f kb: %s", original_size_kb, f); 40 41 Image image; 42 image.loadFromMemory(originalImage); 43 if (image.isError) 44 throw new Exception(to!string(image.errorMessage)); 45 46 int width = image.width; 47 int height = image.height; 48 49 if (image.isError) 50 throw new Exception(to!string(image.errorMessage)); 51 52 ubyte[] qoix_encoded; 53 double qoix_encode_ms = measure( { qoix_encoded = image.saveToMemory(ImageFormat.QOIX); } ); 54 scope(exit) freeEncodedImage(qoix_encoded); 55 56 if (qoix_encoded is null) 57 throw new Exception("encoding failed"); 58 59 double qoix_size_kb = qoix_encoded.length / 1024.0; 60 double qoix_decode_ms = measure( { image.loadFromMemory(qoix_encoded); } ); 61 double qoix_encode_mpps = (width * height * 1.0e-6) / (qoix_encode_ms * 0.001); 62 double qoix_decode_mpps = (width * height * 1.0e-6) / (qoix_decode_ms * 0.001); 63 double bit_per_pixel = (qoix_encoded.length * 8.0) / (width * height); 64 65 mean_encode_mpps += qoix_encode_mpps; 66 mean_decode_mpps += qoix_decode_mpps; 67 mean_bpp += bit_per_pixel; 68 double size_vs_original = qoix_size_kb / original_size_kb; 69 70 writefln(" decode decode mpps encode mpps bit-per-pixel size reduction"); 71 writefln(" %8.2f ms %8.2f %8.2f %8.5f %9.1f kb %9.4f", qoix_decode_ms, qoix_decode_mpps, qoix_encode_mpps, bit_per_pixel, qoix_size_kb, size_vs_original); 72 N += 1; 73 74 // Check encoding is properly done. 75 { 76 Image image2; 77 image2.loadFromMemory(qoix_encoded); 78 assert(!image2.isError); 79 string path = "output/" ~ baseName(f) ~ ".png"; 80 image2.saveToFile(path, ImageFormat.PNG); 81 } 82 } 83 long timeTotal = getTickUs() - timeStart; 84 mean_encode_mpps /= N; 85 mean_decode_mpps /= N; 86 mean_bpp /= N; 87 writefln("\nTOTAL decode mpps encode mpps bit-per-pixel"); 88 writefln(" %8.2f %8.2f %8.5f", mean_decode_mpps, mean_encode_mpps, mean_bpp); 89 90 91 double totalSecs = timeTotal / 1000000.0; 92 writefln("\nTOTAL time = %s secs\n", totalSecs); 93 94 return 0; 95 } 96 97 long getTickUs() nothrow @nogc 98 { 99 import core.time; 100 return convClockFreq(MonoTime.currTime.ticks, MonoTime.ticksPerSecond, 1_000_000); 101 } 102 103 104 105 double measure(void delegate() nothrow @nogc dg) nothrow @nogc 106 { 107 long A = getTickUs(); 108 dg(); 109 long B = getTickUs(); 110 return cast(double)( (B - A) / 1000.0 ); 111 }