From d4a8b247c73603ff62c44abdf7bf069ddd887a6f Mon Sep 17 00:00:00 2001 From: James South Date: Tue, 24 Mar 2015 22:11:59 +0000 Subject: [PATCH] Fix gamma Former-commit-id: a837a9defa7b376e9654b078899aa12359155633 Former-commit-id: 88e2563e726d1c66855b4ff38fb8db897d666893 --- src/ImageProcessor.Playground/Program.cs | 34 +-- .../Calliphora_sp_Portrait.jpg.REMOVED.git-id | 1 + .../images/input/PIA11667_modest.jpg | Bin 0 -> 12354 bytes .../images/input/blur-test.jpg | Bin 0 -> 10879 bytes .../images/input/blur-test.png | Bin 0 -> 3563 bytes .../images/input/gamma-1.0-or-2.2.png | Bin 0 -> 4195 bytes .../images/input/gamma_3x3.jpg | Bin 0 -> 29596 bytes .../images/input/gamma_colors.jpg | Bin 0 -> 15109 bytes .../gamma_dalai_lama_gray.jpg.REMOVED.git-id | 1 + .../images/input/gamma_rainbow.jpg | Bin 0 -> 47557 bytes .../HttpModules/ImageProcessingModule.cs | 2 +- src/ImageProcessor.Web/Processors/Resize.cs | 2 +- src/ImageProcessor/ImageFactory.cs | 62 +++++- src/ImageProcessor/ImageProcessor.csproj | 1 + src/ImageProcessor/Imaging/Convolution.cs | 9 + .../Imaging/Helpers/Adjustments.cs | 45 +++- .../Imaging/Quantizers/OctreeQuantizer.cs | 9 +- src/ImageProcessor/Processors/Gamma.cs | 90 ++++++++ src/ImageProcessor/Processors/Resize.cs | 2 +- src/TestWebsites/MVC/Views/Home/Index.cshtml | 210 +----------------- src/TestWebsites/MVC/Web.config | 8 +- .../MVC/config/imageprocessor/security.config | 3 +- 22 files changed, 254 insertions(+), 225 deletions(-) create mode 100644 src/ImageProcessor.Playground/images/input/Calliphora_sp_Portrait.jpg.REMOVED.git-id create mode 100644 src/ImageProcessor.Playground/images/input/PIA11667_modest.jpg create mode 100644 src/ImageProcessor.Playground/images/input/blur-test.jpg create mode 100644 src/ImageProcessor.Playground/images/input/blur-test.png create mode 100644 src/ImageProcessor.Playground/images/input/gamma-1.0-or-2.2.png create mode 100644 src/ImageProcessor.Playground/images/input/gamma_3x3.jpg create mode 100644 src/ImageProcessor.Playground/images/input/gamma_colors.jpg create mode 100644 src/ImageProcessor.Playground/images/input/gamma_dalai_lama_gray.jpg.REMOVED.git-id create mode 100644 src/ImageProcessor.Playground/images/input/gamma_rainbow.jpg create mode 100644 src/ImageProcessor/Processors/Gamma.cs 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 0000000000000000000000000000000000000000..dafede989b6082a7e44326bf1ff1974e376ce676 GIT binary patch literal 12354 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 literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..ffd08acbd322dc1571301f0296e605c38060c356 GIT binary patch literal 3563 zcmeAS@N?(olHy`uVBq!ia0y~yU{+vYV2a>i1B%QlYbpRzjKx9jP7LeL$-D$|SkfJR z9T^xl_H+M9WCij$3p^r=85mSvfG}fIGOG;Gqy|qH$B>G+w>J&fi8}JQ9!&qXKaD5e zL`aZPNWC!B$o$0}t64w){d~jTF!@>S{xk9G4_-f=zyI0u=T8|L>c9M+1vK|hITOo+ z6@Nc}XJ>F>;b35xAgI8=;NaE(l#*m*Vqi!iUC{mPK1K#bsOAHK*7*z$9+a4ea8ALM zH_{9OLQogVZ2io}&_cTV5auCyZ`9E!5kDHzsHuN6d5k6xJcZ+E@)%7XqsfEVw!&!T sGFrLdXekJ02Y1d_+Z^Uv8&z6f6ba@&SVpmP~KUHx3vIVCg!0QWp4!~g&Q literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..6d2ba91fb1c35b2f90f94a38e22886262efb2432 GIT binary patch literal 4195 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 YKJ%G><%)?9tOxMi@8j`sZ_uUx00Ck-?f?J) literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..d5524d2a80312e697b7aad298976383c83a86761 GIT binary patch literal 29596 zcmeI4eKgf~9LIk@m&+yNj$GB4QkGVED%H7cW+8dlq)v6B2v^pF>EWVQQ7S7_(QlDbhBHEL%z-SPeIkIub!r{DSQI^*6ChvS^z<8j{J-}mSB z`T9s3r1uEJh3=m21WA&_g27Kh+D4eT#YFH3!pDc0Mi7L~;Md@Xw3+yD=&b+rF?5sv zbc3ObrKJR0hm0fR7$lp}V3Q0sDZN6N;+MlOi@&pUnA(F!CK(PMVrsv7WDUnOJh$`l zSd*~qoYRknuEuZm>Nz^vOxDoVY=UHvEb^5@obb+EMHp=2 zeIi$Q-=cS{+co=p^#PV*d!wc1S2K@aJ~_$2ZgD`s__Yb2RgSGH$jz}0Puwk9!r?HF zwY_b(Cra{-wP+l=u;Oy|c@I%=z_w}oH!))pohtmIK8?s@_nNBKjr2`LC+P9WbpeHJGuUYhf zb6`ish3zu*BN{KW_56FK2!bQz%~1nyvlyGP6S~dHDG&dS~?1Gj4wOMzxItYr+(- zLn~*DfEUuW#%dCD>(4HGFT`?-`l*M~AI8nSyudhFiRoOz+NsSzQn|iCm6V}0sb*pm zt4YQtHb=F*hmv}z_%oOoZC3>oqqe$(iO~)KU}BU)CYTtQ*f5tUU}9im!&~5jiGhiM ziH%h90Z9y!*ziI+C?}zu9AfpRZvbsISJ)tF?1(KbCVoQ3``763`}fP z@ALr^qite!`aih%3|wJ`$EEK`O)BW{KDID=Uw*T(X6vsmwnmY4QAdreQcko<94p8< zzZ;IxZ0TC6}!W;kn*Xa52KK#d%f*IZi9Q2po zJQ$EHNp%?sFJ$1be!oU!w}tauB#h+}*U&ouV&}aLUs=7pPa@gn3uhhaF$g|4l~r;+ zF374it9`na&lGNX1HRIfRoFSVmX+%1`}DTuDN1R|>~%!Ji&3A1vi!*_YM8XB zgvc;MD|@c2#E6h{C~#+0p?vMig?z7|;MgZThpI*M<2cK|n5gRIAtlq2FQKQ#+Z~qs z?<0oUSyT#IIibpr-85PXJ*8O`l~UO08m<=m+7W;V|3T%;Ln@{vUqUy|XC)<<%KDgT z7lIU>cI}8sB;QhP1VK-k6UFNh8`I9g0Kz#@wU`!7(~{?Y0LN(4I)GyoxgWqW+8i0+ z7`0{vz%kkl1%P7|n-u`ZXt%lmj#2Ee0vw~=gatT8t-}g%jCMC3;26dIB>=~0?-Kzy zMs0ryz%kkzh9+j&1%_|@(=+YcgJFKY!JC)ax1@?H-~Fz8RfKMP<6?io^l=+%#35sE zN86mmbHz-?6o&TN?SH~eYjQpRVu`U>kGY~CR#36!L~YkZw1rx0_l!m-(dvuWAHF!0 z=lrGHyj_=%N>1|7gBIY~KS8zpj~q<%&Rp1@_3qGvgYv_Q-Vr7(UHS=|BXdTYZEKiqZ`Gi+=+@jv9&DO%!{qcTs`Xh%{86e(=|?Gw-7@M^lblp&Nth}ZaVVe^5pfztM9^MKm z>)-R{Z~IaHPFaQWb{ThM;QQw z0LFm4lmzSmc`52G0P@OE4zL5{rJxN3$ZNB5fE^$&1+7y+Udm~n0`gMSWC!G>q~<9g cF9jPz0C_2?cM8Z$(HMq6elCHOuDF; zc&kWYtPIa|x z{2q|c?{f6uvK{Vc5@V{hx{8_KEx0Gw*$uYr(2j4RBG1_GI_|L*7H6CFP~Nb$@XadC zGyJ=nE2`A=cuf!4C36kDbF3VmrQSeb(XnnHO>U#fZ8W(J_NMb_ zWjb1!(y^yDn%qW{+h}qd9S9j@J#i{I2Yczp9VvDF&%Q4fbrlty+h1Cowo6^+t7?7t zMsN1N_$nC*uo&lLPrnb}l%xJLOuyI8#+3WZ&*)IfrQkib9oP0h{l4&E!|b}rJsW14 zOnJ|rWV-%m?Tdm0wfjpR>!=MklTt<0jI7azk{JAUfP>-CoCCi5Ju4LfgBFH%PX zkiuLs8i1n#II!jNXbK!nfukvKNH>T^v+!sZ9?im|S$MQ7hu)VP?aC3ID@H4k(Mn{r z5+ORfP;U%{dM07d!ro?Uo-MtrzP`2a?JCO)Hi43X2a(CN;T!;jV|` zO6yf{5pZe1$^d!<0Kw95v>+l_9gG%4gev9Hf{0M7WV9e6)GQk+NSh(-${nh%j+ZxQ{!2>?1EZcP9H literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..44d996782797361af527059eedaf45999caa3fa0 GIT binary patch literal 47557 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 cl)gdf83LFpTmzW=XE-+w3mA0zB4r2qf` literal 0 HcmV?d00001 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 @@ - + +