Example #1
0
        /// <summary>
        /// Applies color filter to image.
        /// (Safer if source image was compressed, may be additional bytes per row)
        /// </summary>
        /// <param name="imageBytes">Color image bytes to process</param>
        /// <param name="r">Red component to apply</param>
        /// <param name="g">Green component to apply</param>
        /// <param name="b">Blue component to apply</param>
        /// <param name="bmpData">Image dimension info</param>
        public static void ApplyFilterDirectRGB(byte[] imageBytes, byte r, byte g, byte b, BitmapData bmpData)
        {
            if (!bmpData.IsColor())
            {
                throw new ArgumentException("Image is not color, RGB filter cannot be applied.");
            }

            int stride        = bmpData.Stride;
            int stridePadding = bmpData.GetStridePaddingLength();
            int width         = stride - stridePadding;
            int height        = bmpData.Height;
            int limit         = bmpData.GetSafeArrayLimitForImage(imageBytes);

            // May also have alpha byte
            int pixelDepth = bmpData.GetPixelDepth();

            // Apply mask for each color pixel
            for (int y = 0; y < height; y++)
            {
                // Images may have extra bytes per row to pad for CPU addressing.
                // so need to ensure we traverse to the correct byte when moving between rows.
                // I.e. not divisible by 3
                int offset = y * stride;

                for (int x = 0; x < width; x += pixelDepth)
                {
                    int i = offset + x;

                    if (i < limit)
                    {
                        // Red (LSB)
                        imageBytes[i + 2] &= r;

                        // Green
                        imageBytes[i + 1] &= g;

                        // Blue (MSB)
                        imageBytes[i] &= b;
                    }
                }
            }
        }
        /// <summary>
        /// Any pixel values below threshold will be changed to 0 (black).
        /// Any pixel values above (or equal to) threshold will be changed to 255 (white).
        /// </summary>
        /// <param name="imageBytes">Image bytes</param>
        /// <param name="bitmapData">Pixel depth</param>
        /// <param name="threshold">Threshold value</param>
        private static void ApplyDirect(byte[] imageBytes, BitmapData bitmapData, byte threshold)
        {
            if (bitmapData.IsColor())
            {
                int pixelDepth = bitmapData.GetPixelDepth();
                int stride     = bitmapData.Stride;
                int width      = bitmapData.GetStrideWithoutPadding();
                int height     = bitmapData.Height;

                int limit = bitmapData.GetSafeArrayLimitForImage(imageBytes);

                // Exclude alpha/transparency byte when averaging
                int thresholdByteLength = Math.Min(pixelDepth, Constants.PixelDepthRGB);

                int  pixelSum;
                bool belowThreshold;

                // Find distribution of pixels at each level
                for (int y = 0; y < height; y++)
                {
                    // Images may have extra bytes per row to pad for CPU addressing.
                    // so need to ensure we traverse to the correct byte when moving between rows.
                    int offset = y * stride;

                    for (int x = 0; x < width; x += pixelDepth)
                    {
                        int i = offset + x;

                        if (i < limit)
                        {
                            pixelSum = 0;

                            // Sum each pixel component
                            for (int j = 0; j < thresholdByteLength && i + j < imageBytes.Length; j++)
                            {
                                pixelSum += imageBytes[i + j];
                            }

                            // Compare average to threshold
                            belowThreshold = (pixelSum / thresholdByteLength) < threshold;

                            // Apply threshold
                            for (int j = 0; j < thresholdByteLength && i + j < imageBytes.Length; j++)
                            {
                                imageBytes[i + j] = belowThreshold ? byte.MinValue : byte.MaxValue;
                            }
                        }
                        else
                        {
                            break;
                        }
                    }
                }
            }
            else
            {
                // Apply threshold value to image
                for (int i = 0; i < imageBytes.Length; i++)
                {
                    imageBytes[i] = imageBytes[i] < threshold ? byte.MinValue : byte.MaxValue;
                }
            }
        }
        /// <summary>
        /// Stretches image contrast to specified min/max values.
        /// </summary>
        /// <param name="imageBytes">Image bytes (Grayscale/RGB)</param>
        /// <param name="bmpData">Info on image properties</param>
        /// <param name="min">Minimum contrast value</param>
        /// <param name="max">Maximum contrast value</param>
        public static void StretchDirect(byte[] imageBytes, BitmapData bmpData, byte min, byte max)
        {
            int  pixelDepth = bmpData.GetPixelDepth();
            bool isColor    = bmpData.IsColor();

            // Initialize with opposite values
            byte highest = byte.MinValue;
            byte lowest  = byte.MaxValue;
            byte val;

            // Bitmap converted from jpeg can potentially have array with extra odd byte.
            int limit = bmpData.GetSafeArrayLimitForImage(imageBytes);

            //////////////////////////////////////
            // First find current contrast range
            //////////////////////////////////////
            for (int i = 0; i < limit; i += pixelDepth)
            {
                if (isColor)
                {
                    val = (byte)((imageBytes[i] + imageBytes[i + 1] + imageBytes[i + 2]) / 3);
                }
                else
                {
                    val = imageBytes[i];
                }

                // Check contrast ranges
                if (val < lowest)
                {
                    lowest = val;
                }

                if (val > highest)
                {
                    highest = val;
                }
            }

            // Constant for loop
            double maxMinusMin = max - min;

            // Exclude alpha/transparency byte
            int pixelDepthWithoutAlpha = Math.Min(pixelDepth, Constants.PixelDepthRGB);

            //////////////////////////////////////
            // Now contrast stretch image
            //////////////////////////////////////
            for (int i = 0; i < limit; i += pixelDepth)
            {
                for (int j = 0; j < pixelDepthWithoutAlpha; j++)
                {
                    // Contrast-stretch value
                    val = (byte)(((imageBytes[i + j] - lowest) * (maxMinusMin / (highest - lowest))) + min);

                    // Check limits
                    if (val < lowest)
                    {
                        val = min;
                    }
                    else if (val > highest)
                    {
                        val = max;
                    }

                    imageBytes[i + j] = val;
                }
            }
        }