public static async Task <Bitmap> Encode(Bitmap carrierImage, byte[] message, string password, Func <double, bool> checkCancel = null) { var shuffleSeed = FisherYates.GetSeed(password); var messageAsBitArray = message.ConvertToBitArray(); var userCancelled = false; var stopwatch = new Stopwatch(); stopwatch.Start(); await Task.Run(() => // move away from the calling thread while working { var bitsWritten = 0; IterateBitmap(carrierImage, shuffleSeed, (x, y) => { EncodePixel(carrierImage, messageAsBitArray, ref bitsWritten, x, y); var percentComplete = ((double)bitsWritten / messageAsBitArray.Length); userCancelled = checkCancel == null ? false : CheckCancelAndUpdate(stopwatch, percentComplete, checkCancel); bool encodeComplete = bitsWritten >= messageAsBitArray.Length; return(userCancelled || encodeComplete); }); }); return(userCancelled ? null : carrierImage); }
private static void IterateBitmap(Bitmap bitmap, int shuffleSeed, Func <int, int, bool> onPixel) { var shuffledIndices = FisherYates.Shuffle(shuffleSeed, bitmap.Height * bitmap.Width); for (var i = 0; i < shuffledIndices.Length; i++) { var(x, y) = bitmap.Get2DCoordinate(shuffledIndices[i]); var done = onPixel(x, y); if (done) { break; } } }
public static async Task <byte[]> Take(Bitmap carrierImage, string password, int startingByteIndex, Int64 bytesToTake, Func <double, bool> checkCancel = null) { var shuffleSeed = FisherYates.GetSeed(password); bool userCancelled = false; List <bool> messageBuilder = new List <bool>(); int startingIndexInBits = startingByteIndex * 8; int bitsToTake = (int)bytesToTake * 8; var userUpdateStopwatch = new Stopwatch(); var eofStopwatch = new Stopwatch(); userUpdateStopwatch.Start(); eofStopwatch.Start(); await Task.Run(() => // move away from the calling thread while working { IterateBitmap(carrierImage, shuffleSeed, (x, y) => { var pixelBits = DecodePixel(carrierImage, x, y); messageBuilder.AddRange(pixelBits); var recoveredAllBits = messageBuilder.Count >= startingIndexInBits + bitsToTake; var percentComplete = (double)messageBuilder.Count / carrierImage.BitCapacity; userCancelled = checkCancel == null ? false : CheckCancelAndUpdate(userUpdateStopwatch, percentComplete, checkCancel); return(recoveredAllBits || userCancelled); }); }); messageBuilder.RemoveRange(0, startingIndexInBits); messageBuilder = messageBuilder.Take(bitsToTake).ToList(); // TODO: does this ever blow up if the image is ..small? or something. ...on encode it can check. here we could get an error? return(messageBuilder.ConvertToByteArray()); }