/// <summary> /// The position in the original string where the first character of the captured substring was found. /// </summary> /// <param name="queryString"> /// The query string to search. /// </param> /// <returns> /// The zero-based starting position in the original string where the captured substring was found. /// </returns> public int MatchRegexIndex(string queryString) { this.SortOrder = int.MaxValue; Match match = this.RegexPattern.Match(queryString); if (match.Success) { this.SortOrder = match.Index; int maxSize; double maxSigma; int maxThreshold; int.TryParse(this.Processor.Settings["MaxSize"], NumberStyles.Any, CultureInfo.InvariantCulture, out maxSize); double.TryParse(this.Processor.Settings["MaxSigma"], NumberStyles.Any, CultureInfo.InvariantCulture, out maxSigma); int.TryParse(this.Processor.Settings["MaxThreshold"], NumberStyles.Any, CultureInfo.InvariantCulture, out maxThreshold); NameValueCollection queryCollection = HttpUtility.ParseQueryString(queryString); int size = QueryParamParser.Instance.ParseValue <int>(queryCollection["sharpen"]); // Fall back to default sigma. double sigma = queryCollection["sigma"] != null?QueryParamParser.Instance.ParseValue <double>(queryCollection["sigma"]) : 1.4d; int threshold = QueryParamParser.Instance.ParseValue <int>(queryCollection["threshold"]); // Normalize and set the variables. size = ImageMaths.Clamp(size, 0, maxSize); sigma = ImageMaths.Clamp(sigma, 0, maxSigma); threshold = ImageMaths.Clamp(threshold, 0, maxThreshold); this.Processor.DynamicParameter = new GaussianLayer(size, sigma, threshold); } return(this.SortOrder); }
public void ThenShouldUseMaxValueGivenValueGreaterThanMax(int maxValue, int value) { // Arrange //Act var result = ImageMaths.Clamp(value, int.MinValue, maxValue); // Assert Assert.That(result, Is.EqualTo(maxValue)); }
/// <summary> /// Changes the opacity of the current image. /// </summary> /// <param name="percentage"> /// The percentage by which to alter the images opacity. /// Any integer between 0 and 100. /// </param> /// <returns> /// The current instance of the <see cref="T:ImageProcessor.ImageFactory"/> class. /// </returns> public ImageFactory Alpha(int percentage) { if (this.ShouldProcess) { // Sanitize the input. percentage = ImageMaths.Clamp(percentage, 0, 100); Alpha alpha = new Alpha { DynamicParameter = percentage }; this.CurrentImageFormat.ApplyProcessor(alpha.ProcessImage, this); } return(this); }
/// <summary> /// The position in the original string where the first character of the captured substring was found. /// </summary> /// <param name="queryString">The query string to search.</param> /// <returns> /// The zero-based starting position in the original string where the captured substring was found. /// </returns> public int MatchRegexIndex(string queryString) { this.SortOrder = int.MaxValue; Match match = this.RegexPattern.Match(queryString); if (match.Success) { this.SortOrder = match.Index; NameValueCollection queryCollection = HttpUtility.ParseQueryString(queryString); int percentage = QueryParamParser.Instance.ParseValue <int>(queryCollection["brightness"]); percentage = ImageMaths.Clamp(percentage, -100, 100); this.Processor.DynamicParameter = percentage; } return(this.SortOrder); }
/// <summary> /// The position in the original string where the first character of the captured substring was found. /// </summary> /// <param name="queryString">The query string to search.</param> /// <returns> /// The zero-based starting position in the original string where the captured substring was found. /// </returns> public int MatchRegexIndex(string queryString) { this.SortOrder = int.MaxValue; Match match = this.RegexPattern.Match(queryString); if (match.Success) { this.SortOrder = match.Index; NameValueCollection queryCollection = HttpUtility.ParseQueryString(queryString); Color[] colors = QueryParamParser.Instance.ParseValue <Color[]>(queryCollection["replace"]); int fuzziness = QueryParamParser.Instance.ParseValue <int>(queryCollection["fuzziness"]); fuzziness = ImageMaths.Clamp(fuzziness, 0, 128); this.Processor.DynamicParameter = new Tuple <Color, Color, int>(colors[0], colors[1], fuzziness); } return(this.SortOrder); }
/// <summary> /// The position in the original string where the first character of the captured substring was found. /// </summary> /// <param name="queryString">The query string to search.</param> /// <returns> /// The zero-based starting position in the original string where the captured substring was found. /// </returns> public int MatchRegexIndex(string queryString) { this.SortOrder = int.MaxValue; Match match = this.RegexPattern.Match(queryString); if (match.Success) { this.SortOrder = match.Index; NameValueCollection queryCollection = HttpUtility.ParseQueryString(queryString); int degrees = QueryParamParser.Instance.ParseValue <int>(queryCollection["hue"]); bool rotate = QueryParamParser.Instance.ParseValue <bool>(queryCollection["hue.rotate"]); degrees = ImageMaths.Clamp(degrees, 0, 360); this.Processor.DynamicParameter = new Tuple <int, bool>(degrees, rotate); } return(this.SortOrder); }
/// <summary> /// Sets the resolution of the image. /// <remarks> /// This method sets both the bitmap data and EXIF resolution if available. /// </remarks> /// </summary> /// <param name="horizontal">The horizontal resolution.</param> /// <param name="vertical">The vertical resolution.</param> /// <param name="unit"> /// The unit of measure for the horizontal resolution and the vertical resolution. /// Defaults to inches /// </param> /// <returns> /// The <see cref="ImageFactory"/>. /// </returns> public ImageFactory Resolution(int horizontal, int vertical, PropertyTagResolutionUnit unit = PropertyTagResolutionUnit.Inch) { if (this.ShouldProcess) { // Sanitize the input. horizontal = ImageMaths.Clamp(horizontal, 0, int.MaxValue); vertical = ImageMaths.Clamp(vertical, 0, int.MaxValue); Tuple <int, int, PropertyTagResolutionUnit> resolution = new Tuple <int, int, PropertyTagResolutionUnit>(horizontal, vertical, unit); Resolution dpi = new Resolution { DynamicParameter = resolution }; this.CurrentImageFormat.ApplyProcessor(dpi.ProcessImage, this); } return(this); }
/// <summary> /// Converts an <see cref="T:System.Double"/> value into a valid <see cref="T:System.Byte"/>. /// <remarks> /// If the value given is less than 0 or greater than 255, the value will be constrained into /// those restricted ranges. /// </remarks> /// </summary> /// <param name="value"> /// The <see cref="T:System.Double"/> to convert. /// </param> /// <returns> /// The <see cref="T:System.Byte"/>. /// </returns> public static byte ToByte(this double value) { return(Convert.ToByte(ImageMaths.Clamp(value, 0, 255))); }
/// <summary> /// Checks the range of the given value to ensure that it remains within the acceptable boundaries. /// </summary> /// <param name="value"> /// The value to check. /// </param> /// <returns> /// The sanitized <see cref="float"/>. /// </returns> private static float Clamp(float value) { return(ImageMaths.Clamp(value, 0, 100)); }
/// <summary> /// Initializes a new instance of the <see cref="YCbCrColor"/> struct. /// </summary> /// <param name="y">The y luminance component.</param> /// <param name="cb">The u chroma component.</param> /// <param name="cr">The v chroma component.</param> private YCbCrColor(float y, float cb, float cr) { _y = ImageMaths.Clamp(y, 0, 255); _cb = ImageMaths.Clamp(cb, 0, 255); _cr = ImageMaths.Clamp(cr, 0, 255); }
/// <summary> /// Converts an <see cref="T:System.Int32"/> value into a valid <see cref="T:System.Byte"/>. /// <remarks> /// If the value given is less than 0 or greater than 255, the value will be constrained into /// those restricted ranges. /// </remarks> /// </summary> /// <param name="value"> /// The <see cref="T:System.Int32"/> to convert. /// </param> /// <returns> /// The <see cref="T:System.Byte"/>. /// </returns> public static byte ToByte(this int value) => Convert.ToByte(ImageMaths.Clamp(value, 0, 255));
/// <summary> /// Checks the range of the given value to ensure that it remains within the acceptable boundaries. /// </summary> /// <param name="value"> /// The value to check. /// </param> /// <returns> /// The sanitized <see cref="float"/>. /// </returns> private static float Clamp(float value) => ImageMaths.Clamp(value, 0, 100);
/// <summary> /// Initializes a new instance of the <see cref="YCbCrColor"/> struct. /// </summary> /// <param name="y">The y luminance component.</param> /// <param name="cb">The u chroma component.</param> /// <param name="cr">The v chroma component.</param> private YCbCrColor(float y, float cb, float cr) { this.y = ImageMaths.Clamp(y, 0, 255); this.cb = ImageMaths.Clamp(cb, 0, 255); this.cr = ImageMaths.Clamp(cr, 0, 255); }
/// <summary> /// Applies the halftone filter. /// </summary> /// <param name="source"> /// The <see cref="Bitmap"/> to apply the filter to. /// </param> /// <returns> /// The <see cref="Bitmap"/> with the filter applied. /// </returns> public Bitmap ApplyFilter(Bitmap source) { // TODO: Make this class implement an interface? Bitmap cyan = null; Bitmap magenta = null; Bitmap yellow = null; Bitmap keyline = null; Bitmap newImage = null; try { int width = source.Width; int height = source.Height; // Calculate min and max widths/heights. Rectangle rotatedBounds = this.GetBoundingRectangle(width, height); int minY = -(rotatedBounds.Height + height); int maxY = rotatedBounds.Height + height; int minX = -(rotatedBounds.Width + width); int maxX = rotatedBounds.Width + width; Point center = Point.Empty; // Yellow oversaturates the output. const float YellowMultiplier = 4; float multiplier = YellowMultiplier * (float)Math.Sqrt(2); float max = this.distance; // Bump up the keyline max so that black looks black. float keylineMax = max + ((float)Math.Sqrt(2) * 1.44f); // Color sampled process colours from Wikipedia pages. // Keyline brush is declared separately. Brush cyanBrush = new SolidBrush(Color.FromArgb(0, 183, 235)); Brush magentaBrush = new SolidBrush(Color.FromArgb(255, 0, 144)); Brush yellowBrush = new SolidBrush(Color.FromArgb(255, 239, 0)); // Create our images. cyan = new Bitmap(width, height); magenta = new Bitmap(width, height); yellow = new Bitmap(width, height); keyline = new Bitmap(width, height); newImage = new Bitmap(width, height); // Ensure the correct resolution is set. cyan.SetResolution(source.HorizontalResolution, source.VerticalResolution); magenta.SetResolution(source.HorizontalResolution, source.VerticalResolution); yellow.SetResolution(source.HorizontalResolution, source.VerticalResolution); keyline.SetResolution(source.HorizontalResolution, source.VerticalResolution); newImage.SetResolution(source.HorizontalResolution, source.VerticalResolution); // Check bounds against this. Rectangle rectangle = new Rectangle(0, 0, width, height); using (Graphics graphicsCyan = Graphics.FromImage(cyan)) using (Graphics graphicsMagenta = Graphics.FromImage(magenta)) using (Graphics graphicsYellow = Graphics.FromImage(yellow)) using (Graphics graphicsKeyline = Graphics.FromImage(keyline)) { // Set the quality properties. graphicsCyan.PixelOffsetMode = PixelOffsetMode.HighQuality; graphicsMagenta.PixelOffsetMode = PixelOffsetMode.HighQuality; graphicsYellow.PixelOffsetMode = PixelOffsetMode.HighQuality; graphicsKeyline.PixelOffsetMode = PixelOffsetMode.HighQuality; // Set up the canvas. graphicsCyan.Clear(Color.Transparent); graphicsMagenta.Clear(Color.Transparent); graphicsYellow.Clear(Color.Transparent); graphicsKeyline.Clear(Color.Transparent); int d = this.distance; // This is too slow. The graphics object can't be called within a parallel // loop so we have to do it old school. :( using (FastBitmap sourceBitmap = new FastBitmap(source)) { for (int y = minY; y < maxY; y += d) { for (int x = minX; x < maxX; x += d) { Color color; CmykColor cmykColor; float brushWidth; int offsetX = x - (d >> 1); int offsetY = y - (d >> 1); // Cyan Point rotatedPoint = ImageMaths.RotatePoint(new Point(offsetX, offsetY), this.cyanAngle, center); int angledX = rotatedPoint.X; int angledY = rotatedPoint.Y; if (rectangle.Contains(new Point(angledX, angledY))) { color = sourceBitmap.GetPixel(angledX, angledY); cmykColor = color; brushWidth = ImageMaths.Clamp(d * (cmykColor.C / 255f) * multiplier, 0, max); graphicsCyan.FillEllipse(cyanBrush, angledX, angledY, brushWidth, brushWidth); } // Magenta rotatedPoint = ImageMaths.RotatePoint(new Point(offsetX, offsetY), this.magentaAngle, center); angledX = rotatedPoint.X; angledY = rotatedPoint.Y; if (rectangle.Contains(new Point(angledX, angledY))) { color = sourceBitmap.GetPixel(angledX, angledY); cmykColor = color; brushWidth = ImageMaths.Clamp(d * (cmykColor.M / 255f) * multiplier, 0, max); graphicsMagenta.FillEllipse(magentaBrush, angledX, angledY, brushWidth, brushWidth); } // Yellow rotatedPoint = ImageMaths.RotatePoint(new Point(offsetX, offsetY), this.yellowAngle, center); angledX = rotatedPoint.X; angledY = rotatedPoint.Y; if (rectangle.Contains(new Point(angledX, angledY))) { color = sourceBitmap.GetPixel(angledX, angledY); cmykColor = color; brushWidth = ImageMaths.Clamp(d * (cmykColor.Y / 255f) * YellowMultiplier, 0, max); graphicsYellow.FillEllipse(yellowBrush, angledX, angledY, brushWidth, brushWidth); } // Keyline rotatedPoint = ImageMaths.RotatePoint(new Point(offsetX, offsetY), this.keylineAngle, center); angledX = rotatedPoint.X; angledY = rotatedPoint.Y; if (rectangle.Contains(new Point(angledX, angledY))) { color = sourceBitmap.GetPixel(angledX, angledY); cmykColor = color; brushWidth = ImageMaths.Clamp(d * (cmykColor.K / 255f) * multiplier, 0, keylineMax); // Just using black is too dark. Brush keylineBrush = new SolidBrush(CmykColor.FromCmykColor(0, 0, 0, cmykColor.K)); graphicsKeyline.FillEllipse(keylineBrush, angledX, angledY, brushWidth, brushWidth); } } } } // Set our white background. using (Graphics graphics = Graphics.FromImage(newImage)) { graphics.Clear(Color.White); } // Blend the colors now to mimic adaptive blending. using (FastBitmap cyanBitmap = new FastBitmap(cyan)) using (FastBitmap magentaBitmap = new FastBitmap(magenta)) using (FastBitmap yellowBitmap = new FastBitmap(yellow)) using (FastBitmap keylineBitmap = new FastBitmap(keyline)) using (FastBitmap destinationBitmap = new FastBitmap(newImage)) { Parallel.For( 0, height, y => { for (int x = 0; x < width; x++) { // ReSharper disable AccessToDisposedClosure Color cyanPixel = cyanBitmap.GetPixel(x, y); Color magentaPixel = magentaBitmap.GetPixel(x, y); Color yellowPixel = yellowBitmap.GetPixel(x, y); Color keylinePixel = keylineBitmap.GetPixel(x, y); CmykColor blended = cyanPixel.AddAsCmykColor(magentaPixel, yellowPixel, keylinePixel); if (rectangle.Contains(new Point(x, y))) { destinationBitmap.SetPixel(x, y, blended); } // ReSharper restore AccessToDisposedClosure } }); } } cyan.Dispose(); magenta.Dispose(); yellow.Dispose(); keyline.Dispose(); source.Dispose(); source = newImage; } catch { if (cyan != null) { cyan.Dispose(); } if (magenta != null) { magenta.Dispose(); } if (yellow != null) { yellow.Dispose(); } if (keyline != null) { keyline.Dispose(); } if (newImage != null) { newImage.Dispose(); } } return(source); }
/// <summary> /// Converts an <see cref="T:System.Float"/> value into a valid <see cref="T:System.Byte"/>. /// <remarks> /// If the value given is less than 0 or greater than 255, the value will be constrained into /// those restricted ranges. /// </remarks> /// </summary> /// <param name="value"> /// The <see cref="T:System.Float"/> to convert. /// </param> /// <returns> /// The <see cref="T:System.Byte"/>. /// </returns> public static byte ToByte(this float value) => Convert.ToByte(ImageMaths.Clamp(value, byte.MinValue, byte.MaxValue));