internal static async Task <DitherResult> ditherFile(StorageFile file, uint outputWidth, uint outputHeight) { int pointCount = 0; dithermode dm = dithermode.SierraLite; DitherResult result = new DitherResult(); errorTable = new float[outputWidth * outputHeight]; using (IRandomAccessStream stream = await file.OpenReadAsync()) { var decoder = await BitmapDecoder.CreateAsync(stream); var bitmapTransform = new BitmapTransform { ScaledWidth = outputWidth, ScaledHeight = outputHeight }; var thumbnailColorProvider = await decoder.GetPixelDataAsync( BitmapPixelFormat.Rgba8, BitmapAlphaMode.Straight, bitmapTransform, ExifOrientationMode.IgnoreExifOrientation, ColorManagementMode.DoNotColorManage); var thumbnailColorArray = thumbnailColorProvider.DetachPixelData(); result.width = outputWidth; result.height = outputHeight; var thumbnailBWArray = new byte[result.width * result.height]; var thumbnailDitheredArray = new byte[result.width * result.height]; // First Pass, average each triad for (int i = 0; i < thumbnailBWArray.Length; i++) { var r = thumbnailColorArray[i * 4 + 0]; var g = thumbnailColorArray[i * 4 + 1]; var b = thumbnailColorArray[i * 4 + 2]; thumbnailBWArray[i] = getLuminance(r, g, b); } int newValue; float error; for (var pass = 0; pass < 1; pass++) { for (int x = 0; x < result.width; x++) { for (int y = 0; y < result.height; y++) { int index = y * (int)result.width + x; newValue = thumbnailBWArray[index] + (int)errorTable[index]; if (newValue >= kBWThreshold) { // Set white error = newValue - 255; thumbnailDitheredArray[index] = 255; } else { // Set Black pointCount++; error = newValue; thumbnailDitheredArray[index] = 0; } switch (dm) { case dithermode.FloydSteinberg: { if (x + 1 < result.width) { errorTable[index + 1] += (error * 7 / 16); } if (y + 1 < result.height) { if (x - 1 >= 0) { errorTable[index + result.width - 1] += (error * 3 / 16); } errorTable[index + result.width] += (error * 5 / 16); if (x + 1 < result.width) { errorTable[index + result.width + 1] += (error * 1 / 16); } } } break; case dithermode.Sierra2: { if (x + 1 < result.width) { errorTable[index + 1] += (error * 4 / 16); } if (x + 2 < result.width) { errorTable[index + 2] += (error * 3 / 16); } if (y + 1 < result.height) { if (x - 2 >= 0) { errorTable[index + result.width - 2] += (error * 1 / 16); } if (x - 1 >= 0) { errorTable[index + result.width - 1] += (error * 2 / 16); } errorTable[index + result.width] += (error * 3 / 16); if (x + 1 < result.width) { errorTable[index + result.width + 1] += (error * 2 / 16); } if (x + 2 < result.width) { errorTable[index + result.width + 2] += (error * 1 / 16); } } } break; case dithermode.SierraLite: { if (x + 1 < result.width) { errorTable[index + 1] += (error * 2 / 4); } if (y + 1 < result.height) { if (x - 1 >= 0) { errorTable[index + result.width - 1] += (error * 1 / 4); } errorTable[index + result.width] += (error * 1 / 4); } } break; } } } } Debug.WriteLine("Point count: " + pointCount); result.pixels = thumbnailDitheredArray; return(result); } }
internal static async Task<DitherResult> ditherFile(StorageFile file, uint outputWidth, uint outputHeight) { int pointCount = 0; dithermode dm = dithermode.SierraLite; DitherResult result = new DitherResult(); errorTable = new float[outputWidth * outputHeight]; using (IRandomAccessStream stream = await file.OpenReadAsync()) { var decoder = await BitmapDecoder.CreateAsync(stream); var bitmapTransform = new BitmapTransform { ScaledWidth = outputWidth, ScaledHeight = outputHeight }; var thumbnailColorProvider = await decoder.GetPixelDataAsync( BitmapPixelFormat.Rgba8, BitmapAlphaMode.Straight, bitmapTransform, ExifOrientationMode.IgnoreExifOrientation, ColorManagementMode.DoNotColorManage); var thumbnailColorArray = thumbnailColorProvider.DetachPixelData(); result.width = outputWidth; result.height = outputHeight; var thumbnailBWArray = new byte[result.width * result.height]; var thumbnailDitheredArray = new byte[result.width * result.height]; // First Pass, average each triad for (int i = 0; i < thumbnailBWArray.Length; i++) { var r = thumbnailColorArray[i * 4 + 0]; var g = thumbnailColorArray[i * 4 + 1]; var b = thumbnailColorArray[i * 4 + 2]; thumbnailBWArray[i] = getLuminance(r, g, b); } int newValue; float error; for (var pass = 0; pass < 1; pass++) { for (int x = 0; x < result.width; x++) { for (int y = 0; y < result.height; y++) { int index = y * (int)result.width + x; newValue = thumbnailBWArray[index] + (int)errorTable[index]; if (newValue >= kBWThreshold) { // Set white error = newValue - 255; thumbnailDitheredArray[index] = 255; } else { // Set Black pointCount++; error = newValue; thumbnailDitheredArray[index] = 0; } switch (dm) { case dithermode.FloydSteinberg: { if (x + 1 < result.width) { errorTable[index + 1] += (error * 7 / 16); } if (y + 1 < result.height) { if (x - 1 >= 0) { errorTable[index + result.width - 1] += (error * 3 / 16); } errorTable[index + result.width] += (error * 5 / 16); if (x + 1 < result.width) { errorTable[index + result.width + 1] += (error * 1 / 16); } } } break; case dithermode.Sierra2: { if (x + 1 < result.width) { errorTable[index + 1] += (error * 4 / 16); } if (x + 2 < result.width) { errorTable[index + 2] += (error * 3 / 16); } if (y + 1 < result.height) { if (x - 2 >= 0) { errorTable[index + result.width - 2] += (error * 1 / 16); } if (x - 1 >= 0) { errorTable[index + result.width - 1] += (error * 2 / 16); } errorTable[index + result.width] += (error * 3 / 16); if (x + 1 < result.width) { errorTable[index + result.width + 1] += (error * 2 / 16); } if (x + 2 < result.width) { errorTable[index + result.width + 2] += (error * 1 / 16); } } } break; case dithermode.SierraLite: { if (x + 1 < result.width) { errorTable[index + 1] += (error * 2 / 4); } if (y + 1 < result.height) { if (x - 1 >= 0) { errorTable[index + result.width - 1] += (error * 1 / 4); } errorTable[index + result.width] += (error * 1 / 4); } } break; } } } } Debug.WriteLine("Point count: " + pointCount); result.pixels = thumbnailDitheredArray; return result; } }