/// <summary> /// Embeds a given watermark into a PNG file and saves the result. /// </summary> /// <param name="file">PNGFile to use in the watermarking process.</param> /// <param name="mark">The watermark to embed.</param> /// <param name="password">A password for the embedding process</param> /// <param name="outputPath">Location of the saved file.</param> public static void EmbedWatermark(PNGFile file, Watermark mark, string password, string outputPath) { Rfc2898DeriveBytes bytes = new Rfc2898DeriveBytes(password, new byte[] { 112, 52, 63, 42, 180, 121, 53, 27 }, 1000); PNGScrambler scrambler = new PNGScrambler(file, bytes.GetBytes(16), bytes.GetBytes(8)); byte[] markBytes = mark.GetBytes(); if (ReedSolomonProtection == false) { EmbedData(markBytes, scrambler); } else { markBytes = EncodeWithReedSolomon(markBytes); EmbedData(markBytes, scrambler); } file.SaveAs(outputPath); }
private static byte[] ReadBytes(PNGFile file, PNGScrambler scrambler, int count, int skip = 0) { scrambler.Reset(); List <byte> bits = new List <byte>(); int numBitsToRead = count * 8; int pixelsToRead = numBitsToRead / 6 + ((numBitsToRead / 6.0) % 1.0 != 0 ? 1 : 0); int pixelsToSkip = (skip * 8) / 6; //int bitPairsToThrowaway = pixelsToSkip == 0 ? 0 : (6 - ((skip * 8) % 6)) / 2; int bitPairsToThrowaway = ((skip * 8) % 6) / 2; if (bitPairsToThrowaway == 2) { pixelsToRead++; } for (var x = 0; x < pixelsToSkip; x++) { scrambler.GetPixel(); } for (var x = 0; x < pixelsToRead; x++) { PNGPixel p = scrambler.GetPixel(); bits.Add((byte)(p.Red & 0x03)); bits.Add((byte)(p.Green & 0x03)); bits.Add((byte)(p.Blue & 0x03)); } for (var x = 0; x < bitPairsToThrowaway; x++) { bits.RemoveAt(0); } return(BitsToBytes(bits)); }
/// <summary> /// Extracts a stored watermark from a PNGFile. /// </summary> /// <param name="file">PNGFile that contains the watermark.</param> /// <param name="mark">An empty watermark that will be populated.</param> /// <param name="password">Password that was used to embed the watermark.</param> /// <returns></returns> public static Watermark ExtractWatermark(PNGFile file, string password) { Rfc2898DeriveBytes bytes = new Rfc2898DeriveBytes(password, new byte[] { 112, 52, 63, 42, 180, 121, 53, 27 }, 1000); PNGScrambler scrambler = new PNGScrambler(file, bytes.GetBytes(16), bytes.GetBytes(8)); byte[] data = null; byte markType; if (ReedSolomonProtection == false) { byte[] type = ReadBytes(file, scrambler, 1); markType = type[0]; if (markType > 9) { return(null); } byte[] dword = ReadBytes(file, scrambler, 4, 1); int length = BitConverter.ToInt32(dword, 0); try { data = ReadBytes(file, scrambler, length, 5); } catch (Exception e) { return(null); } } else { byte[] rsType = ReadBytes(file, scrambler, 3, 0); byte[] type = correctErrors(rsType, 1); markType = type[0]; if ((markType & 0x80) != 0x80) { return(null); } markType ^= 0x80; byte[] rsLength = ReadBytes(file, scrambler, 12, 3); byte[] length = correctErrors(rsLength, 4); int markLength = BitConverter.ToInt32(length, 0); int position = 0; int numBlocks = (markLength / 256) + (markLength % 256 > 0 ? 1 : 0); MemoryStream msOut = new MemoryStream(); while (numBlocks > 0) { int bytesInBlock = (markLength - (position / 2) < 256 ? markLength - (position / 2) : 256); bytesInBlock *= 2; byte[] codeBytes = ReadBytes(file, scrambler, bytesInBlock, position + 15); byte[] fixedData = correctErrors(codeBytes, bytesInBlock / 2); msOut.Write(fixedData, 0, fixedData.Length); numBlocks--; position += bytesInBlock; } data = msOut.ToArray(); } Watermark mark = null; switch (markType) { case 1: mark = TextWatermark.LoadFromBytes(data); break; case 2: mark = FileWatermark.LoadFromBytes(data); break; case 3: mark = BinaryWatermark.LoadFromBytes(data); break; case 4: mark = CompositeWatermark.LoadFromBytes(data); break; case 9: mark = EncryptedWatermark.LoadFromBytes(data); break; } return(mark); }