Browse Source

backup before next release

Updates, Gaussian blur, Gaussian sharpen, Comic filter,
ImageProcessingModule


Former-commit-id: b3dee60a42cc64d844e79d60d499128e3c7cc183
af/merge-core
James South 13 years ago
parent
commit
0dfecb3284
  1. 23
      src/ImageProcessor.Web/NET45/Caching/DiskCache.cs
  2. 11
      src/ImageProcessor.Web/NET45/HttpModules/ImageProcessingModule.cs
  3. 98
      src/ImageProcessor/ImageFactory.cs
  4. 1
      src/ImageProcessor/ImageProcessor.csproj
  5. 140
      src/ImageProcessor/Imaging/Convolution.cs
  6. 58
      src/ImageProcessor/Imaging/Filters/ColorMatrixes.cs
  7. 432
      src/ImageProcessor/Imaging/Filters/ComicMatrixFilter.cs
  8. 79
      src/ImageProcessor/Imaging/ResizeLayer.cs
  9. 1
      src/ImageProcessor/Processors/Filter.cs
  10. 8
      src/ImageProcessor/Processors/GaussianBlur.cs
  11. 8
      src/ImageProcessor/Processors/GaussianSharpen.cs
  12. 24
      src/ImageProcessor/Processors/Resize.cs
  13. 2
      src/TestWebsites/NET4/Images/Thumbs.db.REMOVED.git-id
  14. 3
      src/TestWebsites/NET45/Test_Website_NET45/Images/Penguins-200.jpg
  15. 1
      src/TestWebsites/NET45/Test_Website_NET45/Images/Thumbs.db.REMOVED.git-id
  16. 3
      src/TestWebsites/NET45/Test_Website_NET45/Images/emma.jpg
  17. 0
      src/TestWebsites/NET45/Test_Website_NET45/Images/rocks.jpg.REMOVED.git-id
  18. 1
      src/TestWebsites/NET45/Test_Website_NET45/Images/thor.jpg.REMOVED.git-id
  19. 3
      src/TestWebsites/NET45/Test_Website_NET45/Images/udendørs-374.jpg
  20. 4
      src/TestWebsites/NET45/Test_Website_NET45/Test_Website_NET45.csproj
  21. 27
      src/TestWebsites/NET45/Test_Website_NET45/Views/Home/Index.cshtml
  22. 2
      src/TestWebsites/NET45/Test_Website_NET45/Web.config

23
src/ImageProcessor.Web/NET45/Caching/DiskCache.cs

@ -179,7 +179,7 @@ namespace ImageProcessor.Web.Caching
{
// Can't check the last write time so check to see if the cached image is set to expire
// or if the max age is different.
if (cachedImage.CreationTimeUtc.AddDays(MaxFileCachedDuration) < DateTime.UtcNow.AddDays(-MaxFileCachedDuration))
if (this.IsExpired(cachedImage.CreationTimeUtc))
{
CacheIndexer.Remove(path);
isUpdated = true;
@ -208,7 +208,7 @@ namespace ImageProcessor.Web.Caching
// Check to see if the last write time is different of whether the
// cached image is set to expire or if the max age is different.
if (!this.RoughDateTimeCompare(imageFileInfo.LastWriteTimeUtc, cachedImage.LastWriteTimeUtc)
|| cachedImage.CreationTimeUtc.AddDays(MaxFileCachedDuration) < DateTime.UtcNow.AddDays(-MaxFileCachedDuration))
|| this.IsExpired(cachedImage.CreationTimeUtc))
{
CacheIndexer.Remove(path);
isUpdated = true;
@ -285,7 +285,6 @@ namespace ImageProcessor.Web.Caching
DateTime creationTime = DateTime.MinValue.ToUniversalTime();
DateTime lastWriteTime = DateTime.MinValue.ToUniversalTime();
if (this.isRemote)
{
if (cachedFileInfo.Exists)
@ -330,7 +329,8 @@ namespace ImageProcessor.Web.Caching
{
// If the group count is equal to the max count minus 1 then we know we
// have reduced the number of items below the maximum allowed.
if (count <= MaxFilesCount - 1)
// We'll cleanup any orphaned expired files though.
if (!this.IsExpired(fileInfo.CreationTimeUtc) && count <= MaxFilesCount - 1)
{
break;
}
@ -404,6 +404,21 @@ namespace ImageProcessor.Web.Caching
return false;
}
/// <summary>
/// Gets a value indicating whether the given images creation date is out with
/// the prescribed limit.
/// </summary>
/// <param name="creationDate">
/// The creation date.
/// </param>
/// <returns>
/// The true if the date is out with the limit, otherwise; false.
/// </returns>
private bool IsExpired(DateTime creationDate)
{
return creationDate.AddDays(MaxFileCachedDuration) < DateTime.UtcNow.AddDays(-MaxFileCachedDuration);
}
#endregion
#endregion
}

11
src/ImageProcessor.Web/NET45/HttpModules/ImageProcessingModule.cs

@ -314,8 +314,17 @@ namespace ImageProcessor.Web.HttpModules
}
else
{
// Check to see if the file exists.
// ReSharper disable once AssignNullToNotNullAttribute
FileInfo fileInfo = new FileInfo(requestPath);
if (!fileInfo.Exists)
{
throw new HttpException(404, "No image exists at " + fullPath);
}
imageFactory.Load(fullPath).AutoProcess().Save(cachedPath);
// Ensure that the LastWriteTime property of the source and cached file match.
Tuple<DateTime, DateTime> creationAndLastWriteDateTimes = await cache.SetCachedLastWriteTimeAsync();

98
src/ImageProcessor/ImageFactory.cs

@ -364,7 +364,7 @@ namespace ImageProcessor
{
if (this.ShouldProcess)
{
ResizeLayer layer = new ResizeLayer(size, ResizeMode.Max);
ResizeLayer layer = new ResizeLayer(size, Color.Transparent, ResizeMode.Max);
return this.Resize(layer);
}
@ -487,6 +487,102 @@ namespace ImageProcessor
return this;
}
/// <summary>
/// Uses a Gaussian kernel to blur the current image.
/// <remarks>
/// <para>
/// The sigma and threshold values applied to the kernel are
/// 1.4 and 0 respectively.
/// </para>
/// </remarks>
/// </summary>
/// <param name="size">
/// The size to set the Gaussian kernel to.
/// </param>
/// <returns>
/// The current instance of the <see cref="T:ImageProcessor.ImageFactory"/> class.
/// </returns>
public ImageFactory GaussianBlur(int size)
{
if (this.ShouldProcess && size > 0)
{
GaussianLayer layer = new GaussianLayer(size);
GaussianBlur gaussianBlur = new GaussianBlur { DynamicParameter = layer };
this.Image = gaussianBlur.ProcessImage(this);
}
return this;
}
/// <summary>
/// Uses a Gaussian kernel to blur the current image.
/// </summary>
/// <param name="gaussianLayer">
/// The <see cref="T:ImageProcessor.Imaging.GaussianLayer"/> for applying sharpening and
/// blurring methods to an image.
/// </param>
/// <returns>
/// The current instance of the <see cref="T:ImageProcessor.ImageFactory"/> class.
/// </returns>
public ImageFactory GaussianBlur(GaussianLayer gaussianLayer)
{
if (this.ShouldProcess)
{
GaussianBlur gaussianBlur = new GaussianBlur { DynamicParameter = gaussianLayer };
this.Image = gaussianBlur.ProcessImage(this);
}
return this;
}
/// <summary>
/// Uses a Gaussian kernel to sharpen the current image.
/// <remarks>
/// <para>
/// The sigma and threshold values applied to the kernel are
/// 1.4 and 0 respectively.
/// </para>
/// </remarks>
/// </summary>
/// <param name="size">
/// The size to set the Gaussian kernel to.
/// </param>
/// <returns>
/// The current instance of the <see cref="T:ImageProcessor.ImageFactory"/> class.
/// </returns>
public ImageFactory GaussianSharpen(int size)
{
if (this.ShouldProcess && size > 0)
{
GaussianLayer layer = new GaussianLayer(size);
GaussianSharpen gaussianSharpen = new GaussianSharpen { DynamicParameter = layer };
this.Image = gaussianSharpen.ProcessImage(this);
}
return this;
}
/// <summary>
/// Uses a Gaussian kernel to sharpen the current image.
/// </summary>
/// <param name="gaussianLayer">
/// The <see cref="T:ImageProcessor.Imaging.GaussianLayer"/> for applying sharpening and
/// blurring methods to an image.
/// </param>
/// <returns>
/// The current instance of the <see cref="T:ImageProcessor.ImageFactory"/> class.
/// </returns>
public ImageFactory GaussianSharpen(GaussianLayer gaussianLayer)
{
if (this.ShouldProcess)
{
GaussianSharpen gaussianSharpen = new GaussianSharpen { DynamicParameter = gaussianLayer };
this.Image = gaussianSharpen.ProcessImage(this);
}
return this;
}
/// <summary>
/// Alters the output quality of the current image.
/// <remarks>

1
src/ImageProcessor/ImageProcessor.csproj

@ -59,7 +59,6 @@
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="ExtBitmap.cs" />
<Compile Include="Helpers\Extensions\ImageExtensions.cs" />
<Compile Include="Helpers\Extensions\EnumExtensions.cs" />
<Compile Include="Helpers\Extensions\StringExtensions.cs" />

140
src/ImageProcessor/Imaging/Convolution.cs

@ -253,103 +253,34 @@ namespace ImageProcessor.Imaging
}
/// <summary>
/// Convert a Bitmap to an a multidimensional array of raw pixel values
/// Processes the given kernel to produce an array of pixels representing a bitmap.
/// </summary>
/// <param name="image">The image to convert</param>
/// <returns>a multidimensional array of raw pixel values</returns>
public Pixel[,] BitmapToPixels(Bitmap image)
/// <param name="sourceBitmap">The the image to process.</param>
/// <param name="kernel">The Gaussian kernel to use when performing the method</param>
/// <returns>A processed bitmap.</returns>
public Bitmap ProcessKernel(Bitmap sourceBitmap, double[,] kernel)
{
Pixel[,] pixels = new Pixel[image.Width, image.Height];
int width = sourceBitmap.Width;
int height = sourceBitmap.Height;
BitmapData sourceData = image.LockBits(
new Rectangle(0, 0, image.Width, image.Height),
BitmapData sourceData = sourceBitmap.LockBits(
new Rectangle(0, 0, width, height),
ImageLockMode.ReadOnly,
image.PixelFormat);
byte[] pixelBuffer = new byte[sourceData.Stride * sourceData.Height];
Marshal.Copy(sourceData.Scan0, pixelBuffer, 0, pixelBuffer.Length);
image.UnlockBits(sourceData);
int pixelSize = Image.GetPixelFormatSize(image.PixelFormat) / 8;
int stride = sourceData.Stride;
for (int x = 0; x < image.Width; x++)
{
for (int y = 0; y < image.Height; y++)
{
int byteOffset = (y * stride) + (x * pixelSize);
pixels[x, y] = new Pixel
{
A = pixelBuffer[byteOffset + 3],
R = pixelBuffer[byteOffset + 2],
G = pixelBuffer[byteOffset + 1],
B = pixelBuffer[byteOffset]
};
}
}
return pixels;
}
/// <summary>
/// Convert a multidimensional array of raw pixel values to a bitmap
/// </summary>
/// <param name="pixels">The pixels to convert</param>
/// <returns>a bitmap</returns>
public Bitmap PixelsToBitmap(Pixel[,] pixels)
{
int width = pixels.GetLength(0);
int height = pixels.GetLength(1);
Bitmap resultBitmap = new Bitmap(width, height);
BitmapData resultData = resultBitmap.LockBits(
new Rectangle(0, 0, resultBitmap.Width, resultBitmap.Height),
ImageLockMode.WriteOnly,
PixelFormat.Format32bppArgb);
byte[] pixelBuffer = new byte[resultData.Stride * resultData.Height];
int stride = resultData.Stride;
int pixelSize = Image.GetPixelFormatSize(resultBitmap.PixelFormat) / 8;
for (int x = 0; x < width; x++)
{
for (int y = 0; y < height; y++)
{
int byteOffset = (y * stride) + (x * pixelSize);
int strideWidth = sourceData.Stride;
int scanHeight = sourceData.Height;
double pixelRed = pixels[x, y].R;
double pixelGreen = pixels[x, y].G;
double pixelBlue = pixels[x, y].B;
double pixelAlpha = pixels[x, y].A;
int bufferSize = strideWidth * scanHeight;
byte[] pixelBuffer = new byte[bufferSize];
byte[] resultBuffer = new byte[bufferSize];
pixelBuffer[byteOffset] = (byte)pixelBlue;
pixelBuffer[byteOffset + 1] = (byte)pixelGreen;
pixelBuffer[byteOffset + 2] = (byte)pixelRed;
pixelBuffer[byteOffset + 3] = (byte)pixelAlpha;
}
}
Marshal.Copy(pixelBuffer, 0, resultData.Scan0, pixelBuffer.Length);
resultBitmap.UnlockBits(resultData);
return resultBitmap;
}
Marshal.Copy(sourceData.Scan0, pixelBuffer, 0, pixelBuffer.Length);
sourceBitmap.UnlockBits(sourceData);
/// <summary>
/// Processes the given kernel to produce an array of pixels representing a bitmap.
/// </summary>
/// <param name="pixels">The raw pixels of the image to blur</param>
/// <param name="kernel">The Gaussian kernel to use when performing the method</param>
/// <returns>An array of pixels representing the bitmap.</returns>
public Pixel[,] ProcessKernel(Pixel[,] pixels, double[,] kernel)
{
int width = pixels.GetLength(0);
int height = pixels.GetLength(1);
int kernelLength = kernel.GetLength(0);
int radius = kernelLength >> 1;
int kernelSize = kernelLength * kernelLength;
Pixel[,] result = new Pixel[width, height];
// For each line
for (int y = 0; y < height; y++)
@ -367,6 +298,9 @@ namespace ImageProcessor.Imaging
double green;
double red = green = blue = alpha = divider = processedKernelSize = 0;
// The location of the pixel bytes.
int byteOffset = (y * strideWidth) + (x * 4);
// For each kernel row
for (int i = 0; i < kernelLength; i++)
{
@ -399,15 +333,19 @@ namespace ImageProcessor.Imaging
if (offsetX < width)
{
double k = kernel[i, j];
Pixel pixel = pixels[offsetX, offsetY];
int calcOffset = (offsetX * 4) + (offsetY * sourceData.Stride);
byte sourceBlue = pixelBuffer[calcOffset];
byte sourceGreen = pixelBuffer[calcOffset + 1];
byte sourceRed = pixelBuffer[calcOffset + 2];
byte sourceAlpha = pixelBuffer[calcOffset + 3];
double k = kernel[i, j];
divider += k;
red += k * pixel.R;
green += k * pixel.G;
blue += k * pixel.B;
alpha += k * pixel.A;
red += k * sourceRed;
green += k * sourceGreen;
blue += k * sourceBlue;
alpha += k * sourceAlpha;
processedKernelSize++;
}
@ -445,14 +383,24 @@ namespace ImageProcessor.Imaging
blue += this.Threshold;
alpha += this.Threshold;
result[x, y].R = (byte)((red > 255) ? 255 : ((red < 0) ? 0 : red));
result[x, y].G = (byte)((green > 255) ? 255 : ((green < 0) ? 0 : green));
result[x, y].B = (byte)((blue > 255) ? 255 : ((blue < 0) ? 0 : blue));
result[x, y].A = (byte)((alpha > 255) ? 255 : ((alpha < 0) ? 0 : alpha));
resultBuffer[byteOffset] = (byte)((blue > 255) ? 255 : ((blue < 0) ? 0 : blue));
resultBuffer[byteOffset + 1] = (byte)((green > 255) ? 255 : ((green < 0) ? 0 : green));
resultBuffer[byteOffset + 2] = (byte)((red > 255) ? 255 : ((red < 0) ? 0 : red));
resultBuffer[byteOffset + 3] = (byte)((alpha > 255) ? 255 : ((alpha < 0) ? 0 : alpha));
}
}
return result;
Bitmap resultBitmap = new Bitmap(width, height);
BitmapData resultData = resultBitmap.LockBits(
new Rectangle(0, 0, width, height),
ImageLockMode.WriteOnly,
PixelFormat.Format32bppArgb);
Marshal.Copy(resultBuffer, 0, resultData.Scan0, resultBuffer.Length);
resultBitmap.UnlockBits(resultData);
return resultBitmap;
}
#region Private

58
src/ImageProcessor/Imaging/Filters/ColorMatrixes.cs

@ -1,19 +1,18 @@
// -----------------------------------------------------------------------
// --------------------------------------------------------------------------------------------------------------------
// <copyright file="ColorMatrixes.cs" company="James South">
// Copyright (c) James South.
// Licensed under the Apache License, Version 2.0.
// Copyright (c) James South.
// Licensed under the Apache License, Version 2.0.
// </copyright>
// -----------------------------------------------------------------------
// <summary>
// A list of available color matrices to apply to an image.
// </summary>
// --------------------------------------------------------------------------------------------------------------------
namespace ImageProcessor.Imaging.Filters
{
#region Using
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Text;
using System.Drawing.Imaging;
using System.Drawing.Imaging;
#endregion
/// <summary>
@ -175,5 +174,46 @@ namespace ImageProcessor.Imaging.Filters
});
}
}
/// <summary>
/// Gets <see cref="T:System.Drawing.Imaging.ColorMatrix"/> for generating the high pass
/// on the comic book filter.
/// </summary>
internal static ColorMatrix ComicHigh
{
get
{
return new ColorMatrix(
new float[][]
{
new float[] { 2, -0.5f, -0.5f, 0, 0 },
new float[] { -0.5f, 2, -0.5f, 0, 0 },
new float[] { -0.5f, -0.5f, 2, 0, 0 },
new float[] { 0, 0, 0, 1, 0 },
new float[] { 0, 0, 0, 0, 1 }
});
}
}
/// <summary>
/// Gets <see cref="T:System.Drawing.Imaging.ColorMatrix"/> for generating the low pass
/// on the comic book filter.
/// </summary>
internal static ColorMatrix ComicLow
{
get
{
return new ColorMatrix(
new float[][]
{
new float[] { 1, 0, 0, 0, 0 },
new float[] { 0, 1, 0, 0, 0 },
new float[] { 0, 0, 1, 0, 0 },
new float[] { 0, 0, 0, 1, 0 },
new float[] { .075f, .075f, .075f, 0, 1 }
});
}
}
}
}

432
src/ImageProcessor/Imaging/Filters/ComicMatrixFilter.cs

@ -50,13 +50,13 @@ namespace ImageProcessor.Imaging.Filters
/// </summary>
Alpha = 3
}
/// <summary>
/// Gets the <see cref="T:System.Drawing.Imaging.ColorMatrix"/> for this filter instance.
/// </summary>
public ColorMatrix Matrix
{
get { return ColorMatrixes.LoSatch; }
get { return ColorMatrixes.ComicLow; }
}
/// <summary>
@ -74,61 +74,80 @@ namespace ImageProcessor.Imaging.Filters
public Image TransformImage(ImageFactory factory, Image image, Image newImage)
{
// Bitmaps for comic pattern
Bitmap hisatchBitmap = null;
Bitmap highBitmap = null;
Bitmap lowBitmap = null;
Bitmap patternBitmap = null;
try
{
using (Graphics graphics = Graphics.FromImage(newImage))
using (ImageAttributes attributes = new ImageAttributes())
{
using (ImageAttributes attributes = new ImageAttributes())
{
attributes.SetColorMatrix(this.Matrix);
Rectangle rectangle = new Rectangle(0, 0, image.Width, image.Height);
Rectangle rectangle = new Rectangle(0, 0, image.Width, image.Height);
attributes.SetColorMatrix(ColorMatrixes.ComicHigh);
// Set the attributes to LoSatch and draw the image.
graphics.DrawImage(image, rectangle, 0, 0, image.Width, image.Height, GraphicsUnit.Pixel, attributes);
// Draw the image with the high comic colormatrix.
highBitmap = new Bitmap(rectangle.Width, rectangle.Height, PixelFormat.Format32bppPArgb);
// Create a bitmap for overlaying.
hisatchBitmap = new Bitmap(rectangle.Width, rectangle.Height, PixelFormat.Format32bppPArgb);
// Apply a oil painting filter to the image.
highBitmap = OilPaintFilter((Bitmap)image, 3, 5);
// Set the color matrix
attributes.SetColorMatrix(ColorMatrixes.HiSatch);
using (Graphics graphics = Graphics.FromImage(highBitmap))
{
graphics.DrawImage(highBitmap, rectangle, 0, 0, image.Width, image.Height, GraphicsUnit.Pixel, attributes);
}
// Draw the image with the hisatch colormatrix.
using (var g = Graphics.FromImage(hisatchBitmap))
{
g.DrawImage(image, rectangle, 0, 0, image.Width, image.Height, GraphicsUnit.Pixel, attributes);
}
// Create a bitmap for overlaying.
lowBitmap = new Bitmap(rectangle.Width, rectangle.Height, PixelFormat.Format32bppPArgb);
// Set the color matrix
attributes.SetColorMatrix(this.Matrix);
// Draw the image with the losatch colormatrix.
using (Graphics graphics = Graphics.FromImage(lowBitmap))
{
graphics.DrawImage(highBitmap, rectangle, 0, 0, image.Width, image.Height, GraphicsUnit.Pixel, attributes);
}
// We need to create a new image now with the hi saturation colormatrix and a pattern mask to paint it
// onto the other image with.
patternBitmap = new Bitmap(rectangle.Width, rectangle.Height, PixelFormat.Format32bppPArgb);
// We need to create a new image now with a pattern mask to paint it
// onto the other image with.
patternBitmap = new Bitmap(rectangle.Width, rectangle.Height, PixelFormat.Format32bppPArgb);
// Create the pattern mask.
using (var g = Graphics.FromImage(patternBitmap))
// Create the pattern mask.
using (Graphics graphics = Graphics.FromImage(patternBitmap))
{
graphics.Clear(Color.Black);
graphics.SmoothingMode = SmoothingMode.HighQuality;
for (int y = 0; y < image.Height; y += 8)
{
g.Clear(Color.Black);
g.SmoothingMode = SmoothingMode.HighQuality;
for (var y = 0; y < image.Height; y += 10)
for (int x = 0; x < image.Width; x += 4)
{
for (var x = 0; x < image.Width; x += 6)
{
g.FillEllipse(Brushes.White, x, y, 4, 4);
g.FillEllipse(Brushes.White, x + 3, y + 5, 4, 4);
}
graphics.FillEllipse(Brushes.White, x, y, 3, 3);
graphics.FillEllipse(Brushes.White, x + 2, y + 4, 3, 3);
}
}
}
// Transfer the alpha channel from the mask to the high saturation image.
TransferOneArgbChannelFromOneBitmapToAnother(patternBitmap, hisatchBitmap, ChannelArgb.Blue, ChannelArgb.Alpha);
// Transfer the alpha channel from the mask to the high saturation image.
TransferOneArgbChannelFromOneBitmapToAnother(patternBitmap, lowBitmap, ChannelArgb.Blue, ChannelArgb.Alpha);
using (Graphics graphics = Graphics.FromImage(newImage))
{
// Overlay the image.
graphics.DrawImage(hisatchBitmap, 0, 0);
graphics.DrawImage(highBitmap, 0, 0);
graphics.DrawImage(lowBitmap, 0, 0);
// Draw an edge around the image.
using (Pen blackPen = new Pen(Color.Black))
{
blackPen.Width = 4;
graphics.DrawRectangle(blackPen, rectangle);
}
// Dispose of the other images
hisatchBitmap.Dispose();
highBitmap.Dispose();
lowBitmap.Dispose();
patternBitmap.Dispose();
}
}
@ -144,9 +163,14 @@ namespace ImageProcessor.Imaging.Filters
newImage.Dispose();
}
if (hisatchBitmap != null)
if (highBitmap != null)
{
hisatchBitmap.Dispose();
highBitmap.Dispose();
}
if (lowBitmap != null)
{
lowBitmap.Dispose();
}
if (patternBitmap != null)
@ -158,6 +182,335 @@ namespace ImageProcessor.Imaging.Filters
return image;
}
/// <summary>
/// Applies an oil paint filter.
/// TODO: Move this to another class and add to the factory
/// </summary>
/// <param name="sourceBitmap">
/// The source bitmap.
/// </param>
/// <param name="levels">
/// The levels.
/// </param>
/// <param name="filterSize">
/// The filter size.
/// </param>
/// <returns>
/// The <see cref="Bitmap"/>.
/// </returns>
private static Bitmap OilPaintFilter(Bitmap sourceBitmap, int levels, int filterSize)
{
int width = sourceBitmap.Width;
int height = sourceBitmap.Height;
BitmapData sourceData = sourceBitmap.LockBits(
new Rectangle(0, 0, width, height),
ImageLockMode.ReadOnly,
PixelFormat.Format32bppArgb);
int strideWidth = sourceData.Stride;
int scanHeight = sourceData.Height;
int bufferSize = strideWidth * scanHeight;
byte[] pixelBuffer = new byte[bufferSize];
byte[] resultBuffer = new byte[bufferSize];
Marshal.Copy(sourceData.Scan0, pixelBuffer, 0, pixelBuffer.Length);
sourceBitmap.UnlockBits(sourceData);
levels = levels - 1;
int radius = filterSize >> 1;
for (int y = 0; y < height; y++)
{
for (int x = 0; x < width; x++)
{
int maxIntensity = 0;
int maxIndex = 0;
int[] intensityBin = new int[levels + 1];
int[] blueBin = new int[levels + 1];
int[] greenBin = new int[levels + 1];
int[] redBin = new int[levels + 1];
int byteOffset = (y * strideWidth) + (x * 4);
for (int i = 0; i <= radius; i++)
{
int ir = i - radius;
int offsetY = y + ir;
// Skip the current row
if (offsetY < 0)
{
continue;
}
// Outwith the current bounds so break.
if (offsetY >= height)
{
break;
}
for (int j = 0; j <= radius; j++)
{
int jr = j - radius;
int offsetX = x + jr;
// Skip the column
if (offsetX < 0)
{
continue;
}
if (offsetX < width)
{
int calcOffset = (offsetX * 4) + (offsetY * sourceData.Stride);
byte sourceBlue = pixelBuffer[calcOffset];
byte sourceGreen = pixelBuffer[calcOffset + 1];
byte sourceRed = pixelBuffer[calcOffset + 2];
int currentIntensity = (int)Math.Round(((sourceBlue + sourceGreen + sourceRed) / 3.0 * levels) / 255.0);
intensityBin[currentIntensity] += 1;
blueBin[currentIntensity] += sourceBlue;
greenBin[currentIntensity] += sourceGreen;
redBin[currentIntensity] += sourceRed;
if (intensityBin[currentIntensity] > maxIntensity)
{
maxIntensity = intensityBin[currentIntensity];
maxIndex = currentIntensity;
}
}
}
}
double blue = Math.Abs(blueBin[maxIndex] / maxIntensity);
double green = Math.Abs(greenBin[maxIndex] / maxIntensity);
double red = Math.Abs(redBin[maxIndex] / maxIntensity);
blue = blue > 255 ? 255 : (blue < 0 ? 0 : blue);
green = green > 255 ? 255 : (green < 0 ? 0 : green);
red = red > 255 ? 255 : (red < 0 ? 0 : red);
resultBuffer[byteOffset] = (byte)blue;
resultBuffer[byteOffset + 1] = (byte)green;
resultBuffer[byteOffset + 2] = (byte)red;
resultBuffer[byteOffset + 3] = 255;
}
}
Bitmap resultBitmap = new Bitmap(width, height);
BitmapData resultData = resultBitmap.LockBits(
new Rectangle(0, 0, width, height),
ImageLockMode.WriteOnly,
PixelFormat.Format32bppArgb);
Marshal.Copy(resultBuffer, 0, resultData.Scan0, resultBuffer.Length);
resultBitmap.UnlockBits(resultData);
return resultBitmap;
}
/// <summary>
/// Detects and draws edges.
/// TODO: Move this to another class and do move edge detection.
/// </summary>
/// <param name="sourceBitmap">
/// The source bitmap.
/// </param>
/// <param name="threshold">
/// The threshold.
/// </param>
/// <returns>
/// The <see cref="Bitmap"/>.
/// </returns>
private static Bitmap DrawEdges(Bitmap sourceBitmap, byte threshold = 0)
{
Color color = Color.Black;
int width = sourceBitmap.Width;
int height = sourceBitmap.Height;
BitmapData sourceData = sourceBitmap.LockBits(
new Rectangle(0, 0, width, height),
ImageLockMode.ReadOnly,
PixelFormat.Format32bppArgb);
int strideWidth = sourceData.Stride;
int scanHeight = sourceData.Height;
int bufferSize = strideWidth * scanHeight;
byte[] pixelBuffer = new byte[bufferSize];
byte[] resultBuffer = new byte[bufferSize];
Marshal.Copy(sourceData.Scan0, pixelBuffer, 0, pixelBuffer.Length);
sourceBitmap.UnlockBits(sourceData);
for (int offsetY = 1; offsetY < height - 1; offsetY++)
{
for (int offsetX = 1; offsetX < width - 1; offsetX++)
{
int byteOffset = (offsetY * strideWidth) + (offsetX * 4);
int blueGradient = Math.Abs(pixelBuffer[byteOffset - 4] - pixelBuffer[byteOffset + 4]);
blueGradient +=
Math.Abs(
pixelBuffer[byteOffset - strideWidth] - pixelBuffer[byteOffset + strideWidth]);
byteOffset++;
int greenGradient = Math.Abs(pixelBuffer[byteOffset - 4] - pixelBuffer[byteOffset + 4]);
greenGradient +=
Math.Abs(
pixelBuffer[byteOffset - strideWidth] - pixelBuffer[byteOffset + strideWidth]);
byteOffset++;
int redGradient = Math.Abs(pixelBuffer[byteOffset - 4] - pixelBuffer[byteOffset + 4]);
redGradient +=
Math.Abs(
pixelBuffer[byteOffset - strideWidth] - pixelBuffer[byteOffset + strideWidth]);
bool exceedsThreshold;
if (blueGradient + greenGradient + redGradient > threshold)
{
exceedsThreshold = true;
}
else
{
byteOffset -= 2;
blueGradient = Math.Abs(pixelBuffer[byteOffset - 4] - pixelBuffer[byteOffset + 4]);
byteOffset++;
greenGradient = Math.Abs(pixelBuffer[byteOffset - 4] - pixelBuffer[byteOffset + 4]);
byteOffset++;
redGradient = Math.Abs(pixelBuffer[byteOffset - 4] - pixelBuffer[byteOffset + 4]);
if (blueGradient + greenGradient + redGradient > threshold)
{
exceedsThreshold = true;
}
else
{
byteOffset -= 2;
blueGradient =
Math.Abs(pixelBuffer[byteOffset - strideWidth] - pixelBuffer[byteOffset + strideWidth]);
byteOffset++;
greenGradient =
Math.Abs(pixelBuffer[byteOffset - strideWidth] - pixelBuffer[byteOffset + strideWidth]);
byteOffset++;
redGradient =
Math.Abs(pixelBuffer[byteOffset - strideWidth] - pixelBuffer[byteOffset + strideWidth]);
if (blueGradient + greenGradient + redGradient > threshold)
{
exceedsThreshold = true;
}
else
{
byteOffset -= 2;
blueGradient =
Math.Abs(
pixelBuffer[byteOffset - 4 - strideWidth]
- pixelBuffer[byteOffset + 4 + strideWidth]);
blueGradient +=
Math.Abs(
pixelBuffer[byteOffset - strideWidth + 4]
- pixelBuffer[byteOffset + strideWidth - 4]);
byteOffset++;
greenGradient =
Math.Abs(
pixelBuffer[byteOffset - 4 - strideWidth]
- pixelBuffer[byteOffset + 4 + strideWidth]);
greenGradient +=
Math.Abs(
pixelBuffer[byteOffset - strideWidth + 4]
- pixelBuffer[byteOffset + strideWidth - 4]);
byteOffset++;
redGradient =
Math.Abs(
pixelBuffer[byteOffset - 4 - strideWidth]
- pixelBuffer[byteOffset + 4 + strideWidth]);
redGradient +=
Math.Abs(
pixelBuffer[byteOffset - strideWidth + 4]
- pixelBuffer[byteOffset + strideWidth - 4]);
exceedsThreshold = blueGradient + greenGradient + redGradient > threshold;
}
}
}
byteOffset -= 2;
double blue;
double red;
double green;
double alpha;
if (exceedsThreshold)
{
blue = color.B; // 0;
green = color.G; // 0;
red = color.R; // 0;
alpha = 255;
}
else
{
// These would normally be used to transfer the correct value accross.
// blue = pixelBuffer[byteOffset];
// green = pixelBuffer[byteOffset + 1];
// red = pixelBuffer[byteOffset + 2];
blue = 255;
green = 255;
red = 255;
alpha = 0;
}
blue = blue > 255 ? 255 : (blue < 0 ? 0 : blue);
green = green > 255 ? 255 : (green < 0 ? 0 : green);
red = red > 255 ? 255 : (red < 0 ? 0 : red);
resultBuffer[byteOffset] = (byte)blue;
resultBuffer[byteOffset + 1] = (byte)green;
resultBuffer[byteOffset + 2] = (byte)red;
resultBuffer[byteOffset + 3] = (byte)alpha;
}
}
Bitmap resultBitmap = new Bitmap(width, height);
BitmapData resultData = resultBitmap.LockBits(
new Rectangle(0, 0, resultBitmap.Width, resultBitmap.Height),
ImageLockMode.WriteOnly,
PixelFormat.Format32bppArgb);
Marshal.Copy(resultBuffer, 0, resultData.Scan0, resultBuffer.Length);
resultBitmap.UnlockBits(resultData);
return resultBitmap;
}
/// <summary>
/// Transfers a single ARGB channel from one image to another.
/// </summary>
@ -211,6 +564,7 @@ namespace ImageProcessor.Imaging.Filters
for (int i = rectangle.Height * rectangle.Width; i > 0; i--)
{
// Copy the alpha values across.
destinationRgbValues[d] = sourceRgbValues[s];
d += 4;
s += 4;
@ -223,4 +577,4 @@ namespace ImageProcessor.Imaging.Filters
destination.UnlockBits(bitmapDataDestination);
}
}
}
}

79
src/ImageProcessor/Imaging/ResizeLayer.cs

@ -26,64 +26,29 @@ namespace ImageProcessor.Imaging
/// <param name="size">
/// The <see cref="T:System.Drawing.Size"/> containing the width and height to set the image to.
/// </param>
public ResizeLayer(Size size)
{
this.Size = size;
this.ResizeMode = ResizeMode.Pad;
this.AnchorPosition = AnchorPosition.Center;
this.BackgroundColor = Color.Transparent;
}
/// <summary>
/// Initializes a new instance of the <see cref="ResizeLayer"/> class.
/// </summary>
/// <param name="size">
/// The <see cref="T:System.Drawing.Size"/> containing the width and height to set the image to.
/// </param>
/// <param name="resizeMode">
/// The <see cref="ResizeMode"/> to apply to resized image.
/// </param>
public ResizeLayer(Size size, ResizeMode resizeMode)
{
this.Size = size;
this.ResizeMode = resizeMode;
this.AnchorPosition = AnchorPosition.Center;
this.BackgroundColor = Color.Transparent;
}
/// <summary>
/// Initializes a new instance of the <see cref="ResizeLayer"/> class.
/// </summary>
/// <param name="size">
/// The <see cref="T:System.Drawing.Size"/> containing the width and height to set the image to.
/// </param>
/// <param name="anchorPosition">
/// The <see cref="AnchorPosition"/> to apply to resized image.
/// </param>
public ResizeLayer(Size size, AnchorPosition anchorPosition)
{
this.Size = size;
this.AnchorPosition = anchorPosition;
this.ResizeMode = ResizeMode.Pad;
this.BackgroundColor = Color.Transparent;
}
/// <summary>
/// Initializes a new instance of the <see cref="ResizeLayer"/> class.
/// </summary>
/// <param name="backgroundColor">
/// The <see cref="T:System.Drawing.Color"/> to set as the background color.
/// <remarks>Used for image formats that do not support transparency</remarks>
/// <remarks>Used for image formats that do not support transparency (Default transparent)</remarks>
/// </param>
/// <param name="resizeMode">
/// The resize mode to apply to resized image.
/// The resize mode to apply to resized image. (Default ResizeMode.Pad)
/// </param>
/// <param name="anchorPosition">
/// The <see cref="AnchorPosition"/> to apply to resized image.
/// The <see cref="AnchorPosition"/> to apply to resized image. (Default AnchorPosition.Center)
/// </param>
/// <param name="upscale">
/// Whether to allow up-scaling of images. (Default true)
/// </param>
public ResizeLayer(Color backgroundColor, ResizeMode resizeMode = ResizeMode.Pad, AnchorPosition anchorPosition = AnchorPosition.Center)
public ResizeLayer(
Size size,
Color? backgroundColor = null,
ResizeMode resizeMode = ResizeMode.Pad,
AnchorPosition anchorPosition = AnchorPosition.Center,
bool upscale = true)
{
this.BackgroundColor = backgroundColor;
this.Size = size;
this.Upscale = upscale;
this.BackgroundColor = backgroundColor ?? Color.Transparent;
this.ResizeMode = resizeMode;
this.AnchorPosition = anchorPosition;
}
@ -109,6 +74,11 @@ namespace ImageProcessor.Imaging
/// Gets or sets the anchor position.
/// </summary>
public AnchorPosition AnchorPosition { get; set; }
/// <summary>
/// Gets or sets a value indicating whether to allow up-scaling of images.
/// </summary>
public bool Upscale { get; set; }
#endregion
/// <summary>
@ -135,7 +105,8 @@ namespace ImageProcessor.Imaging
return this.Size == resizeLayer.Size
&& this.ResizeMode == resizeLayer.ResizeMode
&& this.AnchorPosition == resizeLayer.AnchorPosition
&& this.BackgroundColor == resizeLayer.BackgroundColor;
&& this.BackgroundColor == resizeLayer.BackgroundColor
&& this.Upscale == resizeLayer.Upscale;
}
/// <summary>
@ -146,7 +117,11 @@ namespace ImageProcessor.Imaging
/// </returns>
public override int GetHashCode()
{
return this.Size.GetHashCode() + this.ResizeMode.GetHashCode() + this.AnchorPosition.GetHashCode() + this.BackgroundColor.GetHashCode();
return this.Size.GetHashCode() +
this.ResizeMode.GetHashCode() +
this.AnchorPosition.GetHashCode() +
this.BackgroundColor.GetHashCode() +
this.Upscale.GetHashCode();
}
}
}

1
src/ImageProcessor/Processors/Filter.cs

@ -120,6 +120,7 @@ namespace ImageProcessor.Processors
try
{
// Don't use an object initializer here.
// ReSharper disable once UseObjectOrCollectionInitializer
newImage = new Bitmap(image.Width, image.Height, PixelFormat.Format32bppPArgb);
newImage.Tag = image.Tag;

8
src/ImageProcessor/Processors/GaussianBlur.cs

@ -139,10 +139,8 @@ namespace ImageProcessor.Processors
GaussianLayer gaussianLayer = (GaussianLayer)this.DynamicParameter;
Convolution convolution = new Convolution(gaussianLayer.Sigma) { Threshold = gaussianLayer.Threshold };
Pixel[,] pixels = convolution.BitmapToPixels(newImage);
double[,] kernel = convolution.CreateGuassianBlurFilter(gaussianLayer.Size);
pixels = convolution.ProcessKernel(pixels, kernel);
newImage = convolution.PixelsToBitmap(pixels);
newImage = convolution.ProcessKernel(newImage, kernel);
newImage.Tag = image.Tag;
image.Dispose();
@ -194,9 +192,9 @@ namespace ImageProcessor.Processors
/// </returns>
private int ParseThreshold(string input)
{
// ReSharper disable once LoopCanBeConvertedToQuery
foreach (Match match in ThresholdRegex.Matches(input))
{
// split on text-
return Convert.ToInt32(match.Value.Split('-')[1]);
}
@ -215,9 +213,9 @@ namespace ImageProcessor.Processors
/// </returns>
private int ParseBlur(string input)
{
// ReSharper disable once LoopCanBeConvertedToQuery
foreach (Match match in BlurRegex.Matches(input))
{
// split on text-
return Convert.ToInt32(match.Value.Split('=')[1]);
}

8
src/ImageProcessor/Processors/GaussianSharpen.cs

@ -138,10 +138,8 @@ namespace ImageProcessor.Processors
GaussianLayer gaussianLayer = (GaussianLayer)this.DynamicParameter;
Convolution convolution = new Convolution(gaussianLayer.Sigma) { Threshold = gaussianLayer.Threshold };
Pixel[,] pixels = convolution.BitmapToPixels(newImage);
double[,] kernel = convolution.CreateGuassianSharpenFilter(gaussianLayer.Size);
pixels = convolution.ProcessKernel(pixels, kernel);
newImage = convolution.PixelsToBitmap(pixels);
newImage = convolution.ProcessKernel(newImage, kernel);
newImage.Tag = image.Tag;
image.Dispose();
@ -193,9 +191,9 @@ namespace ImageProcessor.Processors
/// </returns>
private int ParseThreshold(string input)
{
// ReSharper disable once LoopCanBeConvertedToQuery
foreach (Match match in ThresholdRegex.Matches(input))
{
// split on text-
return Convert.ToInt32(match.Value.Split('-')[1]);
}
@ -214,9 +212,9 @@ namespace ImageProcessor.Processors
/// </returns>
private int ParseSharpen(string input)
{
// ReSharper disable once LoopCanBeConvertedToQuery
foreach (Match match in SharpenRegex.Matches(input))
{
// split on text-
return Convert.ToInt32(match.Value.Split('=')[1]);
}

24
src/ImageProcessor/Processors/Resize.cs

@ -32,7 +32,7 @@ namespace ImageProcessor.Processors
/// <summary>
/// The regular expression to search strings for.
/// </summary>
private static readonly Regex QueryRegex = new Regex(@"((width|height)=\d+)|(mode=(pad|stretch|crop|max))|(anchor=(top|bottom|left|right|center))|(bgcolor=([0-9a-fA-F]{3}){1,2})", RegexOptions.Compiled);
private static readonly Regex QueryRegex = new Regex(@"((width|height)=\d+)|(mode=(pad|stretch|crop|max))|(anchor=(top|bottom|left|right|center))|(bgcolor=([0-9a-fA-F]{3}){1,2})|(upscale=false)", RegexOptions.Compiled);
/// <summary>
/// The regular expression to search strings for the size attribute.
@ -54,6 +54,10 @@ namespace ImageProcessor.Processors
/// </summary>
private static readonly Regex ColorRegex = new Regex(@"bgcolor=([0-9a-fA-F]{3}){1,2}", RegexOptions.Compiled);
/// <summary>
/// The regular expression to search strings for the upscale attribute.
/// </summary>
private static readonly Regex UpscaleRegex = new Regex(@"upscale=false", RegexOptions.Compiled);
#region IGraphicsProcessor Members
/// <summary>
/// Gets the regular expression to search strings for.
@ -136,7 +140,8 @@ namespace ImageProcessor.Processors
{
ResizeMode = this.ParseMode(toParse),
AnchorPosition = this.ParsePosition(toParse),
BackgroundColor = this.ParseColor(toParse)
BackgroundColor = this.ParseColor(toParse),
Upscale = !UpscaleRegex.IsMatch(toParse)
};
this.DynamicParameter = resizeLayer;
@ -160,13 +165,14 @@ namespace ImageProcessor.Processors
ResizeMode mode = this.DynamicParameter.ResizeMode;
AnchorPosition anchor = this.DynamicParameter.AnchorPosition;
Color backgroundColor = this.DynamicParameter.BackgroundColor;
bool upscale = this.DynamicParameter.Upscale;
int defaultMaxWidth;
int defaultMaxHeight;
int.TryParse(this.Settings["MaxWidth"], out defaultMaxWidth);
int.TryParse(this.Settings["MaxHeight"], out defaultMaxHeight);
return this.ResizeImage(factory, width, height, defaultMaxWidth, defaultMaxHeight, backgroundColor, mode, anchor);
return this.ResizeImage(factory, width, height, defaultMaxWidth, defaultMaxHeight, backgroundColor, mode, anchor, upscale);
}
#endregion
@ -198,6 +204,9 @@ namespace ImageProcessor.Processors
/// <param name="anchorPosition">
/// The anchor position to place the image at.
/// </param>
/// <param name="upscale">
/// Whether to allow up-scaling of images. (Default true)
/// </param>
/// <returns>
/// The processed image from the current instance of the <see cref="T:ImageProcessor.ImageFactory"/> class.
/// </returns>
@ -209,7 +218,8 @@ namespace ImageProcessor.Processors
int defaultMaxHeight,
Color backgroundColor,
ResizeMode resizeMode = ResizeMode.Pad,
AnchorPosition anchorPosition = AnchorPosition.Center)
AnchorPosition anchorPosition = AnchorPosition.Center,
bool upscale = true)
{
Bitmap newImage = null;
Image image = factory.Image;
@ -332,6 +342,12 @@ namespace ImageProcessor.Processors
if (width > 0 && height > 0 && width <= maxWidth && height <= maxHeight)
{
// Exit if upscaling is not allowed.
if ((width > sourceWidth || height > sourceHeight) && upscale == false && resizeMode != ResizeMode.Stretch)
{
return image;
}
// Don't use an object initializer here.
// ReSharper disable once UseObjectOrCollectionInitializer
newImage = new Bitmap(width, height, PixelFormat.Format32bppPArgb);

2
src/TestWebsites/NET4/Images/Thumbs.db.REMOVED.git-id

@ -1 +1 @@
32c1c68dd25fc55293b1a21c1ea25002c53f984b
1d78931ad90a644551671f9b1252e4e772f2493b

3
src/TestWebsites/NET45/Test_Website_NET45/Images/Penguins-200.jpg

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:672de68017f17260126901065f1c6ade2b2981d33dea0dea1606bf7cfb6fdcf3
size 10119

1
src/TestWebsites/NET45/Test_Website_NET45/Images/Thumbs.db.REMOVED.git-id

@ -0,0 +1 @@
5a5eaebf9a5eafe87321a87bf497baf7e2152653

3
src/TestWebsites/NET45/Test_Website_NET45/Images/emma.jpg

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:a0e660d63df4245aafc03d68de5ba6ead499cff3610745c42072b00a40cdadda
size 29617

0
src/TestWebsites/NET45/Test_Website_NET45/Images/MSwanson - Wide Large - Rock 02.jpg.REMOVED.git-id → src/TestWebsites/NET45/Test_Website_NET45/Images/rocks.jpg.REMOVED.git-id

1
src/TestWebsites/NET45/Test_Website_NET45/Images/thor.jpg.REMOVED.git-id

@ -0,0 +1 @@
4087bfc9fb25acb1bb13a15478f74e088f617934

3
src/TestWebsites/NET45/Test_Website_NET45/Images/udendørs-374.jpg

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:7a736ad3e043195ebc95fd427cf22f44e9e640bfaa4b37c188dd0ca6ad096eee
size 20944

4
src/TestWebsites/NET45/Test_Website_NET45/Test_Website_NET45.csproj

@ -138,15 +138,19 @@
<Content Include="Images\MSwanson - Wide Large - Rock 02.jpg" />
<Content Include="Images\negative.png" />
<Content Include="Images\negative2.png" />
<Content Include="Images\Penguins-200.jpg" />
<Content Include="Images\Penguins-8.png" />
<Content Include="Images\Penguins.bmp" />
<Content Include="Images\Penguins.gif" />
<Content Include="Images\Penguins.jpg" />
<Content Include="Images\Penguins.png" />
<Content Include="Images\Penguins.tif" />
<Content Include="Images\sample1.jpg" />
<Content Include="Images\srgb.jpg" />
<Content Include="Images\srgb.png" />
<Content Include="Images\text.png" />
<Content Include="Images\Tulips.jpg" />
<Content Include="Images\udendørs-374.jpg" />
<Content Include="Images\udendørs.jpg" />
<Content Include="Images\war_horse_quad.jpg" />
<Content Include="Web.config">

27
src/TestWebsites/NET45/Test_Website_NET45/Views/Home/Index.cshtml

@ -8,8 +8,6 @@
<div class="col-s-6">
<h2>Resized</h2>
<img src="/images/Penguins.jpg?width=300" />
<img src="/images/Penguins.jpg?width=300&blur=7" />
<img src="/images/Penguins.jpg?width=300&sharpen=7" />
<h3>Foreign language test.</h3>
<img src="/images/udendørs.jpg?width=300" />
<img src="/images/udendørs.jpg?preset=demo&filter=comic" />
@ -53,6 +51,17 @@
</div>
</div>
</section>
<section>
<div class="row">
<h2>Resize Max - No Upscale</h2>
<div class="col-s-4">
<img src="/images/Penguins-200.jpg?width=300&height=500&mode=max&upscale=false" />
</div>
<div class="col-s-8">
<img src="/images/udendørs-374.jpg?width=600&height=250&mode=max&upscale=false" />
</div>
</div>
</section>
<section>
<div class="row">
<h2>Resize Stretch</h2>
@ -160,9 +169,19 @@
</div>
</div>
</section>
<section>
<div class="row">
<div class="col-s-6">
<h2>Gaussian Blur</h2>
<img src="/images/Penguins.jpg?width=300&blur=7" />
</div>
<div class="col-s-6">
<h2>Gaussian Sharpen</h2>
<img src="/images/Penguins.jpg?width=300&sharpen=7" />
</div>
</div>
</section>
</article>
<article>
<h1>Color Profiles</h1>
@* <section>

2
src/TestWebsites/NET45/Test_Website_NET45/Web.config

@ -18,7 +18,7 @@
<processing configSource="config\imageprocessor\processing.config"/>
</imageProcessor>
<appSettings>
<add key="webpages:Version" value="2.0.0.0" />
<add key="webpages:Version" value="2.0.0.0" />
<add key="webpages:Enabled" value="false" />
<add key="PreserveLoginUrl" value="true" />
<add key="ClientValidationEnabled" value="true" />

Loading…
Cancel
Save