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 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; // Количество битов в байте #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; } }