diff --git a/src/ImageProcessor.Playground/Program.cs b/src/ImageProcessor.Playground/Program.cs index 52e0157b7..6f8796d7c 100644 --- a/src/ImageProcessor.Playground/Program.cs +++ b/src/ImageProcessor.Playground/Program.cs @@ -54,20 +54,25 @@ namespace ImageProcessor.PlayGround //FileInfo fileInfo = new FileInfo(Path.Combine(resolvedPath, "2008.jpg")); //FileInfo fileInfo = new FileInfo(Path.Combine(resolvedPath, "stretched.jpg")); //FileInfo fileInfo = new FileInfo(Path.Combine(resolvedPath, "mountain.jpg")); + FileInfo fileInfo = new FileInfo(Path.Combine(resolvedPath, "blur-test.png")); + + //FileInfo fileInfo = new FileInfo(Path.Combine(resolvedPath, "gamma-1.0-or-2.2.png")); + //FileInfo fileInfo = new FileInfo(Path.Combine(resolvedPath, "gamma_dalai_lama_gray.jpg")); //FileInfo fileInfo = new FileInfo(Path.Combine(resolvedPath, "Arc-de-Triomphe-France.jpg")); //FileInfo fileInfo = new FileInfo(Path.Combine(resolvedPath, "Martin-Schoeller-Jack-Nicholson-Portrait.jpeg")); - //FileInfo fileInfo = new FileInfo(Path.Combine(resolvedPath, "crop-base-300x200.jpg")); + ////FileInfo fileInfo = new FileInfo(Path.Combine(resolvedPath, "crop-base-300x200.jpg")); //FileInfo fileInfo = new FileInfo(Path.Combine(resolvedPath, "cmyk.png")); //IEnumerable files = GetFilesByExtensions(di, ".gif"); - IEnumerable files = GetFilesByExtensions(di, ".jpg", ".jpeg", ".jfif"); + //IEnumerable files = GetFilesByExtensions(di, ".png"); + //IEnumerable files = GetFilesByExtensions(di, ".jpg", ".jpeg", ".jfif"); //IEnumerable files = GetFilesByExtensions(di, ".gif", ".webp", ".bmp", ".jpg", ".png", ".tif"); - foreach (FileInfo fileInfo in files) - { - if (fileInfo.Name == "test5.jpg") - { - continue; - } + //foreach (FileInfo fileInfo in files) + //{ + // if (fileInfo.Name == "test5.jpg") + // { + // continue; + // } byte[] photoBytes = File.ReadAllBytes(fileInfo.FullName); Console.WriteLine("Processing: " + fileInfo.Name); @@ -78,9 +83,9 @@ namespace ImageProcessor.PlayGround // ImageProcessor using (MemoryStream inStream = new MemoryStream(photoBytes)) { - using (ImageFactory imageFactory = new ImageFactory(true)) + using (ImageFactory imageFactory = new ImageFactory(true, true)) { - Size size = new Size(1024, 0); + Size size = new Size(500, 0); CropLayer cropLayer = new CropLayer(20, 20, 20, 20, ImageProcessor.Imaging.CropMode.Percentage); //ResizeLayer layer = new ResizeLayer(size, ResizeMode.Max, AnchorPosition.Center, false); @@ -109,10 +114,11 @@ namespace ImageProcessor.PlayGround // .Resize(new ResizeLayer(size, ResizeMode.Stretch)) //.DetectEdges(new Laplacian3X3EdgeFilter(), true) //.DetectEdges(new LaplacianOfGaussianEdgeFilter()) + .GaussianBlur(new GaussianLayer(10, 11)) //.EntropyCrop() - //.Halftone(true) + //.Halftone(false) //.RotateBounded(150, false) - .Crop(cropLayer) + //.Crop(cropLayer) //.Rotate(140) //.Filter(MatrixFilters.Invert) //.Contrast(50) @@ -124,7 +130,7 @@ namespace ImageProcessor.PlayGround //.Format(new PngFormat() { IsIndexed = true }) //.Format(new PngFormat() ) .Save(Path.GetFullPath(Path.Combine(Path.GetDirectoryName(path), @"..\..\images\output", fileInfo.Name))); - //.Save(Path.GetFullPath(Path.Combine(Path.GetDirectoryName(path), @"..\..\images\output", Path.GetFileNameWithoutExtension(fileInfo.Name) + ".png"))); + //.Save(Path.GetFullPath(Path.Combine(Path.GetDirectoryName(path), @"..\..\images\output", Path.GetFileNameWithoutExtension(fileInfo.Name) + ".png"))); stopwatch.Stop(); } @@ -136,7 +142,7 @@ namespace ImageProcessor.PlayGround Console.WriteLine(@"Completed {0} in {1:s\.fff} secs {2}Peak memory usage was {3} bytes or {4} Mb.", fileInfo.Name, stopwatch.Elapsed, Environment.NewLine, peakWorkingSet64.ToString("#,#"), mB); //Console.WriteLine("Processed: " + fileInfo.Name + " in " + stopwatch.ElapsedMilliseconds + "ms"); - } + //} Console.ReadLine(); } diff --git a/src/ImageProcessor.Playground/images/input/Calliphora_sp_Portrait.jpg.REMOVED.git-id b/src/ImageProcessor.Playground/images/input/Calliphora_sp_Portrait.jpg.REMOVED.git-id new file mode 100644 index 000000000..44bed7ad3 --- /dev/null +++ b/src/ImageProcessor.Playground/images/input/Calliphora_sp_Portrait.jpg.REMOVED.git-id @@ -0,0 +1 @@ +5d446f64d0636f6ad7e9f82625eeff89ef394fe2 \ No newline at end of file diff --git a/src/ImageProcessor.Playground/images/input/PIA11667_modest.jpg b/src/ImageProcessor.Playground/images/input/PIA11667_modest.jpg new file mode 100644 index 000000000..f9b7e376d --- /dev/null +++ b/src/ImageProcessor.Playground/images/input/PIA11667_modest.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:791e93fab90cd16561f33bb5a69d74ded08f828939d74cd3693ec23a629dd6e5 +size 12354 diff --git a/src/ImageProcessor.Playground/images/input/blur-test.jpg b/src/ImageProcessor.Playground/images/input/blur-test.jpg new file mode 100644 index 000000000..9b535bd03 --- /dev/null +++ b/src/ImageProcessor.Playground/images/input/blur-test.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:35e2ad14d4315b2d52b5022741420214614afc9a6c781e784d6c8644f07c44ef +size 10879 diff --git a/src/ImageProcessor.Playground/images/input/blur-test.png b/src/ImageProcessor.Playground/images/input/blur-test.png new file mode 100644 index 000000000..8f2d2ef53 --- /dev/null +++ b/src/ImageProcessor.Playground/images/input/blur-test.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:08a4072d090b489c23aac01e05a2d1a758db76ed7706c0655686810721aa148c +size 3563 diff --git a/src/ImageProcessor.Playground/images/input/gamma-1.0-or-2.2.png b/src/ImageProcessor.Playground/images/input/gamma-1.0-or-2.2.png new file mode 100644 index 000000000..953689f45 --- /dev/null +++ b/src/ImageProcessor.Playground/images/input/gamma-1.0-or-2.2.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:01a558cd936c4972954baaa163d4cb584fbf52133e5287fff5f8d74402107b46 +size 4195 diff --git a/src/ImageProcessor.Playground/images/input/gamma_3x3.jpg b/src/ImageProcessor.Playground/images/input/gamma_3x3.jpg new file mode 100644 index 000000000..16c2fdb51 --- /dev/null +++ b/src/ImageProcessor.Playground/images/input/gamma_3x3.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c7ba67fed963f782895f8450a5657ab8aa9f53136214d52bb93adc2b1cf823ab +size 29596 diff --git a/src/ImageProcessor.Playground/images/input/gamma_colors.jpg b/src/ImageProcessor.Playground/images/input/gamma_colors.jpg new file mode 100644 index 000000000..050e2f8eb --- /dev/null +++ b/src/ImageProcessor.Playground/images/input/gamma_colors.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7f21bb17e7a751d186e3065316ff1768824e43d98ecc419b0a0ecec08dd96a9c +size 15109 diff --git a/src/ImageProcessor.Playground/images/input/gamma_dalai_lama_gray.jpg.REMOVED.git-id b/src/ImageProcessor.Playground/images/input/gamma_dalai_lama_gray.jpg.REMOVED.git-id new file mode 100644 index 000000000..c6c87c96c --- /dev/null +++ b/src/ImageProcessor.Playground/images/input/gamma_dalai_lama_gray.jpg.REMOVED.git-id @@ -0,0 +1 @@ +56cbc3371def2882d1ead5d4d2456550f2b8d72c \ No newline at end of file diff --git a/src/ImageProcessor.Playground/images/input/gamma_rainbow.jpg b/src/ImageProcessor.Playground/images/input/gamma_rainbow.jpg new file mode 100644 index 000000000..9b155e4f1 --- /dev/null +++ b/src/ImageProcessor.Playground/images/input/gamma_rainbow.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:234449776aad96cc39160a4fbe2f76cecdfa9412f92358c16a4e36d6ea7f9e4c +size 47557 diff --git a/src/ImageProcessor.Web/HttpModules/ImageProcessingModule.cs b/src/ImageProcessor.Web/HttpModules/ImageProcessingModule.cs index 73e44778f..4b482b16e 100644 --- a/src/ImageProcessor.Web/HttpModules/ImageProcessingModule.cs +++ b/src/ImageProcessor.Web/HttpModules/ImageProcessingModule.cs @@ -340,7 +340,7 @@ namespace ImageProcessor.Web.HttpModules else { // Parse any protocol values from settings. - string protocol = currentService.Settings["Protocol"] != null + string protocol = currentService.Settings.ContainsKey("Protocol") ? currentService.Settings["Protocol"] + "://" : string.Empty; diff --git a/src/ImageProcessor.Web/Processors/Resize.cs b/src/ImageProcessor.Web/Processors/Resize.cs index 59b397358..e8dc9bda7 100644 --- a/src/ImageProcessor.Web/Processors/Resize.cs +++ b/src/ImageProcessor.Web/Processors/Resize.cs @@ -115,7 +115,7 @@ namespace ImageProcessor.Web.Processors // TODO: This is hacky and awful and should go. if (match.Value.ToUpperInvariant().Contains("CARVE") || match.Value.ToUpperInvariant().Contains("PERCENT")) { - break; + continue; } if (index == 0) diff --git a/src/ImageProcessor/ImageFactory.cs b/src/ImageProcessor/ImageFactory.cs index 3f63979c9..ffc86d7a8 100644 --- a/src/ImageProcessor/ImageFactory.cs +++ b/src/ImageProcessor/ImageFactory.cs @@ -63,10 +63,14 @@ namespace ImageProcessor /// /// Whether to preserve exif metadata. Defaults to false. /// - public ImageFactory(bool preserveExifData = false) + /// + /// Whether to fix the gamma component of the image. Defaults to true. + /// + public ImageFactory(bool preserveExifData = false, bool fixGamma = true) { this.PreserveExifData = preserveExifData; this.ExifPropertyItems = new ConcurrentDictionary(); + this.FixGamma = fixGamma; } #endregion @@ -111,6 +115,11 @@ namespace ImageProcessor /// public bool PreserveExifData { get; set; } + /// + /// Gets or sets a value indicating whether to fix the gamma component of the current image. + /// + public bool FixGamma { get; set; } + /// /// Gets or sets the exif property items. /// @@ -179,6 +188,12 @@ namespace ImageProcessor this.ShouldProcess = true; + // Normalize the gamma component of the image. + if (this.FixGamma) + { + this.Gamma(2.2F); + } + return this; } @@ -233,6 +248,12 @@ namespace ImageProcessor } this.ShouldProcess = true; + + // Normalize the gamma component of the image. + if (this.FixGamma) + { + this.Gamma(2.2F); + } } } else @@ -560,6 +581,32 @@ namespace ImageProcessor return this; } + /// + /// Adjust the gamma (intensity of the light) component of the given image. + /// + /// + /// The value to adjust the gamma by (typically between .2 and 5). + /// + /// + /// The current instance of the class. + /// + public ImageFactory Gamma(float value) + { + if (this.ShouldProcess) + { + // Sanitize the input. + if (value > 5 || value < .1) + { + value = 2.2F; + } + + Gamma gamma = new Gamma { DynamicParameter = value }; + this.CurrentImageFormat.ApplyProcessor(gamma.ProcessImage, this); + } + + return this; + } + /// /// Uses a Gaussian kernel to blur the current image. /// @@ -1091,6 +1138,12 @@ namespace ImageProcessor directoryInfo.Create(); } + // Normalize the gamma component of the image. + if (this.FixGamma) + { + this.Gamma(1 / 2.2F); + } + this.Image = this.CurrentImageFormat.Save(filePath, this.Image); } @@ -1112,6 +1165,13 @@ namespace ImageProcessor { // Allow the same stream to be used as for input. stream.SetLength(0); + + // Normalize the gamma component of the image. + if (this.FixGamma) + { + this.Gamma(1 / 2.2F); + } + this.Image = this.CurrentImageFormat.Save(stream, this.Image); stream.Position = 0; } diff --git a/src/ImageProcessor/ImageProcessor.csproj b/src/ImageProcessor/ImageProcessor.csproj index 5e2977ed4..c55f51fd2 100644 --- a/src/ImageProcessor/ImageProcessor.csproj +++ b/src/ImageProcessor/ImageProcessor.csproj @@ -216,6 +216,7 @@ + diff --git a/src/ImageProcessor/Imaging/Convolution.cs b/src/ImageProcessor/Imaging/Convolution.cs index 554375b6d..0c9d82051 100644 --- a/src/ImageProcessor/Imaging/Convolution.cs +++ b/src/ImageProcessor/Imaging/Convolution.cs @@ -335,6 +335,10 @@ namespace ImageProcessor.Imaging green += k * color.G; blue += k * color.B; alpha += k * color.A; + //red += k * (color.R * color.R); + //green += k * (color.G * color.G); + //blue += k * (color.B * color.B); + //alpha += k * (color.A * color.A); processedKernelSize++; } @@ -360,6 +364,11 @@ namespace ImageProcessor.Imaging // Check and apply the divider if ((long)divider != 0) { + //red = Math.Sqrt(red / divider); + //green = Math.Sqrt(green / divider); + //blue = Math.Sqrt(blue / divider); + //alpha = Math.Sqrt(alpha / divider); + red /= divider; green /= divider; blue /= divider; diff --git a/src/ImageProcessor/Imaging/Helpers/Adjustments.cs b/src/ImageProcessor/Imaging/Helpers/Adjustments.cs index bef3e864c..0d4ea2d4f 100644 --- a/src/ImageProcessor/Imaging/Helpers/Adjustments.cs +++ b/src/ImageProcessor/Imaging/Helpers/Adjustments.cs @@ -15,6 +15,8 @@ namespace ImageProcessor.Imaging.Helpers using System.Drawing.Imaging; using System.Threading.Tasks; + using ImageProcessor.Common.Extensions; + /// /// Provides reusable adjustment methods to apply to images. /// @@ -144,7 +146,7 @@ namespace ImageProcessor.Imaging.Helpers throw new ArgumentOutOfRangeException("threshold", "Threshold should be between -100 and 100."); } - Rectangle bounds = rectangle.HasValue ? rectangle.Value : new Rectangle(0, 0, source.Width, source.Height); + Rectangle bounds = rectangle ?? new Rectangle(0, 0, source.Width, source.Height); float contrastFactor = (float)threshold / 100; @@ -174,5 +176,46 @@ namespace ImageProcessor.Imaging.Helpers return (Bitmap)source; } + + /// + /// Adjust the gamma (intensity of the light) component of the given image. + /// + /// + /// The source to adjust. + /// + /// + /// The value to adjust the gamma by (typically between .2 and 5). + /// + /// + /// The with the gamma adjusted. + /// + /// + /// Thrown if the value falls outside the acceptable range. + /// + public static Bitmap Gamma(Image source, float value) + { + if (value > 5 || value < .1) + { + throw new ArgumentOutOfRangeException("value", "Value should be between .1 and 5."); + } + + int width = source.Width; + int height = source.Height; + Bitmap destination = new Bitmap(width, height); + destination.SetResolution(source.HorizontalResolution, source.VerticalResolution); + + Rectangle rectangle = new Rectangle(0, 0, width, height); + using (Graphics graphics = Graphics.FromImage(destination)) + { + using (ImageAttributes attributes = new ImageAttributes()) + { + attributes.SetGamma(value); + graphics.DrawImage(source, rectangle, 0, 0, width, height, GraphicsUnit.Pixel, attributes); + } + } + + source.Dispose(); + return destination; + } } } diff --git a/src/ImageProcessor/Imaging/Quantizers/OctreeQuantizer.cs b/src/ImageProcessor/Imaging/Quantizers/OctreeQuantizer.cs index eb5014f7b..4f9496fba 100644 --- a/src/ImageProcessor/Imaging/Quantizers/OctreeQuantizer.cs +++ b/src/ImageProcessor/Imaging/Quantizers/OctreeQuantizer.cs @@ -16,6 +16,7 @@ namespace ImageProcessor.Imaging.Quantizers using System.Drawing; using System.Drawing.Imaging; + using ImageProcessor.Common.Extensions; using ImageProcessor.Imaging.Colors; /// @@ -505,9 +506,15 @@ namespace ImageProcessor.Imaging.Quantizers { // Consume the next palette index this.paletteIndex = index++; + //int r = Math.Abs(this.red / this.pixelCount); + //int g = Math.Abs(this.green / this.pixelCount); + //int b = Math.Abs(this.blue / this.pixelCount); + int r = (this.red / this.pixelCount).ToByte(); + int g = (this.green / this.pixelCount).ToByte(); + int b = (this.blue / this.pixelCount).ToByte(); // And set the color of the palette entry - palette.Add(Color.FromArgb(this.red / this.pixelCount, this.green / this.pixelCount, this.blue / this.pixelCount)); + palette.Add(Color.FromArgb(r, g, b)); } else { diff --git a/src/ImageProcessor/Processors/Gamma.cs b/src/ImageProcessor/Processors/Gamma.cs new file mode 100644 index 000000000..09ce69548 --- /dev/null +++ b/src/ImageProcessor/Processors/Gamma.cs @@ -0,0 +1,90 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) James South. +// Licensed under the Apache License, Version 2.0. +// +// +// Encapsulates methods to change the alpha component of the image to effect its luminance. +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace ImageProcessor.Processors +{ + using System; + using System.Collections.Generic; + using System.Drawing; + + using ImageProcessor.Common.Exceptions; + using ImageProcessor.Imaging.Helpers; + + /// + /// Encapsulates methods to change the gamma component of the image to effect its luminance. + /// + public class Gamma : IGraphicsProcessor + { + /// + /// Initializes a new instance of the class. + /// + public Gamma() + { + this.Settings = new Dictionary(); + } + + /// + /// Gets or sets the dynamic parameter. + /// + public dynamic DynamicParameter + { + get; + set; + } + + /// + /// Gets or sets any additional settings required by the processor. + /// + public Dictionary Settings + { + get; + set; + } + + /// + /// Processes the image. + /// + /// + /// The current instance of the class containing + /// the image to process. + /// + /// + /// The processed image from the current instance of the class. + /// + public Image ProcessImage(ImageFactory factory) + { + Bitmap newImage = null; + Image image = factory.Image; + + try + { + float value = this.DynamicParameter; + + newImage = new Bitmap(image); + newImage.SetResolution(image.HorizontalResolution, image.VerticalResolution); + newImage = Adjustments.Gamma(newImage, value); + + image.Dispose(); + image = newImage; + } + catch (Exception ex) + { + if (newImage != null) + { + newImage.Dispose(); + } + + throw new ImageProcessingException("Error processing image with " + this.GetType().Name, ex); + } + + return image; + } + } +} diff --git a/src/ImageProcessor/Processors/Resize.cs b/src/ImageProcessor/Processors/Resize.cs index ace278a20..56974bfbc 100644 --- a/src/ImageProcessor/Processors/Resize.cs +++ b/src/ImageProcessor/Processors/Resize.cs @@ -112,4 +112,4 @@ namespace ImageProcessor.Processors return image; } } -} +} \ No newline at end of file diff --git a/src/TestWebsites/MVC/Views/Home/Index.cshtml b/src/TestWebsites/MVC/Views/Home/Index.cshtml index 1784b4d36..bdc7dccba 100644 --- a/src/TestWebsites/MVC/Views/Home/Index.cshtml +++ b/src/TestWebsites/MVC/Views/Home/Index.cshtml @@ -7,213 +7,23 @@

Resized

- - + + + +
-

Cropped

- - -

Cropped Percent

- - +

Resized Remote

+
-

Reside Pad

-
- +
+

Resized Remote

+
- @*
-
-

Resize Crop

-
- -
-
- - -
-
-
-
-
-

Resize Max

-
- -
-
- -
-
-
-
-
-

Resize Max - No Upscale

-
- -
-
- -
-
-
-
-
-

Resize Stretch

-
- -
-
- -
-
-
-
-

Filter

-
-
-

blackwhite

- -
-
-

comic

- -
-
-
-
-

lomograph

- -
-
-

greyscale

- -
-
-
-
-

polaroid

- -
-
-

sepia

- -
-
-
-
-

gotham

- -
-
-

hisatch

- -
-
-
-
-

losatch

- -
-
-
-
-
-
-

Watermark

- -
-
-

Format

- -
-
-
-
-
-
-

Rotate

- -
-
-

Quality

- -
-
-
-
-
-
-

Alpha

- -
-
-

Remote

-
-
-
-
-
-
-

Flip - horizontal

- -
-
-

Flip - vertical

- -
-
-
-
-
-
-

Gaussian Blur

- -
-
-

Gaussian Sharpen

- -
-
-
-
-
-
-

Tint rgba

- -
-
-

Tint Hex

- -
-
-
*@ - -@*
-

Color Profiles

-
-
-
-

CMYK resized jpg

- -
- -
-

sRGB resized jpg

- -
-
-
-
-
-

Rounding

- - -
-
-
*@ \ No newline at end of file + \ No newline at end of file diff --git a/src/TestWebsites/MVC/Web.config b/src/TestWebsites/MVC/Web.config index dcc8cdbd3..136c9c7fa 100644 --- a/src/TestWebsites/MVC/Web.config +++ b/src/TestWebsites/MVC/Web.config @@ -6,17 +6,17 @@ - + - + diff --git a/src/TestWebsites/MVC/config/imageprocessor/security.config b/src/TestWebsites/MVC/config/imageprocessor/security.config index eb61ad133..5c0e8da08 100644 --- a/src/TestWebsites/MVC/config/imageprocessor/security.config +++ b/src/TestWebsites/MVC/config/imageprocessor/security.config @@ -4,13 +4,14 @@ - + +