/// <summary> /// Применение метода широкополосного сигнала /// Внедрение данных в графический файл /// </summary> /// <param name="bbsOptions">Параметры алгоритма включая исходные данные</param> /// <returns>Графический файл с внедрёнными данными</returns> public static CvBitmap Pack(BbsOptions bbsOptions) { Debug.WriteLine(bbsOptions.ToString()); var key = bbsOptions.Key; var expandSize = bbsOptions.ExpandSize; var codeSize = bbsOptions.EccCodeSize; var dataSize = bbsOptions.EccDataSize; double alpha = bbsOptions.Alpha; double betta = 0; var dhtMode = bbsOptions.DhtMode; var autoAlpha = bbsOptions.AutoAlpha; var autoResize = bbsOptions.AutoResize; var maximumGamma = bbsOptions.MaximumGamma; var politicIndex = bbsOptions.PoliticIndex; var politicText = bbsOptions.PoliticText; var eccIndex = bbsOptions.EccIndex; var mixerIndex = bbsOptions.MixerIndex; var gammaIndex = bbsOptions.GammaIndex; var archiverIndex = bbsOptions.ArchiverIndex; var barcodeIndex = bbsOptions.BarcodeIndex; var zipperIndex = bbsOptions.ZipperIndex; var filterStep = bbsOptions.FilterStep; var sampleBitmap = bbsOptions.SampleBitmap; var minSize = sampleBitmap.Size; CvBitmap barcodeBitmap = null; try { using (var barcode = new Barcode(barcodeIndex) { // indeces ArchiverIndex = archiverIndex, EccIndex = eccIndex, MixerIndex = mixerIndex, GammaIndex = gammaIndex, // ints ExpandSize = expandSize, EccCodeSize = codeSize, EccDataSize = dataSize, // bools DhtMode = dhtMode, AutoAlpha = autoAlpha, MaximumGamma = maximumGamma, // strings Key = key }) { // Формирование баркода с параметрами для используемых алгоритмов barcodeBitmap = new CvBitmap(barcode.Encode()); var barcodeSize = barcodeBitmap.Size; minSize.Width = Math.Max(minSize.Width, 4 * barcodeSize.Width); minSize.Height = Math.Max(minSize.Height, 4 * barcodeSize.Height); } } catch (ArgumentNullException exception) { } var bytes = Encoding.GetEncoding(0).GetBytes(bbsOptions.RtfText); Debug.WriteLine(string.Join("", bytes.Select(x => x.ToString("X02")))); // В дополнение к самому методу широкополосного сигнала данные могут быть сжаты алгоритмом компрессии данных, // добавлены коды исправления ошибок, последовательности бит могут размещаться в изображении не последовательно, а в // соответствии с выбранным алгоритмом. IStreamTransform[] streamTransforms = { new Archiver(archiverIndex), // Алгоритм сжатия данных new Envelope(), // Добавление конверта new Ecc(eccIndex, codeSize, dataSize) // Алгоритм коррекции ошибок }; var input = new MemoryStream(bytes); Debug.WriteLine("input {0}", input.Length); foreach (var transform in streamTransforms) { using (var prev = input) transform.Forward(prev, input = new MemoryStream()); input.Seek(0, SeekOrigin.Begin); Debug.WriteLine("{0} {1}", transform, input.Length); } // для каждого бита сообщения нужно N пикселей носителя var inputLength = input.Length; // Количество байт передаваемых данных var requiredLength = inputLength * expandSize * BitsPerByte; // Требуемое число пикселей var sampleSize = sampleBitmap.Size; var sampleLength = sampleBitmap.Length; var ratio = Math.Sqrt(1 + (double)requiredLength / sampleLength); ratio = Math.Max(ratio, (double)minSize.Width / sampleSize.Width); ratio = Math.Max(ratio, (double)minSize.Height / sampleSize.Height); minSize.Width = (int)Math.Max(minSize.Width, Math.Ceiling(ratio * sampleSize.Width)); minSize.Height = (int)Math.Max(minSize.Height, Math.Ceiling(ratio * sampleSize.Height)); CvBitmap bitmap; CvBitmap median; using (var stretchBuilder = new StretchBuilder(minSize)) bitmap = new CvBitmap(sampleBitmap, stretchBuilder, autoResize); var length = bitmap.Length; var size = bitmap.Size; if (requiredLength > length) { throw new Exception( string.Format("Размер изображения недостаточен для сохранения данных {0}/{1}", requiredLength, sampleLength)); } if (minSize.Width > size.Width || minSize.Height > size.Height) { throw new Exception( string.Format( "Размер изображения недостаточен для сохранения данных {0}x{1}/{2}x{3}", size.Width, size.Height, minSize.Width, minSize.Height)); } // Применение политики обработки неиспользуемых пикселей using (IStreamTransform streamTransform = new Politic(politicIndex, politicText, expandSize, bitmap)) using (var prev = input) streamTransform.Forward(prev, input = new MemoryStream()); input.Seek(0, SeekOrigin.Begin); Debug.WriteLine("input {0}", input.Length); // Внедрения в передаваемое изображение баркода с настроечными параметрами для используемых алгоритмов if (barcodeBitmap != null) { bitmap.DrawCopyright(barcodeBitmap); } using (var builder = new BlurBuilder(filterStep)) median = new CvBitmap(bitmap, builder); using (var reader = new BinaryReader(input)) { var data = reader.ReadBytes((int)input.Length); Debug.WriteLine(string.Join("", data.Select(x => x.ToString("X02")))); var index = new int[length]; var colors = new double[length]; var medianColors = new double[length]; var gamma = new byte[maximumGamma ? ((length + BitsPerByte - 1) / BitsPerByte) : ((expandSize + BitsPerByte - 1) / BitsPerByte)]; using (var builder = new Mixer(mixerIndex, key)) builder.GetInts(index); using (var builder = new Gamma(gammaIndex, key)) builder.GetBytes(gamma); var bitmapDataContainer = dhtMode ? new HartleyOfBitmap(bitmap) : (IDataContainer)bitmap; bitmapDataContainer.Select(index, colors); var medianDataContainer = dhtMode ? new HartleyOfBitmap(median) : (IDataContainer)median; medianDataContainer.Select(index, medianColors); Debug.Assert(dhtMode || colors.All(x => x >= 0)); Debug.Assert(dhtMode || medianColors.All(x => x >= 0)); // Рассчёт весов пикселей var middle = medianColors.Average(); var weight = medianColors.Select(x => F / (F + Math.Abs(x - middle))).ToArray(); var average = weight.Average(); weight = weight.Select(x => x / average).ToArray(); if (autoAlpha) { // Вычисление параметров из характеристик отправляемых данных var delta = colors.Zip(medianColors, (x, y) => (x - y)).Zip(weight, (x, y) => x * y).ToArray(); var e1 = delta.Average(x => x); var e2 = delta.Average(x => x * x); bbsOptions.Alpha = (int)Math.Ceiling(alpha = Math.Sqrt(e2 - e1 * e1)); // Использование псевдослучайной последовательности с характеристиками приближенными к равновероятной, для кодирования // данных, позволяет сохранить среднюю яркость пикселей у исходного графического изображения и у изображения, // содержащего внедрённые данные // Однако при прямом и дословном применении алгоритма средняя яркость пикселей могла бы иметь смещение относительно средней яркости у исходного изображения // Поэтому производим статистическую оценку такого смещения и вводим её в качестве компенсирующего слагаемого в алгоритм // Вычисление количества единиц в исходных данных и псевдослучайной последовательности double trueData = BitCounter.Count(data); double trueGamma = BitCounter.Count(gamma); // Вычисление количества нулей в исходных данных и псевдослучайной последовательности var falseData = (long)data.Length * BitsPerByte - trueData; var falseGamma = (long)gamma.Length * BitsPerByte - trueGamma; // Вычисление оценки количества единиц и нулей при смешивании исходных данных и псевдослучайной последовательности var trueCount = trueGamma * falseData + falseGamma * trueData; var falseCount = trueGamma * trueData + falseGamma * falseData; betta = ((falseCount - trueCount) * alpha / (trueCount + falseCount)); Debug.WriteLine("alpha = {0} betta = {1}", alpha, betta); } using (var bbSignals = new BbSignals(expandSize, maximumGamma)) { var delta = new double[colors.Length]; bbSignals.Combine(delta, data, gamma, alpha, betta); delta = delta.Zip(weight, (x, y) => x * y).ToArray(); colors = colors.Zip(delta, (x, y) => (x + y)).ToArray(); } bitmapDataContainer.Replace(index, colors); return(bbsOptions.OutputBitmap = bitmap); } }
private const int BitsPerByte = 8; // Количество битов в байте /// <summary> /// Применение метода широкополосного сигнала /// Внедрение данных в графический файл /// </summary> /// <param name="bbsOptions">Параметры алгоритма включая исходные данные</param> /// <returns>Графический файл с внедрёнными данными</returns> public static CvBitmap Pack(BbsOptions bbsOptions) { Debug.WriteLine(bbsOptions.ToString()); string key = bbsOptions.Key; int expandSize = bbsOptions.ExpandSize; int codeSize = bbsOptions.EccCodeSize; int dataSize = bbsOptions.EccDataSize; int alpha = bbsOptions.Alpha; int betta = 0; bool autoAlpha = bbsOptions.AutoAlpha; bool autoResize = bbsOptions.AutoResize; bool maximumGamma = bbsOptions.MaximumGamma; int politicIndex = bbsOptions.PoliticIndex; string politicText = bbsOptions.PoliticText; int eccIndex = bbsOptions.EccIndex; int mixerIndex = bbsOptions.MixerIndex; int gammaIndex = bbsOptions.GammaIndex; int archiverIndex = bbsOptions.ArchiverIndex; int barcodeIndex = bbsOptions.BarcodeIndex; int filterStep = bbsOptions.FilterStep; CvBitmap sampleBitmap = bbsOptions.SampleBitmap; Size minSize = sampleBitmap.Size; CvBitmap barcodeBitmap = null; try { using (var barcode = new Barcode(barcodeIndex) { ArchiverIndex = archiverIndex, EccIndex = eccIndex, MixerIndex = mixerIndex, GammaIndex = gammaIndex, ExpandSize = expandSize, EccCodeSize = codeSize, EccDataSize = dataSize, MaximumGamma = maximumGamma, Key = key, }) { // Формирование баркода с параметрами для используемых алгоритмов barcodeBitmap = new CvBitmap(barcode.Encode()); Size barcodeSize = barcodeBitmap.Size; minSize.Width = Math.Max(minSize.Width, 4 * barcodeSize.Width); minSize.Height = Math.Max(minSize.Height, 4 * barcodeSize.Height); } } catch (ArgumentNullException exception) { } byte[] bytes = Encoding.Default.GetBytes(bbsOptions.RtfText); Debug.WriteLine(string.Join("", bytes.Select(x => x.ToString("X02")))); // В дополнение к самому методу широкополосного сигнала данные могут быть сжаты алгоритмом компрессии данных, // добавлены коды исправления ошибок, последовательности бит могут размещаться в изображении не последовательно, а в // соответствии с выбранным алгоритмом. IStreamTransform[] streamTransforms = { new Archiver(archiverIndex), // Алгоритм сжатия данных new Envelope(), // Добавление конверта new Ecc(eccIndex, codeSize, dataSize) // Алгоритм коррекции ошибок }; var input = new MemoryStream(bytes); Debug.WriteLine("input {0}", input.Length); foreach (IStreamTransform transform in streamTransforms) { using (MemoryStream prev = input) transform.Forward(prev, input = new MemoryStream()); input.Seek(0, SeekOrigin.Begin); Debug.WriteLine("{0} {1}", transform, input.Length); } // для каждого бита сообщения нужно N байт носителя long inputLength = input.Length; // Количество байт передаваемых данных long requiredLength = inputLength * expandSize * BitsPerByte; // Требуемое число пикселей Size sampleSize = sampleBitmap.Size; long sampleLength = sampleBitmap.Length; double ratio = Math.Sqrt(1 + (double)requiredLength / sampleLength); ratio = Math.Max(ratio, (double)minSize.Width / sampleSize.Width); ratio = Math.Max(ratio, (double)minSize.Height / sampleSize.Height); minSize.Width = (int)Math.Max(minSize.Width, Math.Ceiling(ratio * sampleSize.Width)); minSize.Height = (int)Math.Max(minSize.Height, Math.Ceiling(ratio * sampleSize.Height)); CvBitmap bitmap; using (var stretchBuilder = new StretchBuilder(minSize)) bitmap = new CvBitmap(sampleBitmap, stretchBuilder, autoResize); long length = bitmap.Length; Size size = bitmap.Size; if (requiredLength > length) { throw new Exception( string.Format("Размер изображения недостаточен для сохранения данных {0}/{1}", requiredLength, sampleLength)); } if (minSize.Width > size.Width || minSize.Height > size.Height) { throw new Exception( string.Format( "Размер изображения недостаточен для сохранения данных {0}x{1}/{2}x{3}", size.Width, size.Height, minSize.Width, minSize.Height)); } // Внедрения в передаваемое изображение баркода с настроечными параметрами для используемых алгоритмов if (barcodeBitmap != null) { bitmap.DrawCopyright(barcodeBitmap); } using (IStreamTransform streamTransform = new Politic(politicIndex, politicText, expandSize, bitmap)) using (MemoryStream prev = input) streamTransform.Forward(prev, input = new MemoryStream()); input.Seek(0, SeekOrigin.Begin); Debug.WriteLine("input {0}", input.Length); using (var reader = new BinaryReader(input)) { byte[] data = reader.ReadBytes((int)input.Length); Debug.WriteLine(string.Join("", data.Select(x => x.ToString("X02")))); var index = new int[length]; var colors = new byte[length]; var cw = new byte[length]; var gamma = new byte[maximumGamma ? ((length + BitsPerByte - 1) / BitsPerByte) : ((expandSize + BitsPerByte - 1) / BitsPerByte)]; using (var builder = new Mixer(mixerIndex, key)) builder.GetInts(index); using (var builder = new Gamma(gammaIndex, key)) builder.GetBytes(gamma); bitmap.Select(index, colors); if (autoAlpha) { using (var blurBuilder = new BlurBuilder(filterStep)) using (var median = new CvBitmap(bitmap, blurBuilder)) { if (barcodeBitmap != null) { median.DrawCopyright(barcodeBitmap); } var medianColors = new byte[length]; median.Select(index, medianColors); double e1 = colors.Zip(medianColors, (x, y) => (int)x - (int)y).Average(x => (double)x); double e2 = colors.Zip(medianColors, (x, y) => (int)x - (int)y).Average(x => (double)x * x); alpha = (int)Math.Sqrt(e2 - e1 * e1); bbsOptions.Alpha = alpha; // Вычисление оценки смещение яркости относительно средней яркости исходного изображения при прямом и дословном применении алгоритма // Построение массивов, содержащих статистическую информацию о исходных данных и псевдослучайной последовательности // То есть построение гистограмм исходных данных и псевдослучайной последовательности var countData = new int[256]; var countGamma = new int[256]; foreach (byte ch in data) { countData[ch]++; } foreach (byte ch in gamma) { countGamma[ch]++; } // Построение массива, где каждый элемент содержит количество ненулевых бит в бинарном разложении индекса элемента var count = new int[256]; count[0] = 0; for (int k = 1; k < 256; k <<= 1) { for (int i = 0; i < k; i++) { count[k + i] = count[i] + 1; } } // Использование псевдослучайной последовательности с характеристиками приближенными к равновероятной, для кодирования // данных, позволяет сохранить среднюю яркость пикселей у исходного графического изображения и у изображения, // содержащего внедрённые данные // Однако при прямом и дословном применении алгоритма средняя яркость пикселей могла бы иметь смещение относительно средней яркости у исходного изображения // Поэтому производим статистическую оценку такого смещения и вводим её в качестве компенсирующего слагаемого в алгоритм // Вычисление количества единиц в исходных данных и псевдослучайной последовательности double trueData = count.Zip(countData, (x, y) => (double)((long)x * y)).Sum(); double trueGamma = count.Zip(countGamma, (x, y) => (double)((long)x * y)).Sum(); // Вычисление количества нулей в исходных данных и псевдослучайной последовательности double falseData = (long)data.Length * BitsPerByte - trueData; double falseGamma = (long)gamma.Length * BitsPerByte - trueGamma; // Вычисление оценки количества единиц и нулей при смешивании исходных данных и псевдослучайной последовательности double trueCount = trueGamma * falseData + falseGamma * trueData; double falseCount = trueGamma * trueData + falseGamma * falseData; betta = (int)((falseCount - trueCount) * alpha / (trueCount + falseCount)); bbsOptions.Alpha = alpha; } } using (var bbSignals = new BbSignals(expandSize, maximumGamma)) bbSignals.Combine(colors, data, gamma, alpha, betta, cw); bitmap.Replace(index, cw); return(bbsOptions.OutputBitmap = bitmap); } }
/// <summary> /// Применение метода широкополосного сигнала /// Извлечение данных из графического файла /// </summary> /// <param name="bbsOptions">Параметры алгоритма включая графический файл с внедрёнными данными</param> /// <returns>Извлечённые данные</returns> public static string Unpack(BbsOptions bbsOptions) { Debug.WriteLine(bbsOptions.ToString()); var key = bbsOptions.Key; var expandSize = bbsOptions.ExpandSize; var codeSize = bbsOptions.EccCodeSize; var dataSize = bbsOptions.EccDataSize; var filterStep = bbsOptions.FilterStep; var eccIndex = bbsOptions.EccIndex; var mixerIndex = bbsOptions.MixerIndex; var gammaIndex = bbsOptions.GammaIndex; var archiverIndex = bbsOptions.ArchiverIndex; var zipperIndex = bbsOptions.ZipperIndex; double alpha = bbsOptions.Alpha; double betta = 0; var dhtMode = bbsOptions.DhtMode; var autoAlpha = bbsOptions.AutoAlpha; var maximumGamma = bbsOptions.MaximumGamma; var extractBarcode = bbsOptions.ExtractBarcode; var bitmap = bbsOptions.InputBitmap; if (extractBarcode) { using (var barcode = new Barcode(bitmap.Bitmap)) { // Извлечение параметров из внедрённого в изображение баркода // и использование этих извлечённых параметров для используемых алгоритмов barcode.Decode(); archiverIndex = barcode.ArchiverIndex; eccIndex = barcode.EccIndex; mixerIndex = barcode.MixerIndex; gammaIndex = barcode.GammaIndex; // ints expandSize = barcode.ExpandSize; codeSize = barcode.EccCodeSize; dataSize = barcode.EccDataSize; // bools dhtMode = barcode.DhtMode; autoAlpha = barcode.AutoAlpha; maximumGamma = barcode.MaximumGamma; // strings key = barcode.Key; Debug.WriteLine(barcode.ToString()); } } using (var builder = new BlurBuilder(filterStep)) bbsOptions.MedianBitmap = new CvBitmap(bitmap, builder); var median = bbsOptions.MedianBitmap; var length = bitmap.Length; var index = new int[length]; var colors = new double[length]; var medianColors = new double[length]; var data = new byte[length / expandSize / BitsPerByte]; using (var builder = new Mixer(mixerIndex, key)) builder.GetInts(index); var gamma = new byte[maximumGamma ? ((length + BitsPerByte - 1) / BitsPerByte) : ((expandSize + BitsPerByte - 1) / BitsPerByte)]; using (var builder = new Gamma(gammaIndex, key)) builder.GetBytes(gamma); var bitmapDataContainer = dhtMode ? new HartleyOfBitmap(bitmap) : (IDataContainer)bitmap; bitmapDataContainer.Select(index, colors); var medianDataContainer = dhtMode ? new HartleyOfBitmap(median) : (IDataContainer)median; medianDataContainer.Select(index, medianColors); Debug.Assert(dhtMode || colors.All(x => x >= 0)); Debug.Assert(dhtMode || medianColors.All(x => x >= 0)); // Рассчёт весов пикселей var middle = medianColors.Average(); var weight = medianColors.Select(x => F / (F + Math.Abs(x - middle))).ToArray(); var average = weight.Average(); weight = weight.Select(x => x / average).ToArray(); var delta = colors.Zip(medianColors, (x, y) => (x - y)).Zip(weight, (x, y) => x * y).ToArray(); if (autoAlpha) { // Вычисление параметров из характеристик полученных данных var e1 = delta.Average(x => x); var e2 = delta.Average(x => x * x); betta = e1; bbsOptions.Alpha = (int)Math.Ceiling(alpha = Math.Sqrt(e2 - e1 * e1)); Debug.WriteLine("alpha = {0} betta = {1}", alpha, betta); } using (var bbSignals = new BbSignals(expandSize, maximumGamma)) bbSignals.Extract(delta, data, gamma, alpha, betta); Debug.WriteLine(string.Join("", data.Select(x => x.ToString("X02")))); // В дополнение к самому методу широкополосного сигнала данные могут быть сжаты алгоритмом компрессии данных, // добавлены коды исправления ошибок, последовательности бит могут размещаться в изображении не последовательно, а в // соответствии с выбранным алгоритмом. IStreamTransform[] streamTransforms = { new Ecc(eccIndex, codeSize, dataSize), // Алгоритм коррекции ошибок new Envelope(), // Извлечение из конверта new Archiver(archiverIndex) // Алгоритм извлечения из сжатого архива }; var input = new MemoryStream(data); Debug.WriteLine("input {0}", input.Length); foreach (var transform in streamTransforms) { using (var prev = input) transform.Backward(prev, input = new MemoryStream()); input.Seek(0, SeekOrigin.Begin); Debug.WriteLine("{0} {1}", transform, input.Length); } using (var reader = new BinaryReader(input)) { var bytes = reader.ReadBytes((int)input.Length); Debug.WriteLine(string.Join("", bytes.Select(x => x.ToString("X02")))); return(bbsOptions.RtfText = Encoding.GetEncoding(0).GetString(bytes)); } }
/// <summary> /// Применение метода широкополосного сигнала /// Извлечение данных из графического файла /// </summary> /// <param name="bbsOptions">Параметры алгоритма включая графический файл с внедрёнными данными</param> /// <returns>Извлечённые данные</returns> public static string Unpack(BbsOptions bbsOptions) { Debug.WriteLine(bbsOptions.ToString()); string key = bbsOptions.Key; int expandSize = bbsOptions.ExpandSize; int codeSize = bbsOptions.EccCodeSize; int dataSize = bbsOptions.EccDataSize; int filterStep = bbsOptions.FilterStep; int eccIndex = bbsOptions.EccIndex; int mixerIndex = bbsOptions.MixerIndex; int gammaIndex = bbsOptions.GammaIndex; int archiverIndex = bbsOptions.ArchiverIndex; int alpha = bbsOptions.Alpha; int betta = 0; bool autoAlpha = bbsOptions.AutoAlpha; bool maximumGamma = bbsOptions.MaximumGamma; bool extractBarcode = bbsOptions.ExtractBarcode; CvBitmap bitmap = bbsOptions.InputBitmap; if (extractBarcode) { using (var barcode = new Barcode(bitmap.Bitmap)) { // Извлечение параметров из внедрённого в изображение баркода // и использование этих извлечённых параметров для используемых алгоритмов barcode.Decode(); archiverIndex = barcode.ArchiverIndex; eccIndex = barcode.EccIndex; mixerIndex = barcode.MixerIndex; gammaIndex = barcode.GammaIndex; expandSize = barcode.ExpandSize; codeSize = barcode.EccCodeSize; dataSize = barcode.EccDataSize; maximumGamma = barcode.MaximumGamma; key = barcode.Key; } } using (var builder = new BlurBuilder(filterStep)) bbsOptions.MedianBitmap = new CvBitmap(bitmap, builder); CvBitmap median = bbsOptions.MedianBitmap; long length = bitmap.Length; var index = new int[length]; var colors = new byte[length]; var medianColors = new byte[length]; var data = new byte[length / expandSize / BitsPerByte]; using (var builder = new Mixer(mixerIndex, key)) builder.GetInts(index); var gamma = new byte[maximumGamma ? ((length + BitsPerByte - 1) / BitsPerByte) : ((expandSize + BitsPerByte - 1) / BitsPerByte)]; using (var builder = new Gamma(gammaIndex, key)) builder.GetBytes(gamma); bitmap.Select(index, colors); median.Select(index, medianColors); if (autoAlpha) { double e1 = colors.Zip(medianColors, (x, y) => (int)x - (int)y).Average(x => (double)x); double e2 = colors.Zip(medianColors, (x, y) => (int)x - (int)y).Average(x => (double)x * x); betta = (int)e1; alpha = (int)Math.Sqrt(e2 - e1 * e1); bbsOptions.Alpha = alpha; } using (var bbSignals = new BbSignals(expandSize, maximumGamma)) bbSignals.Extract(colors, medianColors, gamma, alpha, betta, data); Debug.WriteLine(string.Join("", data.Select(x => x.ToString("X02")))); // В дополнение к самому методу широкополосного сигнала данные могут быть сжаты алгоритмом компрессии данных, // добавлены коды исправления ошибок, последовательности бит могут размещаться в изображении не последовательно, а в // соответствии с выбранным алгоритмом. IStreamTransform[] streamTransforms = { new Ecc(eccIndex, codeSize, dataSize), // Алгоритм коррекции ошибок new Envelope(), // Извлечение из конверта new Archiver(archiverIndex) // Алгоритм извлечения из сжатого архива }; var input = new MemoryStream(data); Debug.WriteLine("input {0}", input.Length); foreach (IStreamTransform transform in streamTransforms) { using (MemoryStream prev = input) transform.Backward(prev, input = new MemoryStream()); input.Seek(0, SeekOrigin.Begin); Debug.WriteLine("{0} {1}", transform, input.Length); } using (var reader = new BinaryReader(input)) { byte[] bytes = reader.ReadBytes((int)input.Length); Debug.WriteLine(string.Join("", bytes.Select(x => x.ToString("X02")))); return(bbsOptions.RtfText = Encoding.Default.GetString(bytes)); } }
private const int BitsPerByte = 8; // Количество битов в байте #endregion Fields #region Methods /// <summary> /// Применение метода широкополосного сигнала /// Внедрение данных в графический файл /// </summary> /// <param name="bbsOptions">Параметры алгоритма включая исходные данные</param> /// <returns>Графический файл с внедрёнными данными</returns> public static CvBitmap Pack(BbsOptions bbsOptions) { Debug.WriteLine(bbsOptions.ToString()); string key = bbsOptions.Key; int expandSize = bbsOptions.ExpandSize; int codeSize = bbsOptions.EccCodeSize; int dataSize = bbsOptions.EccDataSize; int alpha = bbsOptions.Alpha; int betta = 0; bool autoAlpha = bbsOptions.AutoAlpha; bool autoResize = bbsOptions.AutoResize; bool maximumGamma = bbsOptions.MaximumGamma; int politicIndex = bbsOptions.PoliticIndex; string politicText = bbsOptions.PoliticText; int eccIndex = bbsOptions.EccIndex; int mixerIndex = bbsOptions.MixerIndex; int gammaIndex = bbsOptions.GammaIndex; int archiverIndex = bbsOptions.ArchiverIndex; int barcodeIndex = bbsOptions.BarcodeIndex; int filterStep = bbsOptions.FilterStep; CvBitmap sampleBitmap = bbsOptions.SampleBitmap; Size minSize = sampleBitmap.Size; CvBitmap barcodeBitmap = null; try { using (var barcode = new Barcode(barcodeIndex) { ArchiverIndex = archiverIndex, EccIndex = eccIndex, MixerIndex = mixerIndex, GammaIndex = gammaIndex, ExpandSize = expandSize, EccCodeSize = codeSize, EccDataSize = dataSize, MaximumGamma = maximumGamma, Key = key, }) { // Формирование баркода с параметрами для используемых алгоритмов barcodeBitmap = new CvBitmap(barcode.Encode()); Size barcodeSize = barcodeBitmap.Size; minSize.Width = Math.Max(minSize.Width, 4*barcodeSize.Width); minSize.Height = Math.Max(minSize.Height, 4*barcodeSize.Height); } } catch (ArgumentNullException exception) { } byte[] bytes = Encoding.Default.GetBytes(bbsOptions.RtfText); Debug.WriteLine(string.Join("", bytes.Select(x => x.ToString("X02")))); // В дополнение к самому методу широкополосного сигнала данные могут быть сжаты алгоритмом компрессии данных, // добавлены коды исправления ошибок, последовательности бит могут размещаться в изображении не последовательно, а в // соответствии с выбранным алгоритмом. IStreamTransform[] streamTransforms = { new Archiver(archiverIndex), // Алгоритм сжатия данных new Envelope(), // Добавление конверта new Ecc(eccIndex, codeSize, dataSize) // Алгоритм коррекции ошибок }; var input = new MemoryStream(bytes); Debug.WriteLine("input {0}", input.Length); foreach (IStreamTransform transform in streamTransforms) { using (MemoryStream prev = input) transform.Forward(prev, input = new MemoryStream()); input.Seek(0, SeekOrigin.Begin); Debug.WriteLine("{0} {1}", transform, input.Length); } // для каждого бита сообщения нужно N байт носителя long inputLength = input.Length; // Количество байт передаваемых данных long requiredLength = inputLength*expandSize*BitsPerByte; // Требуемое число пикселей Size sampleSize = sampleBitmap.Size; long sampleLength = sampleBitmap.Length; double ratio = Math.Sqrt(1+(double) requiredLength/sampleLength); ratio = Math.Max(ratio, (double) minSize.Width/sampleSize.Width); ratio = Math.Max(ratio, (double) minSize.Height/sampleSize.Height); minSize.Width = (int) Math.Max(minSize.Width, Math.Ceiling(ratio*sampleSize.Width)); minSize.Height = (int) Math.Max(minSize.Height, Math.Ceiling(ratio*sampleSize.Height)); CvBitmap bitmap; using (var stretchBuilder = new StretchBuilder(minSize)) bitmap = new CvBitmap(sampleBitmap, stretchBuilder, autoResize); long length = bitmap.Length; Size size = bitmap.Size; if (requiredLength > length) throw new Exception( string.Format("Размер изображения недостаточен для сохранения данных {0}/{1}", requiredLength, sampleLength)); if (minSize.Width > size.Width || minSize.Height > size.Height) throw new Exception( string.Format( "Размер изображения недостаточен для сохранения данных {0}x{1}/{2}x{3}", size.Width, size.Height, minSize.Width, minSize.Height)); // Внедрения в передаваемое изображение баркода с настроечными параметрами для используемых алгоритмов if (barcodeBitmap != null) bitmap.DrawCopyright(barcodeBitmap); using (IStreamTransform streamTransform = new Politic(politicIndex, politicText, expandSize, bitmap)) using (MemoryStream prev = input) streamTransform.Forward(prev, input = new MemoryStream()); input.Seek(0, SeekOrigin.Begin); Debug.WriteLine("input {0}", input.Length); using (var reader = new BinaryReader(input)) { byte[] data = reader.ReadBytes((int) input.Length); Debug.WriteLine(string.Join("", data.Select(x => x.ToString("X02")))); var index = new int[length]; var colors = new byte[length]; var cw = new byte[length]; var gamma = new byte[maximumGamma ? ((length + BitsPerByte - 1)/BitsPerByte) : ((expandSize + BitsPerByte - 1)/BitsPerByte)]; using (var builder = new Mixer(mixerIndex, key)) builder.GetInts(index); using (var builder = new Gamma(gammaIndex, key)) builder.GetBytes(gamma); bitmap.Select(index, colors); if (autoAlpha) { using (var blurBuilder = new BlurBuilder(filterStep)) using (var median = new CvBitmap(bitmap, blurBuilder)) { if (barcodeBitmap != null) median.DrawCopyright(barcodeBitmap); var medianColors = new byte[length]; median.Select(index, medianColors); double e1 = colors.Zip(medianColors, (x, y) => (int) x - (int) y).Average(x => (double) x); double e2 = colors.Zip(medianColors, (x, y) => (int) x - (int) y).Average(x => (double) x*x); alpha = (int) Math.Sqrt(e2 - e1*e1); bbsOptions.Alpha = alpha; // Вычисление оценки смещение яркости относительно средней яркости исходного изображения при прямом и дословном применении алгоритма // Построение массивов, содержащих статистическую информацию о исходных данных и псевдослучайной последовательности // То есть построение гистограмм исходных данных и псевдослучайной последовательности var countData = new int[256]; var countGamma = new int[256]; foreach (byte ch in data) countData[ch]++; foreach (byte ch in gamma) countGamma[ch]++; // Построение массива, где каждый элемент содержит количество ненулевых бит в бинарном разложении индекса элемента var count = new int[256]; count[0] = 0; for (int k = 1; k < 256; k <<= 1) for (int i = 0; i < k; i++) count[k + i] = count[i] + 1; // Использование псевдослучайной последовательности с характеристиками приближенными к равновероятной, для кодирования // данных, позволяет сохранить среднюю яркость пикселей у исходного графического изображения и у изображения, // содержащего внедрённые данные // Однако при прямом и дословном применении алгоритма средняя яркость пикселей могла бы иметь смещение относительно средней яркости у исходного изображения // Поэтому производим статистическую оценку такого смещения и вводим её в качестве компенсирующего слагаемого в алгоритм // Вычисление количества единиц в исходных данных и псевдослучайной последовательности double trueData = count.Zip(countData, (x, y) => (double) ((long) x*y)).Sum(); double trueGamma = count.Zip(countGamma, (x, y) => (double) ((long) x*y)).Sum(); // Вычисление количества нулей в исходных данных и псевдослучайной последовательности double falseData = (long) data.Length*BitsPerByte - trueData; double falseGamma = (long) gamma.Length*BitsPerByte - trueGamma; // Вычисление оценки количества единиц и нулей при смешивании исходных данных и псевдослучайной последовательности double trueCount = trueGamma*falseData + falseGamma*trueData; double falseCount = trueGamma*trueData + falseGamma*falseData; betta = (int) ((falseCount - trueCount)*alpha/(trueCount + falseCount)); bbsOptions.Alpha = alpha; } } using (var bbSignals = new BbSignals(expandSize, maximumGamma)) bbSignals.Combine(colors, data, gamma, alpha, betta, cw); bitmap.Replace(index, cw); return bbsOptions.OutputBitmap = bitmap; } }
/// <summary> /// Применение метода широкополосного сигнала /// Извлечение данных из графического файла /// </summary> /// <param name="bbsOptions">Параметры алгоритма включая графический файл с внедрёнными данными</param> /// <returns>Извлечённые данные</returns> public static string Unpack(BbsOptions bbsOptions) { Debug.WriteLine(bbsOptions.ToString()); string key = bbsOptions.Key; int expandSize = bbsOptions.ExpandSize; int codeSize = bbsOptions.EccCodeSize; int dataSize = bbsOptions.EccDataSize; int filterStep = bbsOptions.FilterStep; int eccIndex = bbsOptions.EccIndex; int mixerIndex = bbsOptions.MixerIndex; int gammaIndex = bbsOptions.GammaIndex; int archiverIndex = bbsOptions.ArchiverIndex; int alpha = bbsOptions.Alpha; int betta = 0; bool autoAlpha = bbsOptions.AutoAlpha; bool maximumGamma = bbsOptions.MaximumGamma; bool extractBarcode = bbsOptions.ExtractBarcode; CvBitmap bitmap = bbsOptions.InputBitmap; if (extractBarcode) using (var barcode = new Barcode(bitmap.Bitmap)) { // Извлечение параметров из внедрённого в изображение баркода // и использование этих извлечённых параметров для используемых алгоритмов barcode.Decode(); archiverIndex = barcode.ArchiverIndex; eccIndex = barcode.EccIndex; mixerIndex = barcode.MixerIndex; gammaIndex = barcode.GammaIndex; expandSize = barcode.ExpandSize; codeSize = barcode.EccCodeSize; dataSize = barcode.EccDataSize; maximumGamma = barcode.MaximumGamma; key = barcode.Key; } using (var builder = new BlurBuilder(filterStep)) bbsOptions.MedianBitmap = new CvBitmap(bitmap, builder); CvBitmap median = bbsOptions.MedianBitmap; long length = bitmap.Length; var index = new int[length]; var colors = new byte[length]; var medianColors = new byte[length]; var data = new byte[length/expandSize/BitsPerByte]; using (var builder = new Mixer(mixerIndex, key)) builder.GetInts(index); var gamma = new byte[maximumGamma ? ((length + BitsPerByte - 1)/BitsPerByte) : ((expandSize + BitsPerByte - 1)/BitsPerByte)]; using (var builder = new Gamma(gammaIndex, key)) builder.GetBytes(gamma); bitmap.Select(index, colors); median.Select(index, medianColors); if (autoAlpha) { double e1 = colors.Zip(medianColors, (x, y) => (int) x - (int) y).Average(x => (double) x); double e2 = colors.Zip(medianColors, (x, y) => (int) x - (int) y).Average(x => (double) x*x); betta = (int) e1; alpha = (int) Math.Sqrt(e2 - e1*e1); bbsOptions.Alpha = alpha; } using (var bbSignals = new BbSignals(expandSize, maximumGamma)) bbSignals.Extract(colors, medianColors, gamma, alpha, betta, data); Debug.WriteLine(string.Join("", data.Select(x => x.ToString("X02")))); // В дополнение к самому методу широкополосного сигнала данные могут быть сжаты алгоритмом компрессии данных, // добавлены коды исправления ошибок, последовательности бит могут размещаться в изображении не последовательно, а в // соответствии с выбранным алгоритмом. IStreamTransform[] streamTransforms = { new Ecc(eccIndex, codeSize, dataSize), // Алгоритм коррекции ошибок new Envelope(), // Извлечение из конверта new Archiver(archiverIndex) // Алгоритм извлечения из сжатого архива }; var input = new MemoryStream(data); Debug.WriteLine("input {0}", input.Length); foreach (IStreamTransform transform in streamTransforms) { using (MemoryStream prev = input) transform.Backward(prev, input = new MemoryStream()); input.Seek(0, SeekOrigin.Begin); Debug.WriteLine("{0} {1}", transform, input.Length); } using (var reader = new BinaryReader(input)) { byte[] bytes = reader.ReadBytes((int) input.Length); Debug.WriteLine(string.Join("", bytes.Select(x => x.ToString("X02")))); return bbsOptions.RtfText = Encoding.Default.GetString(bytes); } }
public BbsControl() { InitializeComponent(); repositoryItemComboBoxArchiver.Items.AddRange(Archiver.ComboBoxItems); repositoryItemComboBoxEcc.Items.AddRange(Ecc.ComboBoxItems); repositoryItemComboBoxGamma.Items.AddRange(Gamma.ComboBoxItems); repositoryItemComboBoxMixer.Items.AddRange(Mixer.ComboBoxItems); repositoryItemComboBoxPolitic.Items.AddRange(Politic.ComboBoxItems); repositoryItemComboBoxBarcode.Items.AddRange(Barcode.ComboBoxItems); try { Debug.WriteLine("Reading Default Options Information"); using (Stream stream = File.Open(DefaultOptionsFileName, FileMode.Open)) _bbsOptions = (BbsOptions) new BinaryFormatter().Deserialize(stream); } catch (Exception) { _bbsOptions.PoliticIndex = 0; _bbsOptions.EccIndex = 1; _bbsOptions.GammaIndex = 1; _bbsOptions.MixerIndex = 1; _bbsOptions.ArchiverIndex = 1; _bbsOptions.BarcodeIndex = 1; _bbsOptions.EccCodeSize = 255; _bbsOptions.EccDataSize = 224; _bbsOptions.ExpandSize = 63; _bbsOptions.Alpha = 10; _bbsOptions.FilterStep = 10; _bbsOptions.AutoResize = true; _bbsOptions.AutoAlpha = true; _bbsOptions.ExtractBarcode = true; _bbsOptions.MaximumGamma = true; _bbsOptions.Key = "WELCOME"; _bbsOptions.PoliticText = "Lorem ipsum dolor sit amet, his ea quod tation, ne sit mazim concludaturque, graece tincidunt pro ei. Vero diceret iracundia pro ea, ne eripuit mandamus mea, an usu nisl liber theophrastus. Partem mollis nostrud eam no. Duis partiendo no pro. Cu eum quot luptatum probatus. Ex per labitur incorrupte inciderint, sit sint nonumy melius ea.\n" + "Tollit soleat torquatos qui eu. Cu mutat debitis legendos per. Nemore partiendo ne mei. At ridens eruditi efficiantur his.\n" + "Petentium abhorreant definitiones mea ex. Dolore necessitatibus ad vim. No agam ubique efficiendi qui, has at dico dissentiet. Cu sed dicam omnesque, oratio ridens eum ne. Ea adolescens definiebas mel, cum eu debitis veritus. Mei purto essent cu.\n" + "Perfecto complectitur no vel, ex oblique offendit quo. Ad eos viris scripta postulant. Dolorem volumus eam id. Dicant consectetuer consequuntur et vim, ad sed saepe impedit. Vim ei error tibique. Vitae admodum est eu, mundi eligendi evertitur an vix. Pri doming dicunt repudiandae an, debitis inimicus has no.\n" + "Vidisse torquatos ius te, his ei nibh ornatus moderatius. Eu qui aperiam omittam albucius, at pro vivendo scriptorem. Has natum volumus suavitate eu, mazim consulatu imperdiet an nam. Id mei idque aliquid, ad cetero suavitate quo. Vel soluta ridens invenire id."; _bbsOptions.IndexToObject(); } _sampleBitmap = _bbsOptions.SampleBitmap; _inputBitmap = _bbsOptions.InputBitmap; _outputBitmap = _bbsOptions.OutputBitmap; _medianBitmap = _bbsOptions.MedianBitmap; propertyGridControlPack.DefaultEditors.AddRange(new[] { new DefaultEditor(typeof (bool), repositoryItemCheckEditBoolean), new DefaultEditor(typeof (int), repositoryItemSpinEditNumber), new DefaultEditor(typeof (string), repositoryItemTextEditString) }); propertyGridControlPack.RepositoryItems.AddRange(new RepositoryItem[] { repositoryItemComboBoxBarcode, repositoryItemComboBoxMixer, repositoryItemComboBoxGamma, repositoryItemComboBoxEcc, repositoryItemComboBoxArchiver, repositoryItemComboBoxPolitic, repositoryItemMemoEditPoliticText, repositoryItemCheckEditBoolean, repositoryItemSpinEditNumber, repositoryItemTextEditString }); propertyGridControlUnpack.DefaultEditors.AddRange(new[] { new DefaultEditor(typeof (bool), repositoryItemCheckEditBoolean), new DefaultEditor(typeof (int), repositoryItemSpinEditNumber), new DefaultEditor(typeof (string), repositoryItemTextEditString) }); propertyGridControlUnpack.RepositoryItems.AddRange(new RepositoryItem[] { repositoryItemComboBoxBarcode, repositoryItemComboBoxMixer, repositoryItemComboBoxGamma, repositoryItemComboBoxEcc, repositoryItemComboBoxArchiver, repositoryItemComboBoxPolitic, repositoryItemMemoEditPoliticText, repositoryItemCheckEditBoolean, repositoryItemSpinEditNumber, repositoryItemTextEditString }); ArchiverComboBoxItem1.Properties.RowEdit = ArchiverComboBoxItem.Properties.RowEdit.Clone() as RepositoryItem; EccComboBoxItem1.Properties.RowEdit = EccComboBoxItem.Properties.RowEdit.Clone() as RepositoryItem; MixerComboBoxItem1.Properties.RowEdit = MixerComboBoxItem.Properties.RowEdit.Clone() as RepositoryItem; GammaComboBoxItem1.Properties.RowEdit = GammaComboBoxItem.Properties.RowEdit.Clone() as RepositoryItem; BarcodeComboBoxItem1.Properties.RowEdit = BarcodeComboBoxItem.Properties.RowEdit.Clone() as RepositoryItem; PoliticComboBoxItem1.Properties.RowEdit = PoliticComboBoxItem.Properties.RowEdit.Clone() as RepositoryItem; PoliticText1.Properties.RowEdit = PoliticText.Properties.RowEdit.Clone() as RepositoryItem; ArchiverComboBoxItem2.Properties.RowEdit = ArchiverComboBoxItem.Properties.RowEdit.Clone() as RepositoryItem; EccComboBoxItem2.Properties.RowEdit = EccComboBoxItem.Properties.RowEdit.Clone() as RepositoryItem; MixerComboBoxItem2.Properties.RowEdit = MixerComboBoxItem.Properties.RowEdit.Clone() as RepositoryItem; GammaComboBoxItem2.Properties.RowEdit = GammaComboBoxItem.Properties.RowEdit.Clone() as RepositoryItem; propertyGridControlOptions.SelectedObject = _bbsOptions; propertyGridControlPack.SelectedObject = _bbsOptions; propertyGridControlUnpack.SelectedObject = _bbsOptions; openSampleDialog.Filter = openImageDialog.Filter = saveImageDialog.Filter = @"Bitmap Images (*.bmp)|*.bmp|All Files (*.*)|*.*"; saveFileDialog.Filter = openFileDialog.Filter = @"Rich Text Files (*.rtf)|*.rtf|All Files (*.*)|*.*"; }
public bool OptionsLoad() { if (openOptionsDialog.ShowDialog() != DialogResult.OK) return false; using (Stream stream = File.Open(openOptionsDialog.FileName, FileMode.Open)) _bbsOptions = (BbsOptions) new BinaryFormatter().Deserialize(stream); _bbsOptions.IndexToObject(); propertyGridControlOptions.SelectedObject = _bbsOptions; propertyGridControlPack.SelectedObject = _bbsOptions; propertyGridControlUnpack.SelectedObject = _bbsOptions; return true; }