public static void ProcessFile(string method, string filePath, Action <string> logger, Action <string> outFile) { var srcImg = SixLabors.ImageSharp.Image.Load <SixLabors.ImageSharp.PixelFormats.Rgba32>(filePath); void processSTB(CompressionMode mode, bool useAlpha, string ext) { var dstFileName = System.IO.Path.ChangeExtension(filePath, ext); dstFileName = System.IO.Path.Combine(NUnit.Framework.TestContext.CurrentContext.WorkDirectory, dstFileName); logger($"{dstFileName} with {mode}"); using (var stream = System.IO.File.OpenRead(filePath)) { var srcImage = new StbSharp.ImageReader().Read(stream); if (srcImage.Comp != 4) { return; // TODO: should convert RGB to RGBA } // flags bits: // 1 = dither // 2 = refine count (1 or 2) var bytes = StbDxt.stb_compress_dxt(srcImage, useAlpha, 2); var dstImage = Bitmap .Decompress(srcImage.Width, srcImage.Height, bytes, mode) .ToImageSharp(); dstImage.Save(dstFileName); outFile?.Invoke(dstFileName); } } void processNVidia(CompressionMode mode, string ext) { var dstFileName = System.IO.Path.ChangeExtension(filePath, ext); dstFileName = System.IO.Path.Combine(NUnit.Framework.TestContext.CurrentContext.WorkDirectory, dstFileName); logger($"{dstFileName} with {mode}"); srcImg.SquishImageWithNvidia(mode, logger).Save(dstFileName); outFile?.Invoke(dstFileName); } void processSquish(CompressionMode mode, CompressionOptions options, string ext) { var dstFileName = System.IO.Path.ChangeExtension(filePath, ext); dstFileName = System.IO.Path.Combine(NUnit.Framework.TestContext.CurrentContext.WorkDirectory, dstFileName); logger($"{dstFileName} with {mode}"); srcImg.SquishImage(mode, options, logger).Save(dstFileName); outFile?.Invoke(dstFileName); } if (method == "STB") { processSTB(CompressionMode.Dxt1, false, "Dx1-STB-NoAlpha.png"); processSTB(CompressionMode.Dxt1, true, "Dx1-STB.png"); processSTB(CompressionMode.Dxt3, true, "Dx3-STB.png"); processSTB(CompressionMode.Dxt5, true, "Dx5-STB.png"); return; } if (method == "NVIDIA") { processNVidia(CompressionMode.Dxt1, "Dx1-NVidia.png"); processNVidia(CompressionMode.Dxt3, "Dx3-NVidia.png"); processNVidia(CompressionMode.Dxt5, "Dx5-NVidia.png"); return; } var xflags = CompressionOptions.UseParallelProcessing | CompressionOptions.None; if (method == "RANGEFIT") { var flags = xflags | CompressionOptions.ColourRangeFit; processSquish(CompressionMode.Dxt1, flags, "Dx1-RangeFit.png"); processSquish(CompressionMode.Dxt3, flags, "Dx3-RangeFit.png"); processSquish(CompressionMode.Dxt5, flags, "Dx5-RangeFit.png"); return; } if (method == "CLUSTERFIT") { var flags = xflags | CompressionOptions.ColourClusterFit; processSquish(CompressionMode.Dxt1, flags, "Dx1-ClusterFit.png"); processSquish(CompressionMode.Dxt3, flags, "Dx3-ClusterFit.png"); processSquish(CompressionMode.Dxt5, flags, "Dx5-ClusterFit.png"); return; } if (method == "CLUSTERFIT_ALT") { var flags = xflags | CompressionOptions.ColourClusterFit; processSquish(CompressionMode.Dxt1, flags, "Dx1-ClusterFitAlt.png"); processSquish(CompressionMode.Dxt3, flags, "Dx3-ClusterFitAlt.png"); processSquish(CompressionMode.Dxt5, flags, "Dx5-ClusterFitAlt.png"); return; } if (method == "CLUSTERFIT_ITER") { var flags = xflags | CompressionOptions.ColourClusterFit; processSquish(CompressionMode.Dxt1, flags, "Dx1-ClusterFitIter.png"); processSquish(CompressionMode.Dxt3, flags, "Dx3-ClusterFitIter.png"); processSquish(CompressionMode.Dxt5, flags, "Dx5-ClusterFitIter.png"); return; } }
private static void ThreadProc(string f) { try { var sw = new Stopwatch(); if (!f.EndsWith(".bmp") && !f.EndsWith(".jpg") && !f.EndsWith(".png") && !f.EndsWith(".jpg") && !f.EndsWith(".psd") && !f.EndsWith(".pic") && !f.EndsWith(".tga")) { return; } Log(string.Empty); Log("{0} -- #{1}: Loading {2} into memory", DateTime.Now.ToLongTimeString(), filesProcessed, f); var data = File.ReadAllBytes(f); Log("----------------------------"); Log("Loading From Stream"); int x = 0, y = 0, comp = 0; int stbSharpPassed, stbNativePassed; byte[] parsed = new byte[0]; ParseTest( sw, (out int xx, out int yy, out int ccomp) => { using (var ms = new MemoryStream(data)) { var loader = new ImageReader(); var img = loader.Read(ms); parsed = img.Data; xx = img.Width; yy = img.Height; ccomp = img.SourceComp; x = xx; y = yy; comp = ccomp; return(parsed); } }, (out int xx, out int yy, out int ccomp) => { using (var ms = new MemoryStream(data)) { return(Native.load_from_stream(ms, out xx, out yy, out ccomp, StbImage.STBI_default)); } }, out stbSharpPassed, out stbNativePassed ); stbSharpLoadingFromStream += stbSharpPassed; stbNativeLoadingFromStream += stbNativePassed; Log("Loading from memory"); ParseTest( sw, (out int xx, out int yy, out int ccomp) => { var img = StbImage.LoadFromMemory(data); var res = img.Data; xx = img.Width; yy = img.Height; ccomp = img.SourceComp; x = xx; y = yy; comp = ccomp; return(res); }, (out int xx, out int yy, out int ccomp) => Native.load_from_memory(data, out xx, out yy, out ccomp, StbImage.STBI_default), out stbSharpPassed, out stbNativePassed ); stbSharpLoadingFromMemory += stbSharpPassed; stbNativeLoadingFromMemory += stbNativePassed; var image = new Image { Comp = comp, Data = parsed, Width = x, Height = y }; for (var k = 0; k <= 4; ++k) { Log("Saving as {0} with StbSharp", FormatNames[k]); if (k < 4) { var writer = new ImageWriter(); WriteDelegate wd = null; switch (k) { case 0: wd = writer.WriteBmp; break; case 1: wd = writer.WriteTga; break; case 2: wd = writer.WriteHdr; break; case 3: wd = writer.WritePng; break; } byte[] save; BeginWatch(sw); using (var stream = new MemoryStream()) { wd(image, stream); save = stream.ToArray(); } var passed = EndWatch(sw); stbSharpWrite += passed; Log("Span: {0} ms", passed); Log("StbSharp Size: {0}", save.Length); Log("Saving as {0} with Stb.Native", FormatNames[k]); BeginWatch(sw); byte[] save2; using (var stream = new MemoryStream()) { Native.save_to_stream(parsed, x, y, comp, k, stream); save2 = stream.ToArray(); } passed = EndWatch(sw); stbNativeWrite += passed; Log("Span: {0} ms", passed); Log("Stb.Native Size: {0}", save2.Length); if (save.Length != save2.Length) { throw new Exception(string.Format("Inconsistent output size: StbSharp={0}, Stb.Native={1}", save.Length, save2.Length)); } for (var i = 0; i < save.Length; ++i) { if (save[i] != save2[i]) { throw new Exception(string.Format("Inconsistent data: index={0}, StbSharp={1}, Stb.Native={2}", i, (int)save[i], (int)save2[i])); } } } else { for (var qi = 0; qi < JpgQualities.Length; ++qi) { var quality = JpgQualities[qi]; Log("Saving as JPG with StbSharp with quality={0}", quality); byte[] save; BeginWatch(sw); using (var stream = new MemoryStream()) { var writer = new ImageWriter(); writer.WriteJpg(image, stream, quality); save = stream.ToArray(); } var passed = EndWatch(sw); stbSharpWrite += passed; Log("Span: {0} ms", passed); Log("StbSharp Size: {0}", save.Length); Log("Saving as JPG with Stb.Native with quality={0}", quality); BeginWatch(sw); byte[] save2; using (var stream = new MemoryStream()) { Native.save_to_jpg(parsed, x, y, comp, stream, quality); save2 = stream.ToArray(); } passed = EndWatch(sw); stbNativeWrite += passed; Log("Span: {0} ms", passed); Log("Stb.Native Size: {0}", save2.Length); if (save.Length != save2.Length) { throw new Exception(string.Format("Inconsistent output size: StbSharp={0}, Stb.Native={1}", save.Length, save2.Length)); } for (var i = 0; i < save.Length; ++i) { if (save[i] != save2[i]) { throw new Exception(string.Format("Inconsistent data: index={0}, StbSharp={1}, Stb.Native={2}", i, (int)save[i], (int)save2[i])); } } } } } // Compressing Log("Performing DXT compression with StbSharp"); image = StbImage.LoadFromMemory(data, StbImage.STBI_rgb_alpha); BeginWatch(sw); var compressed = StbDxt.stb_compress_dxt(image); stbSharpCompression += EndWatch(sw); Log("Performing DXT compression with Stb.Native"); BeginWatch(sw); var compressed2 = Native.compress_dxt(image.Data, image.Width, image.Height, true); stbNativeCompression += EndWatch(sw); if (compressed.Length != compressed2.Length) { throw new Exception(string.Format("Inconsistent output size: StbSharp={0}, Stb.Native={1}", compressed.Length, compressed2.Length)); } for (var i = 0; i < compressed.Length; ++i) { if (compressed[i] != compressed2[i]) { throw new Exception(string.Format("Inconsistent data: index={0}, StbSharp={1}, Stb.Native={2}", i, (int)compressed[i], (int)compressed2[i])); } } Log("Total StbSharp Loading From Stream Time: {0} ms", stbSharpLoadingFromStream); Log("Total Stb.Native Loading From Stream Time: {0} ms", stbNativeLoadingFromStream); Log("Total StbSharp Loading From memory Time: {0} ms", stbSharpLoadingFromMemory); Log("Total Stb.Native Loading From memory Time: {0} ms", stbNativeLoadingFromMemory); Log("Total StbSharp Write Time: {0} ms", stbSharpWrite); Log("Total Stb.Native Write Time: {0} ms", stbNativeWrite); Log("Total StbSharp Compression Time: {0} ms", stbSharpCompression); Log("Total Stb.Native Compression Time: {0} ms", stbNativeCompression); Log("GC Memory: {0}", GC.GetTotalMemory(true)); ++filesProcessed; Log(DateTime.Now.ToLongTimeString() + " -- " + " Files processed: " + filesProcessed); } catch (Exception ex) { Log("Error: " + ex.Message); } finally { --tasksStarted; } }