Browse Source

Merge remote-tracking branch 'origin/dev'

Former-commit-id: e30fe5a386a8da37e6ce936d6451a64d45b0f5e9
pull/17/head
James South 13 years ago
parent
commit
ffbd08901f
  1. 4
      src/ImageProcessor.Tests/ImageProcessor.Tests.csproj
  2. 57
      src/ImageProcessor.Web/NET4/ImageProcessor.Web.csproj
  3. 11
      src/ImageProcessor.Web/NET4/Settings.StyleCop
  4. 0
      src/ImageProcessor.Web/NET4/app.config
  5. 4
      src/ImageProcessor.Web/NET4/packages.config
  6. 0
      src/ImageProcessor.Web/NET45/Caching/CachedImage.cs
  7. 0
      src/ImageProcessor.Web/NET45/Caching/DiskCache.cs
  8. 0
      src/ImageProcessor.Web/NET45/Caching/PersistantDictionary.cs
  9. 0
      src/ImageProcessor.Web/NET45/Caching/SQLContext.cs
  10. 0
      src/ImageProcessor.Web/NET45/Config/ImageCacheSection.cs
  11. 0
      src/ImageProcessor.Web/NET45/Config/ImageProcessingSection.cs
  12. 0
      src/ImageProcessor.Web/NET45/Config/ImageProcessorConfig.cs
  13. 0
      src/ImageProcessor.Web/NET45/Config/ImageSecuritySection.cs
  14. 0
      src/ImageProcessor.Web/NET45/Helpers/LockedDictionary.cs
  15. 0
      src/ImageProcessor.Web/NET45/Helpers/RemoteFile.cs
  16. 0
      src/ImageProcessor.Web/NET45/Helpers/TaskHelpers.cs
  17. 0
      src/ImageProcessor.Web/NET45/HttpModules/ImageProcessingModule.cs
  18. 6
      src/ImageProcessor.Web/NET45/ImageFactoryExtensions.cs
  19. 19
      src/ImageProcessor.Web/NET45/ImageProcessor.Web_NET45.csproj
  20. 4
      src/ImageProcessor.Web/NET45/Properties/AssemblyInfo.cs
  21. 0
      src/ImageProcessor.Web/NET45/SQLite.cs.REMOVED.git-id
  22. 0
      src/ImageProcessor.Web/NET45/SQLiteAsync.cs
  23. 5
      src/ImageProcessor.Web/NET45/packages.config
  24. 95
      src/ImageProcessor.sln
  25. 85
      src/ImageProcessor/ImageFactory.cs
  26. 3
      src/ImageProcessor/ImageProcessor.csproj
  27. 836
      src/ImageProcessor/Imaging/ColorQuantizer.cs
  28. 4
      src/ImageProcessor/Imaging/Filters/GothamMatrixFilter.cs
  29. 2
      src/ImageProcessor/Imaging/Filters/LomographMatrixFilter.cs
  30. 2
      src/ImageProcessor/Imaging/Filters/PolaroidMatrixFilter.cs
  31. 61
      src/ImageProcessor/Imaging/ImageUtils.cs
  32. 543
      src/ImageProcessor/Imaging/OctreeQuantizer.cs
  33. 315
      src/ImageProcessor/Imaging/Quantizer.cs
  34. 24
      src/ImageProcessor/Processors/Format.cs
  35. 4
      src/ImageProcessor/Properties/AssemblyInfo.cs
  36. 11
      src/ImageProcessor/Settings.StyleCop
  37. BIN
      src/Nuget/ImageProcessor.1.3.0.0.nupkg
  38. BIN
      src/Nuget/ImageProcessor.1.4.0.0.nupkg
  39. BIN
      src/Nuget/ImageProcessor.1.4.1.0.nupkg
  40. BIN
      src/Nuget/ImageProcessor.1.4.2.0.nupkg
  41. BIN
      src/Nuget/ImageProcessor.1.5.0.0.nupkg
  42. BIN
      src/Nuget/ImageProcessor.1.6.0.0.nupkg
  43. BIN
      src/Nuget/ImageProcessor.1.7.0.0.nupkg
  44. BIN
      src/Nuget/ImageProcessor.Web.1.3.0.0.nupkg
  45. BIN
      src/Nuget/ImageProcessor.Web.2.0.0.0.nupkg
  46. BIN
      src/Nuget/ImageProcessor.Web.2.0.1.0.nupkg
  47. BIN
      src/Nuget/ImageProcessor.Web.2.1.0.0.nupkg
  48. BIN
      src/Nuget/ImageProcessor.Web.2.1.0.1.nupkg
  49. BIN
      src/Nuget/ImageProcessor.Web.2.1.0.2.nupkg
  50. BIN
      src/Nuget/ImageProcessor.Web.2.1.0.3.nupkg
  51. 1
      src/Nuget/ImageProcessor.Web.2.1.0.4.nupkg.REMOVED.git-id
  52. 1
      src/Nuget/ImageProcessor.Web.2.1.1.0.nupkg.REMOVED.git-id
  53. 1
      src/Nuget/ImageProcessor.Web.2.1.2.0.nupkg.REMOVED.git-id
  54. 1
      src/Nuget/ImageProcessor.Web.2.2.0.0.nupkg.REMOVED.git-id
  55. 1
      src/Nuget/ImageProcessor.Web.2.2.0.1.nupkg.REMOVED.git-id
  56. 43
      src/Nuget/ImageProcessor.Web.2.2.0.1.nuspec
  57. 1
      src/Nuget/ImageProcessor.Web.2.2.1.0.nupkg.REMOVED.git-id
  58. 1
      src/Nuget/ImageProcessor.Web.2.2.2.0.nupkg.REMOVED.git-id
  59. 1
      src/Nuget/ImageProcessor.Web.2.2.3.0.nupkg.REMOVED.git-id
  60. 1
      src/Nuget/ImageProcessor.Web.2.2.3.1.nupkg.REMOVED.git-id
  61. 1
      src/Nuget/ImageProcessor.Web.2.2.3.2.nupkg.REMOVED.git-id
  62. 1
      src/Nuget/ImageProcessor.Web.2.3.0.0.nupkg.REMOVED.git-id
  63. BIN
      src/Nuget/imageprocessor.128.png
  64. 37
      src/Packages.dgml
  65. 212
      src/TestWebsites/NET4/Content/flexo.css
  66. 3
      src/TestWebsites/NET4/Content/responsive-legacy.min.css
  67. 3
      src/TestWebsites/NET4/Content/responsive.min.css
  68. 64
      src/TestWebsites/NET4/Content/style.css
  69. 147
      src/TestWebsites/NET4/Controllers/HomeController.cs
  70. BIN
      src/TestWebsites/NET4/Resized/240px_228406_276791782435436_815038966_n.jpg
  71. BIN
      src/TestWebsites/NET4/Resized/240px_MSwanson - Wide Large - Rock 02.jpg
  72. BIN
      src/TestWebsites/NET4/Resized/240px_Neck2-1.jpg
  73. BIN
      src/TestWebsites/NET4/Resized/320px_228406_276791782435436_815038966_n.jpg
  74. BIN
      src/TestWebsites/NET4/Resized/320px_MSwanson - Wide Large - Rock 02.jpg
  75. BIN
      src/TestWebsites/NET4/Resized/320px_Neck2-1.jpg
  76. BIN
      src/TestWebsites/NET4/Resized/460px_228406_276791782435436_815038966_n.jpg
  77. BIN
      src/TestWebsites/NET4/Resized/460px_MSwanson - Wide Large - Rock 02.jpg
  78. BIN
      src/TestWebsites/NET4/Resized/460px_Neck2-1.jpg
  79. 17
      src/TestWebsites/NET4/Test_Website.csproj
  80. 14
      src/TestWebsites/NET4/Views/Home/About.cshtml
  81. 20
      src/TestWebsites/NET4/Views/Home/Collisions.cshtml
  82. 457
      src/TestWebsites/NET4/Views/Home/Index.cshtml
  83. 18
      src/TestWebsites/NET4/Views/Home/Responsive.cshtml
  84. 5
      src/TestWebsites/NET4/Views/Home/Upload.cshtml
  85. 9
      src/TestWebsites/NET4/Views/Shared/Error.cshtml
  86. 25
      src/TestWebsites/NET4/Views/Shared/_Layout.cshtml
  87. 8
      src/TestWebsites/NET4/Web.config
  88. BIN
      src/TestWebsites/NET4/cache/0/0/0af9c9c3ac0bd099667ef1890991ecf0.jpg
  89. BIN
      src/TestWebsites/NET4/cache/0/2/0b5ec0dd58da4a94241a4a0c84fbcf92.jpg
  90. 1
      src/TestWebsites/NET4/cache/0/3/0ed1b21b56f58f1cc566014f5f5cf5e3.bmp.REMOVED.git-id
  91. 1
      src/TestWebsites/NET4/cache/0/4/0b64a147662ae5f841029e61c5e88984.png.REMOVED.git-id
  92. 1
      src/TestWebsites/NET4/cache/0/7/09f4cdcadedc15e2bb3fb3647d6e4a87.bmp.REMOVED.git-id
  93. 1
      src/TestWebsites/NET4/cache/0/c/016bbd2c44ab6af915e4dc26a715d5ec.bmp.REMOVED.git-id
  94. 1
      src/TestWebsites/NET4/cache/0/e/0b24c3d312abd3bfcc04452e8eaca81e.bmp.REMOVED.git-id
  95. 1
      src/TestWebsites/NET4/cache/0/f/07d78f73ba8fe89fe3197254c394da4f.bmp.REMOVED.git-id
  96. 1
      src/TestWebsites/NET4/cache/1/3/1de0e9e101bdd9bc8122039f22bcc073.bmp.REMOVED.git-id
  97. BIN
      src/TestWebsites/NET4/cache/2/8/28d7c32164bdb0423a972759b7cf68a8.png
  98. BIN
      src/TestWebsites/NET4/cache/2/d/218fc888534353242520d7c4975e43fd.gif
  99. BIN
      src/TestWebsites/NET4/cache/3/4/3470eab4ef380d70769da7c043814fe4.jpg
  100. BIN
      src/TestWebsites/NET4/cache/3/5/3bc1aeca44cbb62786c612395a5de385.jpg

4
src/ImageProcessor.Tests/ImageProcessor.Tests.csproj

@ -74,10 +74,6 @@
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\ImageProcessor.Web\ImageProcessor.Web.csproj">
<Project>{4f7050f2-465f-4e10-8db2-2fb97ac6aa43}</Project>
<Name>ImageProcessor.Web</Name>
</ProjectReference>
<ProjectReference Include="..\ImageProcessor\ImageProcessor.csproj">
<Project>{3b5dd734-fb7a-487d-8ce6-55e7af9aea7e}</Project>
<Name>ImageProcessor</Name>

57
src/ImageProcessor.Web/ImageProcessor.Web.csproj → src/ImageProcessor.Web/NET4/ImageProcessor.Web.csproj

@ -40,57 +40,60 @@
</PropertyGroup>
<ItemGroup>
<Reference Include="Community.CsharpSqlite">
<HintPath>..\packages\Csharp-Sqlite.3.7.7.1\lib\net40\Community.CsharpSqlite.dll</HintPath>
<HintPath>..\..\packages\Csharp-Sqlite.3.7.7.1\lib\net40\Community.CsharpSqlite.dll</HintPath>
</Reference>
<Reference Include="Community.CsharpSqlite.SQLiteClient">
<HintPath>..\packages\Csharp-Sqlite.3.7.7.1\lib\net40\Community.CsharpSqlite.SQLiteClient.dll</HintPath>
<HintPath>..\..\packages\Csharp-Sqlite.3.7.7.1\lib\net40\Community.CsharpSqlite.SQLiteClient.dll</HintPath>
</Reference>
<Reference Include="Microsoft.Threading.Tasks, Version=1.0.12.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\packages\Microsoft.Bcl.Async.1.0.16\lib\net40\Microsoft.Threading.Tasks.dll</HintPath>
<HintPath>..\..\packages\Microsoft.Bcl.Async.1.0.16\lib\net40\Microsoft.Threading.Tasks.dll</HintPath>
</Reference>
<Reference Include="Microsoft.Threading.Tasks.Extensions, Version=1.0.12.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\packages\Microsoft.Bcl.Async.1.0.16\lib\net40\Microsoft.Threading.Tasks.Extensions.dll</HintPath>
<HintPath>..\..\packages\Microsoft.Bcl.Async.1.0.16\lib\net40\Microsoft.Threading.Tasks.Extensions.dll</HintPath>
</Reference>
<Reference Include="Microsoft.Threading.Tasks.Extensions.Desktop, Version=1.0.16.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\packages\Microsoft.Bcl.Async.1.0.16\lib\net40\Microsoft.Threading.Tasks.Extensions.Desktop.dll</HintPath>
<HintPath>..\..\packages\Microsoft.Bcl.Async.1.0.16\lib\net40\Microsoft.Threading.Tasks.Extensions.Desktop.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Configuration" />
<Reference Include="System.Core" />
<Reference Include="System.Drawing" />
<Reference Include="System.IO">
<HintPath>..\..\packages\Microsoft.Bcl.1.1.3\lib\net40\System.IO.dll</HintPath>
</Reference>
<Reference Include="System.Net" />
<Reference Include="System.Runtime">
<HintPath>..\packages\Microsoft.Bcl.1.0.19\lib\net40\System.Runtime.dll</HintPath>
<HintPath>..\..\packages\Microsoft.Bcl.1.1.3\lib\net40\System.Runtime.dll</HintPath>
</Reference>
<Reference Include="System.Threading.Tasks">
<HintPath>..\packages\Microsoft.Bcl.1.0.19\lib\net40\System.Threading.Tasks.dll</HintPath>
<HintPath>..\..\packages\Microsoft.Bcl.1.1.3\lib\net40\System.Threading.Tasks.dll</HintPath>
</Reference>
<Reference Include="System.Web" />
<Reference Include="System.Data" />
</ItemGroup>
<ItemGroup>
<Compile Include="Caching\CachedImage.cs" />
<Compile Include="Caching\DiskCache.cs" />
<Compile Include="Helpers\TaskHelpers.cs" />
<Compile Include="Helpers\LockedDictionary.cs" />
<Compile Include="Caching\PersistantDictionary.cs" />
<Compile Include="Caching\SQLContext.cs" />
<Compile Include="Config\ImageCacheSection.cs" />
<Compile Include="Config\ImageProcessingSection.cs" />
<Compile Include="Config\ImageProcessorConfig.cs" />
<Compile Include="Config\ImageSecuritySection.cs" />
<Compile Include="Helpers\RemoteFile.cs" />
<Compile Include="HttpModules\ImageProcessingModule.cs" />
<Compile Include="ImageFactoryExtensions.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="SQLite.cs" />
<Compile Include="SQLiteAsync.cs" />
<Compile Include="..\NET45\Caching\CachedImage.cs" />
<Compile Include="..\NET45\Caching\DiskCache.cs" />
<Compile Include="..\NET45\Caching\PersistantDictionary.cs" />
<Compile Include="..\NET45\Caching\SQLContext.cs" />
<Compile Include="..\NET45\Config\ImageCacheSection.cs" />
<Compile Include="..\NET45\Config\ImageProcessingSection.cs" />
<Compile Include="..\NET45\Config\ImageProcessorConfig.cs" />
<Compile Include="..\NET45\Config\ImageSecuritySection.cs" />
<Compile Include="..\NET45\Helpers\LockedDictionary.cs" />
<Compile Include="..\NET45\Helpers\RemoteFile.cs" />
<Compile Include="..\NET45\Helpers\TaskHelpers.cs" />
<Compile Include="..\NET45\HttpModules\ImageProcessingModule.cs" />
<Compile Include="..\NET45\ImageFactoryExtensions.cs" />
<Compile Include="..\NET45\Properties\AssemblyInfo.cs" />
<Compile Include="..\NET45\SQLite.cs" />
<Compile Include="..\NET45\SQLiteAsync.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\ImageProcessor\ImageProcessor.csproj">
<ProjectReference Include="..\..\ImageProcessor\ImageProcessor.csproj">
<Project>{3B5DD734-FB7A-487D-8CE6-55E7AF9AEA7E}</Project>
<Name>ImageProcessor</Name>
</ProjectReference>
@ -99,14 +102,16 @@
<None Include="app.config">
<SubType>Designer</SubType>
</None>
<None Include="packages.config" />
<None Include="packages.config">
<SubType>Designer</SubType>
</None>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<PropertyGroup>
<PostBuildEvent>xcopy /y "$(TargetPath)" "$(SolutionDir)\TestWebsites\NET4\bin"
xcopy /y "$(TargetDir)$(TargetName).pdb" "$(SolutionDir)\TestWebsites\NET4\bin"</PostBuildEvent>
</PropertyGroup>
<Import Project="..\packages\Microsoft.Bcl.Build.1.0.6\tools\Microsoft.Bcl.Build.targets" />
<Import Project="..\..\packages\Microsoft.Bcl.Build.1.0.8\tools\Microsoft.Bcl.Build.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">

11
src/ImageProcessor.Web/NET4/Settings.StyleCop

@ -0,0 +1,11 @@
<StyleCopSettings Version="105">
<Analyzers>
<Analyzer AnalyzerId="StyleCop.CSharp.DocumentationRules">
<AnalyzerSettings>
<StringProperty Name="CompanyName">James South</StringProperty>
<StringProperty Name="Copyright">Copyright (c) James South.
Licensed under the Apache License, Version 2.0.</StringProperty>
</AnalyzerSettings>
</Analyzer>
</Analyzers>
</StyleCopSettings>

0
src/ImageProcessor.Web/app.config → src/ImageProcessor.Web/NET4/app.config

4
src/ImageProcessor.Web/packages.config → src/ImageProcessor.Web/NET4/packages.config

@ -1,8 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Csharp-Sqlite" version="3.7.7.1" targetFramework="net40" />
<package id="Microsoft.Bcl" version="1.0.19" targetFramework="net40" />
<package id="Microsoft.Bcl" version="1.1.3" targetFramework="net40" />
<package id="Microsoft.Bcl.Async" version="1.0.16" targetFramework="net40" />
<package id="Microsoft.Bcl.Build" version="1.0.6" targetFramework="net40" />
<package id="Microsoft.Bcl.Build" version="1.0.8" targetFramework="net40" />
<package id="sqlite-net" version="1.0.7" targetFramework="net40" />
</packages>

0
src/ImageProcessor.Web/Caching/CachedImage.cs → src/ImageProcessor.Web/NET45/Caching/CachedImage.cs

0
src/ImageProcessor.Web/Caching/DiskCache.cs → src/ImageProcessor.Web/NET45/Caching/DiskCache.cs

0
src/ImageProcessor.Web/Caching/PersistantDictionary.cs → src/ImageProcessor.Web/NET45/Caching/PersistantDictionary.cs

0
src/ImageProcessor.Web/Caching/SQLContext.cs → src/ImageProcessor.Web/NET45/Caching/SQLContext.cs

0
src/ImageProcessor.Web/Config/ImageCacheSection.cs → src/ImageProcessor.Web/NET45/Config/ImageCacheSection.cs

0
src/ImageProcessor.Web/Config/ImageProcessingSection.cs → src/ImageProcessor.Web/NET45/Config/ImageProcessingSection.cs

0
src/ImageProcessor.Web/Config/ImageProcessorConfig.cs → src/ImageProcessor.Web/NET45/Config/ImageProcessorConfig.cs

0
src/ImageProcessor.Web/Config/ImageSecuritySection.cs → src/ImageProcessor.Web/NET45/Config/ImageSecuritySection.cs

0
src/ImageProcessor.Web/Helpers/LockedDictionary.cs → src/ImageProcessor.Web/NET45/Helpers/LockedDictionary.cs

0
src/ImageProcessor.Web/Helpers/RemoteFile.cs → src/ImageProcessor.Web/NET45/Helpers/RemoteFile.cs

0
src/ImageProcessor.Web/Helpers/TaskHelpers.cs → src/ImageProcessor.Web/NET45/Helpers/TaskHelpers.cs

0
src/ImageProcessor.Web/HttpModules/ImageProcessingModule.cs → src/ImageProcessor.Web/NET45/HttpModules/ImageProcessingModule.cs

6
src/ImageProcessor.Web/ImageFactoryExtensions.cs → src/ImageProcessor.Web/NET45/ImageFactoryExtensions.cs

@ -9,6 +9,7 @@ namespace ImageProcessor.Web
{
#region Using
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using ImageProcessor.Processors;
using ImageProcessor.Web.Config;
@ -41,7 +42,7 @@ namespace ImageProcessor.Web
// It's faster to lock and run through our activated list than to create new instances.
lock (SyncRoot)
{
// Get a list of all graphics processors that have parsed and matched the querystring.
// Get a list of all graphics processors that have parsed and matched the query string.
List<IGraphicsProcessor> graphicsProcessors =
ImageProcessorConfig.Instance.GraphicsProcessors
.Where(x => x.MatchRegexIndex(factory.QueryString) != int.MaxValue)
@ -51,7 +52,8 @@ namespace ImageProcessor.Web
// Loop through and process the image.
foreach (IGraphicsProcessor graphicsProcessor in graphicsProcessors)
{
factory.Image = graphicsProcessor.ProcessImage(factory);
Image img = graphicsProcessor.ProcessImage(factory);
factory.Update(img);
}
}
}

19
src/ImageProcessor.Web/ImageProcessor.Web_NET45.csproj → src/ImageProcessor.Web/NET45/ImageProcessor.Web_NET45.csproj

@ -16,7 +16,7 @@
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\NET45\</OutputPath>
<OutputPath>bin\Debug</OutputPath>
<DefineConstants>TRACE;DEBUG;USE_CSHARP_SQLITE, NET45</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
@ -24,19 +24,17 @@
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\NET45\</OutputPath>
<OutputPath>bin\Release</OutputPath>
<DefineConstants>TRACE;USE_CSHARP_SQLITE, NET45</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="Community.CsharpSqlite, Version=3.7.7.1, Culture=neutral, PublicKeyToken=fef4dbb895105d0c, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>bin\Release\Community.CsharpSqlite.dll</HintPath>
<Reference Include="Community.CsharpSqlite">
<HintPath>..\..\packages\Csharp-Sqlite.3.7.7.1\lib\net40\Community.CsharpSqlite.dll</HintPath>
</Reference>
<Reference Include="Community.CsharpSqlite.SQLiteClient, Version=3.7.7.1, Culture=neutral, PublicKeyToken=fef4dbb895105d0c, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>bin\Release\Community.CsharpSqlite.SQLiteClient.dll</HintPath>
<Reference Include="Community.CsharpSqlite.SQLiteClient">
<HintPath>..\..\packages\Csharp-Sqlite.3.7.7.1\lib\net40\Community.CsharpSqlite.SQLiteClient.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Configuration" />
@ -68,11 +66,14 @@
<Compile Include="SQLiteAsync.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\ImageProcessor\ImageProcessor.csproj">
<ProjectReference Include="..\..\ImageProcessor\ImageProcessor.csproj">
<Project>{3b5dd734-fb7a-487d-8ce6-55e7af9aea7e}</Project>
<Name>ImageProcessor</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.

4
src/ImageProcessor.Web/Properties/AssemblyInfo.cs → src/ImageProcessor.Web/NET45/Properties/AssemblyInfo.cs

@ -31,5 +31,5 @@ using System.Runtime.InteropServices;
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
[assembly: AssemblyVersion("2.2.3.3")]
[assembly: AssemblyFileVersion("2.2.3.3")]
[assembly: AssemblyVersion("2.3.0.0")]
[assembly: AssemblyFileVersion("2.3.0.0")]

0
src/ImageProcessor.Web/SQLite.cs.REMOVED.git-id → src/ImageProcessor.Web/NET45/SQLite.cs.REMOVED.git-id

0
src/ImageProcessor.Web/SQLiteAsync.cs → src/ImageProcessor.Web/NET45/SQLiteAsync.cs

5
src/ImageProcessor.Web/NET45/packages.config

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<packages >
<package id="Csharp-Sqlite" version="3.7.7.1" targetFramework="net40" />
<package id="sqlite-net" version="1.0.7" targetFramework="net40" />
</packages>

95
src/ImageProcessor.sln

@ -3,8 +3,6 @@ Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 2012
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ImageProcessor", "ImageProcessor\ImageProcessor.csproj", "{3B5DD734-FB7A-487D-8CE6-55E7AF9AEA7E}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ImageProcessor.Web", "ImageProcessor.Web\ImageProcessor.Web.csproj", "{4F7050F2-465F-4E10-8DB2-2FB97AC6AA43}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ImageProcessor.Tests", "ImageProcessor.Tests\ImageProcessor.Tests.csproj", "{39911A38-CA06-413C-80AA-39EF60CE984F}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Web.Tests", "Web.Test\Web.Tests.csproj", "{23CE0FC0-9E59-4C93-A604-A4A98A6284D1}"
@ -15,11 +13,13 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
Local.testsettings = Local.testsettings
EndProjectSection
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ImageProcessor.Web_NET45", "ImageProcessor.Web\ImageProcessor.Web_NET45.csproj", "{D011A778-59C8-4BFA-A770-C350216BF161}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Test_Website", "TestWebsites\NET4\Test_Website.csproj", "{30327C08-7574-4D7E-AC95-6A58753C6855}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Test_Website_NET45", "TestWebsites\NET45\Test_Website_NET45.csproj", "{F6A208E9-C18F-43E9-B051-3C6EED30FDAF}"
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Test_Website_NET45", "TestWebsites\NET45\Test_Website_NET45\Test_Website_NET45.csproj", "{F6A208E9-C18F-43E9-B051-3C6EED30FDAF}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ImageProcessor.Web", "ImageProcessor.Web\NET4\ImageProcessor.Web.csproj", "{4F7050F2-465F-4E10-8DB2-2FB97AC6AA43}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ImageProcessor.Web_NET45", "ImageProcessor.Web\NET45\ImageProcessor.Web_NET45.csproj", "{D011A778-59C8-4BFA-A770-C350216BF161}"
EndProject
Global
GlobalSection(TestCaseManagementSettings) = postSolution
@ -52,21 +52,6 @@ Global
{3B5DD734-FB7A-487D-8CE6-55E7AF9AEA7E}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{3B5DD734-FB7A-487D-8CE6-55E7AF9AEA7E}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{3B5DD734-FB7A-487D-8CE6-55E7AF9AEA7E}.Release|x86.ActiveCfg = Release|Any CPU
{4F7050F2-465F-4E10-8DB2-2FB97AC6AA43}.All|Any CPU.ActiveCfg = All|Any CPU
{4F7050F2-465F-4E10-8DB2-2FB97AC6AA43}.All|Any CPU.Build.0 = All|Any CPU
{4F7050F2-465F-4E10-8DB2-2FB97AC6AA43}.All|Mixed Platforms.ActiveCfg = All|Any CPU
{4F7050F2-465F-4E10-8DB2-2FB97AC6AA43}.All|Mixed Platforms.Build.0 = All|Any CPU
{4F7050F2-465F-4E10-8DB2-2FB97AC6AA43}.All|x86.ActiveCfg = All|Any CPU
{4F7050F2-465F-4E10-8DB2-2FB97AC6AA43}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{4F7050F2-465F-4E10-8DB2-2FB97AC6AA43}.Debug|Any CPU.Build.0 = Debug|Any CPU
{4F7050F2-465F-4E10-8DB2-2FB97AC6AA43}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
{4F7050F2-465F-4E10-8DB2-2FB97AC6AA43}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
{4F7050F2-465F-4E10-8DB2-2FB97AC6AA43}.Debug|x86.ActiveCfg = Debug|Any CPU
{4F7050F2-465F-4E10-8DB2-2FB97AC6AA43}.Release|Any CPU.ActiveCfg = Release|Any CPU
{4F7050F2-465F-4E10-8DB2-2FB97AC6AA43}.Release|Any CPU.Build.0 = Release|Any CPU
{4F7050F2-465F-4E10-8DB2-2FB97AC6AA43}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{4F7050F2-465F-4E10-8DB2-2FB97AC6AA43}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{4F7050F2-465F-4E10-8DB2-2FB97AC6AA43}.Release|x86.ActiveCfg = Release|Any CPU
{39911A38-CA06-413C-80AA-39EF60CE984F}.All|Any CPU.ActiveCfg = Release|Any CPU
{39911A38-CA06-413C-80AA-39EF60CE984F}.All|Any CPU.Build.0 = Release|Any CPU
{39911A38-CA06-413C-80AA-39EF60CE984F}.All|Mixed Platforms.ActiveCfg = Release|x86
@ -100,21 +85,6 @@ Global
{23CE0FC0-9E59-4C93-A604-A4A98A6284D1}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{23CE0FC0-9E59-4C93-A604-A4A98A6284D1}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{23CE0FC0-9E59-4C93-A604-A4A98A6284D1}.Release|x86.ActiveCfg = Release|Any CPU
{D011A778-59C8-4BFA-A770-C350216BF161}.All|Any CPU.ActiveCfg = Release|Any CPU
{D011A778-59C8-4BFA-A770-C350216BF161}.All|Any CPU.Build.0 = Release|Any CPU
{D011A778-59C8-4BFA-A770-C350216BF161}.All|Mixed Platforms.ActiveCfg = Release|Any CPU
{D011A778-59C8-4BFA-A770-C350216BF161}.All|Mixed Platforms.Build.0 = Release|Any CPU
{D011A778-59C8-4BFA-A770-C350216BF161}.All|x86.ActiveCfg = Release|Any CPU
{D011A778-59C8-4BFA-A770-C350216BF161}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{D011A778-59C8-4BFA-A770-C350216BF161}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D011A778-59C8-4BFA-A770-C350216BF161}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
{D011A778-59C8-4BFA-A770-C350216BF161}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
{D011A778-59C8-4BFA-A770-C350216BF161}.Debug|x86.ActiveCfg = Debug|Any CPU
{D011A778-59C8-4BFA-A770-C350216BF161}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D011A778-59C8-4BFA-A770-C350216BF161}.Release|Any CPU.Build.0 = Release|Any CPU
{D011A778-59C8-4BFA-A770-C350216BF161}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{D011A778-59C8-4BFA-A770-C350216BF161}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{D011A778-59C8-4BFA-A770-C350216BF161}.Release|x86.ActiveCfg = Release|Any CPU
{30327C08-7574-4D7E-AC95-6A58753C6855}.All|Any CPU.ActiveCfg = All|Any CPU
{30327C08-7574-4D7E-AC95-6A58753C6855}.All|Any CPU.Build.0 = All|Any CPU
{30327C08-7574-4D7E-AC95-6A58753C6855}.All|Mixed Platforms.ActiveCfg = All|x86
@ -133,24 +103,51 @@ Global
{30327C08-7574-4D7E-AC95-6A58753C6855}.Release|Mixed Platforms.Build.0 = Release|x86
{30327C08-7574-4D7E-AC95-6A58753C6855}.Release|x86.ActiveCfg = Release|x86
{30327C08-7574-4D7E-AC95-6A58753C6855}.Release|x86.Build.0 = Release|x86
{F6A208E9-C18F-43E9-B051-3C6EED30FDAF}.All|Any CPU.ActiveCfg = All|Any CPU
{F6A208E9-C18F-43E9-B051-3C6EED30FDAF}.All|Any CPU.Build.0 = All|Any CPU
{F6A208E9-C18F-43E9-B051-3C6EED30FDAF}.All|Mixed Platforms.ActiveCfg = All|x86
{F6A208E9-C18F-43E9-B051-3C6EED30FDAF}.All|Mixed Platforms.Build.0 = All|x86
{F6A208E9-C18F-43E9-B051-3C6EED30FDAF}.All|x86.ActiveCfg = All|x86
{F6A208E9-C18F-43E9-B051-3C6EED30FDAF}.All|x86.Build.0 = All|x86
{F6A208E9-C18F-43E9-B051-3C6EED30FDAF}.All|Any CPU.ActiveCfg = Release|Any CPU
{F6A208E9-C18F-43E9-B051-3C6EED30FDAF}.All|Any CPU.Build.0 = Release|Any CPU
{F6A208E9-C18F-43E9-B051-3C6EED30FDAF}.All|Mixed Platforms.ActiveCfg = Release|Any CPU
{F6A208E9-C18F-43E9-B051-3C6EED30FDAF}.All|Mixed Platforms.Build.0 = Release|Any CPU
{F6A208E9-C18F-43E9-B051-3C6EED30FDAF}.All|x86.ActiveCfg = Release|Any CPU
{F6A208E9-C18F-43E9-B051-3C6EED30FDAF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{F6A208E9-C18F-43E9-B051-3C6EED30FDAF}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F6A208E9-C18F-43E9-B051-3C6EED30FDAF}.Debug|Mixed Platforms.ActiveCfg = Debug|x86
{F6A208E9-C18F-43E9-B051-3C6EED30FDAF}.Debug|Mixed Platforms.Build.0 = Debug|x86
{F6A208E9-C18F-43E9-B051-3C6EED30FDAF}.Debug|x86.ActiveCfg = Debug|x86
{F6A208E9-C18F-43E9-B051-3C6EED30FDAF}.Debug|x86.Build.0 = Debug|x86
{F6A208E9-C18F-43E9-B051-3C6EED30FDAF}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
{F6A208E9-C18F-43E9-B051-3C6EED30FDAF}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
{F6A208E9-C18F-43E9-B051-3C6EED30FDAF}.Debug|x86.ActiveCfg = Debug|Any CPU
{F6A208E9-C18F-43E9-B051-3C6EED30FDAF}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F6A208E9-C18F-43E9-B051-3C6EED30FDAF}.Release|Any CPU.Build.0 = Release|Any CPU
{F6A208E9-C18F-43E9-B051-3C6EED30FDAF}.Release|Mixed Platforms.ActiveCfg = Release|x86
{F6A208E9-C18F-43E9-B051-3C6EED30FDAF}.Release|Mixed Platforms.Build.0 = Release|x86
{F6A208E9-C18F-43E9-B051-3C6EED30FDAF}.Release|x86.ActiveCfg = Release|x86
{F6A208E9-C18F-43E9-B051-3C6EED30FDAF}.Release|x86.Build.0 = Release|x86
{F6A208E9-C18F-43E9-B051-3C6EED30FDAF}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{F6A208E9-C18F-43E9-B051-3C6EED30FDAF}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{F6A208E9-C18F-43E9-B051-3C6EED30FDAF}.Release|x86.ActiveCfg = Release|Any CPU
{4F7050F2-465F-4E10-8DB2-2FB97AC6AA43}.All|Any CPU.ActiveCfg = All|Any CPU
{4F7050F2-465F-4E10-8DB2-2FB97AC6AA43}.All|Any CPU.Build.0 = All|Any CPU
{4F7050F2-465F-4E10-8DB2-2FB97AC6AA43}.All|Mixed Platforms.ActiveCfg = All|Any CPU
{4F7050F2-465F-4E10-8DB2-2FB97AC6AA43}.All|Mixed Platforms.Build.0 = All|Any CPU
{4F7050F2-465F-4E10-8DB2-2FB97AC6AA43}.All|x86.ActiveCfg = All|Any CPU
{4F7050F2-465F-4E10-8DB2-2FB97AC6AA43}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{4F7050F2-465F-4E10-8DB2-2FB97AC6AA43}.Debug|Any CPU.Build.0 = Debug|Any CPU
{4F7050F2-465F-4E10-8DB2-2FB97AC6AA43}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
{4F7050F2-465F-4E10-8DB2-2FB97AC6AA43}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
{4F7050F2-465F-4E10-8DB2-2FB97AC6AA43}.Debug|x86.ActiveCfg = Debug|Any CPU
{4F7050F2-465F-4E10-8DB2-2FB97AC6AA43}.Release|Any CPU.ActiveCfg = Release|Any CPU
{4F7050F2-465F-4E10-8DB2-2FB97AC6AA43}.Release|Any CPU.Build.0 = Release|Any CPU
{4F7050F2-465F-4E10-8DB2-2FB97AC6AA43}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{4F7050F2-465F-4E10-8DB2-2FB97AC6AA43}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{4F7050F2-465F-4E10-8DB2-2FB97AC6AA43}.Release|x86.ActiveCfg = Release|Any CPU
{D011A778-59C8-4BFA-A770-C350216BF161}.All|Any CPU.ActiveCfg = Release|Any CPU
{D011A778-59C8-4BFA-A770-C350216BF161}.All|Any CPU.Build.0 = Release|Any CPU
{D011A778-59C8-4BFA-A770-C350216BF161}.All|Mixed Platforms.ActiveCfg = Release|Any CPU
{D011A778-59C8-4BFA-A770-C350216BF161}.All|Mixed Platforms.Build.0 = Release|Any CPU
{D011A778-59C8-4BFA-A770-C350216BF161}.All|x86.ActiveCfg = Release|Any CPU
{D011A778-59C8-4BFA-A770-C350216BF161}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{D011A778-59C8-4BFA-A770-C350216BF161}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D011A778-59C8-4BFA-A770-C350216BF161}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
{D011A778-59C8-4BFA-A770-C350216BF161}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
{D011A778-59C8-4BFA-A770-C350216BF161}.Debug|x86.ActiveCfg = Debug|Any CPU
{D011A778-59C8-4BFA-A770-C350216BF161}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D011A778-59C8-4BFA-A770-C350216BF161}.Release|Any CPU.Build.0 = Release|Any CPU
{D011A778-59C8-4BFA-A770-C350216BF161}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{D011A778-59C8-4BFA-A770-C350216BF161}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{D011A778-59C8-4BFA-A770-C350216BF161}.Release|x86.ActiveCfg = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE

85
src/ImageProcessor/ImageFactory.cs

@ -1,22 +1,25 @@
// -----------------------------------------------------------------------
// --------------------------------------------------------------------------------------------------------------------
// <copyright file="ImageFactory.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>
// Encapsulates methods for processing image files.
// </summary>
// --------------------------------------------------------------------------------------------------------------------
namespace ImageProcessor
{
#region Using
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Linq;
using ImageProcessor.Imaging;
using ImageProcessor.Processors;
#endregion
/// <summary>
@ -35,6 +38,11 @@ namespace ImageProcessor
/// </summary>
private ImageFormat backupImageFormat;
/// <summary>
/// Whether the image is indexed.
/// </summary>
private bool isIndexed;
/// <summary>
/// A value indicating whether this instance of the given entity has been disposed.
/// </summary>
@ -72,9 +80,9 @@ namespace ImageProcessor
#region Properties
/// <summary>
/// Gets or sets the local image for manipulation.
/// Gets the local image for manipulation.
/// </summary>
public Image Image { get; set; }
public Image Image { get; private set; }
/// <summary>
/// Gets the path to the local image for manipulation.
@ -114,7 +122,7 @@ namespace ImageProcessor
/// </returns>
public ImageFactory Load(MemoryStream memoryStream)
{
// Set our image as the memorystream value.
// Set our image as the memory stream value.
this.Image = Image.FromStream(memoryStream);
// Store the stream in the image Tag property so we can dispose of it later.
@ -124,6 +132,7 @@ namespace ImageProcessor
this.JpegQuality = DefaultJpegQuality;
this.backupImageFormat = ImageFormat.Jpeg;
this.ImageFormat = ImageFormat.Jpeg;
this.isIndexed = ImageUtils.IsIndexed(this.Image);
this.ShouldProcess = true;
return this;
@ -154,7 +163,7 @@ namespace ImageProcessor
this.ImagePath = path;
this.QueryString = query;
// Open a filstream to prevent the need for lock.
// Open a file stream to prevent the need for lock.
using (FileStream fileStream = new FileStream(path, FileMode.Open, FileAccess.Read))
{
MemoryStream memoryStream = new MemoryStream();
@ -165,7 +174,7 @@ namespace ImageProcessor
// Set the position to 0 afterwards.
fileStream.Position = memoryStream.Position = 0;
// Set our image as the memorystream value.
// Set our image as the memory stream value.
this.Image = Image.FromStream(memoryStream);
// Store the stream in the image Tag property so we can dispose of it later.
@ -176,6 +185,7 @@ namespace ImageProcessor
ImageFormat imageFormat = ImageUtils.GetImageFormat(imageName);
this.backupImageFormat = imageFormat;
this.ImageFormat = imageFormat;
this.isIndexed = ImageUtils.IsIndexed(this.Image);
this.ShouldProcess = true;
}
}
@ -183,6 +193,23 @@ namespace ImageProcessor
return this;
}
/// <summary>
/// Updates the specified image. Used by the various IProcessors.
/// </summary>
/// <param name="image">The image.</param>
/// <returns>
/// The current instance of the <see cref="T:ImageProcessor.ImageFactory"/> class.
/// </returns>
public ImageFactory Update(Image image)
{
if (this.ShouldProcess)
{
this.Image = image;
}
return this;
}
/// <summary>
/// Resets the current image to its original loaded state.
/// </summary>
@ -195,7 +222,7 @@ namespace ImageProcessor
{
MemoryStream memoryStream = (MemoryStream)this.Image.Tag;
// Set our new image as the memorystream value.
// Set our new image as the memory stream value.
Image newImage = Image.FromStream(memoryStream);
// Store the stream in the image Tag property so we can dispose of it later.
@ -208,6 +235,7 @@ namespace ImageProcessor
// Set the other properties.
this.JpegQuality = DefaultJpegQuality;
this.ImageFormat = this.backupImageFormat;
this.isIndexed = ImageUtils.IsIndexed(this.Image);
}
return this;
@ -386,13 +414,16 @@ namespace ImageProcessor
/// Sets the output format of the current image to the matching <see cref="T:System.Drawing.Imaging.ImageFormat"/>.
/// </summary>
/// <param name="imageFormat">The <see cref="T:System.Drawing.Imaging.ImageFormat"/>. to set the image to.</param>
/// <param name="indexedFormat">Whether the pixel format of the image should be indexed. Used for generating Png8 images.</param>
/// <returns>
/// The current instance of the <see cref="T:ImageProcessor.ImageFactory"/> class.
/// </returns>
public ImageFactory Format(ImageFormat imageFormat)
[SuppressMessage("StyleCop.CSharp.DocumentationRules", "SA1650:ElementDocumentationMustBeSpelledCorrectly", Justification = "Reviewed. Suppression is OK here.")]
public ImageFactory Format(ImageFormat imageFormat, bool indexedFormat = false)
{
if (this.ShouldProcess)
{
this.isIndexed = indexedFormat;
this.ImageFormat = imageFormat;
}
@ -584,8 +615,8 @@ namespace ImageProcessor
string extension = ImageUtils.GetExtensionFromImageFormat(this.ImageFormat);
filePath = length == -1 ? filePath + extension : filePath.Substring(0, length) + extension;
// Fix the colour palette of gif images.
this.FixGifs();
// Fix the colour palette of indexed images.
this.FixIndexedPallete();
if (this.ImageFormat.Equals(ImageFormat.Jpeg))
{
@ -594,12 +625,14 @@ namespace ImageProcessor
using (EncoderParameters encoderParameters = ImageUtils.GetEncodingParameters(this.JpegQuality))
{
ImageCodecInfo imageCodecInfo =
ImageCodecInfo.GetImageEncoders().FirstOrDefault(
ici => ici.MimeType.Equals("image/jpeg", StringComparison.OrdinalIgnoreCase));
ImageCodecInfo.GetImageEncoders()
.FirstOrDefault(
ici => ici.MimeType.Equals("image/jpeg", StringComparison.OrdinalIgnoreCase));
// ReSharper disable AssignNullToNotNullAttribute
this.Image.Save(filePath, imageCodecInfo, encoderParameters);
// ReSharper restore AssignNullToNotNullAttribute
if (imageCodecInfo != null)
{
this.Image.Save(filePath, imageCodecInfo, encoderParameters);
}
}
}
else
@ -625,7 +658,7 @@ namespace ImageProcessor
if (this.ShouldProcess)
{
// Fix the colour palette of gif images.
this.FixGifs();
this.FixIndexedPallete();
if (this.ImageFormat.Equals(ImageFormat.Jpeg))
{
@ -704,17 +737,15 @@ namespace ImageProcessor
#endregion
/// <summary>
/// Uses the <see cref="T:ImageProcessor.Imaging.OctreeQuantizer"/>
/// Uses the <see cref="T:ImageProcessor.Imaging.ColorQuantizer"/>
/// to fix the color palette of gif images.
/// </summary>
private void FixGifs()
private void FixIndexedPallete()
{
// Fix the colour palette of gif images.
// TODO: Why does the palette not get fixed when resized to the same dimensions.
if (object.Equals(this.ImageFormat, ImageFormat.Gif))
// Fix the colour palette of indexed images.
if (this.isIndexed)
{
OctreeQuantizer quantizer = new OctreeQuantizer(255, 8);
this.Image = quantizer.Quantize(this.Image);
this.Image = ColorQuantizer.Quantize(this.Image, PixelFormat.Format8bppIndexed);
}
}
#endregion

3
src/ImageProcessor/ImageProcessor.csproj

@ -61,6 +61,7 @@
<Compile Include="Helpers\Extensions\EnumExtensions.cs" />
<Compile Include="Helpers\Extensions\StringExtensions.cs" />
<Compile Include="ImageFactory.cs" />
<Compile Include="Imaging\ColorQuantizer.cs" />
<Compile Include="Imaging\Filters\BlackWhiteMatrixFilter.cs" />
<Compile Include="Imaging\Filters\ColorMatrixes.cs" />
<Compile Include="Imaging\Filters\ComicMatrixFilter.cs" />
@ -74,8 +75,6 @@
<Compile Include="Imaging\Filters\SepiaMatrixFilter.cs" />
<Compile Include="Imaging\Filters\IMatrixFilter.cs" />
<Compile Include="Imaging\ImageUtils.cs" />
<Compile Include="Imaging\OctreeQuantizer.cs" />
<Compile Include="Imaging\Quantizer.cs" />
<Compile Include="Imaging\ResponseType.cs" />
<Compile Include="Imaging\RotateLayer.cs" />
<Compile Include="Imaging\RoundedCornerLayer.cs" />

836
src/ImageProcessor/Imaging/ColorQuantizer.cs

@ -0,0 +1,836 @@
// --------------------------------------------------------------------------------------------------------------------
// <copyright file="ColorQuantizer.cs" company="James South">
// Copyright (c) James South.
// Licensed under the Apache License, Version 2.0.
// </copyright>
// <summary>
// The color quantizer.
// </summary>
// --------------------------------------------------------------------------------------------------------------------
namespace ImageProcessor.Imaging
{
#region Using
using System;
using System.Diagnostics.CodeAnalysis;
using System.Drawing;
using System.Drawing.Imaging;
using System.Runtime.InteropServices;
#endregion
/// <summary>
/// The color quantizer.
/// </summary>
[SuppressMessage("StyleCop.CSharp.DocumentationRules", "SA1650:ElementDocumentationMustBeSpelledCorrectly", Justification = "Reviewed. Suppression is OK here.")]
public static class ColorQuantizer
{
#region Quantize methods
/// <summary>The quantize.</summary>
/// <param name="image">The image.</param>
/// <param name="bitmapPixelFormat">The bitmap pixel format.</param>
/// <returns>The quantized image with the recalculated color palette.</returns>
public static Bitmap Quantize(Image image, PixelFormat bitmapPixelFormat)
{
// Use dither by default
return Quantize(image, bitmapPixelFormat, true);
}
/// <summary>The quantize.</summary>
/// <param name="image">The image.</param>
/// <param name="pixelFormat">The pixel format.</param>
/// <param name="useDither">The use dither.</param>
/// <returns>The quantized image with the recalculated color palette.</returns>
public static Bitmap Quantize(Image image, PixelFormat pixelFormat, bool useDither)
{
Bitmap tryBitmap = image as Bitmap;
if (tryBitmap != null && tryBitmap.PixelFormat == PixelFormat.Format32bppArgb)
{
// The image passed to us is ALREADY a bitmap in the right format. No need to create
// a copy and work from there.
return DoQuantize(tryBitmap, pixelFormat, useDither);
}
// We use these values a lot
int width = image.Width;
int height = image.Height;
Rectangle sourceRect = Rectangle.FromLTRB(0, 0, width, height);
// create a 24-bit rgb version of the source image
using (Bitmap bitmapSource = new Bitmap(width, height, PixelFormat.Format32bppArgb))
{
using (Graphics grfx = Graphics.FromImage(bitmapSource))
{
grfx.DrawImage(image, sourceRect, 0, 0, width, height, GraphicsUnit.Pixel);
}
return DoQuantize(bitmapSource, pixelFormat, useDither);
}
}
/// <summary>
/// Does the quantize.
/// </summary>
/// <param name="bitmapSource">The bitmap source.</param>
/// <param name="pixelFormat">The pixel format.</param>
/// <param name="useDither">if set to <c>true</c> [use dither].</param>
/// <returns>The quantized image with the recalculated color palette.</returns>
private static Bitmap DoQuantize(Bitmap bitmapSource, PixelFormat pixelFormat, bool useDither)
{
// We use these values a lot
int width = bitmapSource.Width;
int height = bitmapSource.Height;
Rectangle sourceRect = Rectangle.FromLTRB(0, 0, width, height);
Bitmap bitmapOptimized = null;
try
{
// Create a bitmap with the same dimensions and the desired format
bitmapOptimized = new Bitmap(width, height, pixelFormat);
// Lock the bits of the source image for reading.
// we will need to write if we do the dither.
BitmapData bitmapDataSource = bitmapSource.LockBits(
sourceRect,
ImageLockMode.ReadWrite,
PixelFormat.Format32bppArgb);
try
{
// Perform the first pass, which generates the octree data
// Create an Octree
Octree octree = new Octree(pixelFormat);
// Stride might be negative, indicating inverted row order.
// Allocate a managed buffer for the pixel data, and copy it from the unmanaged pointer.
int strideSource = Math.Abs(bitmapDataSource.Stride);
byte[] sourceDataBuffer = new byte[strideSource * height];
Marshal.Copy(bitmapDataSource.Scan0, sourceDataBuffer, 0, sourceDataBuffer.Length);
// We could skip every other row and/or every other column when sampling the colors
// of the source image, rather than hitting every other pixel. It doesn't seem to
// degrade the resulting image too much. But it doesn't really help the performance
// too much because the majority of the time seems to be spent in other places.
// For every row
int rowStartSource = 0;
for (int ndxRow = 0; ndxRow < height; ndxRow += 1)
{
// For each column
for (int ndxCol = 0; ndxCol < width; ndxCol += 1)
{
// Add the color (4 bytes per pixel - ARGB)
Pixel pixel = GetSourcePixel(sourceDataBuffer, rowStartSource, ndxCol);
octree.AddColor(pixel);
}
rowStartSource += strideSource;
}
// Get the optimized colors
Color[] colors = octree.GetPaletteColors();
// Set the palette from the octree
ColorPalette palette = bitmapOptimized.Palette;
for (var ndx = 0; ndx < palette.Entries.Length; ++ndx)
{
// Use the colors we calculated
// for the rest, just set to transparent
palette.Entries[ndx] = (ndx < colors.Length)
? colors[ndx]
: Color.Transparent;
}
bitmapOptimized.Palette = palette;
// Lock the bits of the optimized bitmap for writing.
// we will also need to read if we are doing 1bpp or 4bpp
BitmapData bitmapDataOutput = bitmapOptimized.LockBits(sourceRect, ImageLockMode.ReadWrite, pixelFormat);
try
{
// Create a managed array for the destination bytes given the desired color depth
// and marshal the unmanaged data to the managed array
int strideOutput = Math.Abs(bitmapDataOutput.Stride);
byte[] bitmapOutputBuffer = new byte[strideOutput * height];
// For each source pixel, compute the appropriate color index
rowStartSource = 0;
int rowStartOutput = 0;
for (int ndxRow = 0; ndxRow < height; ++ndxRow)
{
// For each column
for (int ndxCol = 0; ndxCol < width; ++ndxCol)
{
// Get the source color
Pixel pixel = GetSourcePixel(sourceDataBuffer, rowStartSource, ndxCol);
// Get the closest palette index
int paletteIndex = octree.GetPaletteIndex(pixel);
// If we want to dither and this isn't the transparent pixel
if (useDither && pixel.Alpha != 0)
{
// Calculate the error
Color paletteColor = colors[paletteIndex];
int deltaRed = pixel.Red - paletteColor.R;
int deltaGreen = pixel.Green - paletteColor.G;
int deltaBlue = pixel.Blue - paletteColor.B;
// Propagate the dither error.
// we'll use a standard Floyd-Steinberg matrix (1/16):
// | 0 0 0 |
// | 0 x 7 |
// | 3 5 1 |
// Make sure we're not on the right-hand edge
if (ndxCol + 1 < width)
{
DitherSourcePixel(sourceDataBuffer, rowStartSource, ndxCol + 1, deltaRed, deltaGreen, deltaBlue, 7);
}
// Make sure we're not already on the bottom row
if (ndxRow + 1 < height)
{
int nextRow = rowStartSource + strideSource;
// Make sure we're not on the left-hand column
if (ndxCol > 0)
{
// Down one row, but back one pixel
DitherSourcePixel(sourceDataBuffer, nextRow, ndxCol - 1, deltaRed, deltaGreen, deltaBlue, 3);
}
// pixel directly below us
DitherSourcePixel(sourceDataBuffer, nextRow, ndxCol, deltaRed, deltaGreen, deltaBlue, 5);
// Make sure we're not on the right-hand column
if (ndxCol + 1 < width)
{
// Down one row, but right one pixel
DitherSourcePixel(sourceDataBuffer, nextRow, ndxCol + 1, deltaRed, deltaGreen, deltaBlue, 1);
}
}
}
// Set the bitmap index based on the format
switch (pixelFormat)
{
case PixelFormat.Format8bppIndexed:
// Each byte is a palette index
bitmapOutputBuffer[rowStartOutput + ndxCol] = (byte)paletteIndex;
break;
case PixelFormat.Format4bppIndexed:
// Each byte contains two pixels
bitmapOutputBuffer[rowStartOutput + (ndxCol >> 1)] |= ((ndxCol & 1) == 1)
? (byte)(paletteIndex & 0x0f) // lower nibble
: (byte)(paletteIndex << 4); // upper nibble
break;
case PixelFormat.Format1bppIndexed:
// Each byte contains eight pixels
if (paletteIndex != 0)
{
bitmapOutputBuffer[rowStartOutput + (ndxCol >> 3)] |= (byte)(0x80 >> (ndxCol & 0x07));
}
break;
}
}
rowStartSource += strideSource;
rowStartOutput += strideOutput;
}
// Now copy the calculated pixel bytes from the managed array to the unmanaged bitmap
Marshal.Copy(bitmapOutputBuffer, 0, bitmapDataOutput.Scan0, bitmapOutputBuffer.Length);
}
finally
{
bitmapOptimized.UnlockBits(bitmapDataOutput);
bitmapDataOutput = null;
}
}
finally
{
bitmapSource.UnlockBits(bitmapDataSource);
bitmapDataSource = null;
}
}
catch (Exception)
{
// If any exception is thrown, dispose of the bitmap object
// we've been working on before we rethrow and bail
if (bitmapOptimized != null)
{
bitmapOptimized.Dispose();
}
throw;
}
// Caller is responsible for disposing of this bitmap!
return bitmapOptimized;
}
/// <summary>
/// Dithers the source pixel.
/// </summary>
/// <param name="buffer">The buffer.</param>
/// <param name="rowStart">The row start.</param>
/// <param name="col">The column.</param>
/// <param name="deltaRed">The delta red.</param>
/// <param name="deltaGreen">The delta green.</param>
/// <param name="deltaBlue">The delta blue.</param>
/// <param name="weight">The weight.</param>
private static void DitherSourcePixel(byte[] buffer, int rowStart, int col, int deltaRed, int deltaGreen, int deltaBlue, int weight)
{
int colorIndex = rowStart + (col * 4);
buffer[colorIndex + 2] = ChannelAdjustment(buffer[colorIndex + 2], (deltaRed * weight) >> 4);
buffer[colorIndex + 1] = ChannelAdjustment(buffer[colorIndex + 1], (deltaGreen * weight) >> 4);
buffer[colorIndex] = ChannelAdjustment(buffer[colorIndex], (deltaBlue * weight) >> 4);
}
/// <summary>
/// Gets the source pixel.
/// </summary>
/// <param name="buffer">The buffer.</param>
/// <param name="rowStart">The row start.</param>
/// <param name="col">The column.</param>
/// <returns>The source pixel.</returns>
private static Pixel GetSourcePixel(byte[] buffer, int rowStart, int col)
{
int colorIndex = rowStart + (col * 4);
return new Pixel
{
Alpha = buffer[colorIndex + 3],
Red = buffer[colorIndex + 2],
Green = buffer[colorIndex + 1],
Blue = buffer[colorIndex]
};
}
#endregion
/// <summary>Gets the channel adjustment.</summary>
/// <param name="current">The current.</param>
/// <param name="offset">The offset.</param>
/// <returns>The channel adjustment.</returns>
private static byte ChannelAdjustment(byte current, int offset)
{
return (byte)Math.Min(255, Math.Max(0, current + offset));
}
#region Octree class
/// <summary>data structure for storing and reducing colors used in the source image</summary>
private class Octree
{
/// <summary>The m_max colors.</summary>
private readonly int octreeMaxColors;
/// <summary>The m_reducible nodes.</summary>
private readonly OctreeNode[] octreeReducibleNodes;
/// <summary>The m_color count.</summary>
private int octreeColorCount;
/// <summary>The m_has transparent.</summary>
private bool octreeHasTransparent;
/// <summary>The m_last argb.</summary>
private int octreeLastArgb;
/// <summary>The m_last node.</summary>
private OctreeNode octreeLastNode;
/// <summary>The m_palette.</summary>
private Color[] octreePalette;
/// <summary>The m_root.</summary>
private OctreeNode octreeRoot;
/// <summary>Initializes a new instance of the <see cref="Octree"/> class. Constructor</summary>
/// <param name="pixelFormat">desired pixel format</param>
internal Octree(PixelFormat pixelFormat)
{
// figure out the maximum colors from the pixel format passed in
switch (pixelFormat)
{
case PixelFormat.Format1bppIndexed:
this.octreeMaxColors = 2;
break;
case PixelFormat.Format4bppIndexed:
this.octreeMaxColors = 16;
break;
case PixelFormat.Format8bppIndexed:
this.octreeMaxColors = 256;
break;
default:
throw new ArgumentException("Invalid Pixel Format", "pixelFormat");
}
// we need a list for each level that may have reducible nodes.
// since the last level (level 7) is only made up of leaf nodes,
// we don't need an array entry for it.
this.octreeReducibleNodes = new OctreeNode[7];
// add the initial level-0 root node
this.octreeRoot = new OctreeNode(0, this);
}
/// <summary>Add the given pixel color to the octree</summary>
/// <param name="pixel">points to the pixel color we want to add</param>
internal void AddColor(Pixel pixel)
{
// If the A value is non-zero (ignore the transparent color)
if (pixel.Alpha > 0)
{
// If we have a previous node and this color is the same as the last...
if (this.octreeLastNode != null && pixel.Argb == this.octreeLastArgb)
{
// Just add this color to the same last node
this.octreeLastNode.AddColor(pixel);
}
else
{
// Just start at the root. If a new color is added,
// add one to the count (otherwise 0).
this.octreeColorCount += this.octreeRoot.AddColor(pixel) ? 1 : 0;
}
}
else
{
// Flag that we have a transparent color.
this.octreeHasTransparent = true;
}
}
/// <summary>
/// Given a pixel color, return the index of the palette entry
/// we want to use in the reduced image. If the color is not in the
/// octree, OctreeNode.GetPaletteIndex will return a negative number.
/// In that case, we will have to calculate the palette index the brute-force
/// method by computing the least distance to each color in the palette array.
/// </summary>
/// <param name="pixel">pointer to the pixel color we want to look up</param>
/// <returns>index of the palette entry we want to use for this color</returns>
internal int GetPaletteIndex(Pixel pixel)
{
int paletteIndex = 0;
// transparent is always the first entry, so if this is transparent,
// don't do anything.
if (pixel.Alpha > 0)
{
paletteIndex = this.octreeRoot.GetPaletteIndex(pixel);
// returns -1 if this value isn't in the octree.
if (paletteIndex < 0)
{
// Use the brute-force method of calculating the closest color
// in the palette to the one we want
int minDistance = int.MaxValue;
for (int ndx = 0; ndx < this.octreePalette.Length; ++ndx)
{
Color paletteColor = this.octreePalette[ndx];
// Calculate the delta for each channel
int deltaRed = pixel.Red - paletteColor.R;
int deltaGreen = pixel.Green - paletteColor.G;
int deltaBlue = pixel.Blue - paletteColor.B;
// Calculate the distance-squared by summing each channel's square
int distance = (deltaRed * deltaRed) + (deltaGreen * deltaGreen) + (deltaBlue * deltaBlue);
if (distance < minDistance)
{
minDistance = distance;
paletteIndex = ndx;
}
}
}
}
return paletteIndex;
}
/// <summary>
/// Return a color palette for the computed octree.
/// </summary>
/// <returns>A color palette for the computed octree</returns>
internal Color[] GetPaletteColors()
{
// If we haven't already computed it, compute it now
if (this.octreePalette == null)
{
// Start at the second-to-last reducible level
int reductionLevel = this.octreeReducibleNodes.Length - 1;
// We want to subtract one from the target if we have a transparent
// bit because we want to save room for that special color
int targetCount = this.octreeMaxColors - (this.octreeHasTransparent ? 1 : 0);
// While we still have more colors than the target...
while (this.octreeColorCount > targetCount)
{
// Find the first reducible node, starting with the last level
// that can have reducible nodes
while (reductionLevel > 0 && this.octreeReducibleNodes[reductionLevel] == null)
{
--reductionLevel;
}
if (this.octreeReducibleNodes[reductionLevel] == null)
{
// Shouldn't get here
break;
}
// We should have a node now
OctreeNode newLeaf = this.octreeReducibleNodes[reductionLevel];
this.octreeReducibleNodes[reductionLevel] = newLeaf.NextReducibleNode;
this.octreeColorCount -= newLeaf.Reduce() - 1;
}
if (reductionLevel == 0 && !this.octreeHasTransparent)
{
// If this was the top-most level, we now only have a single color
// representing the average. That's not what we want.
// use just black and white
this.octreePalette = new Color[2];
this.octreePalette[0] = Color.Black;
this.octreePalette[1] = Color.White;
// And empty the octree so it always picks the closer of the black and white entries
this.octreeRoot = new OctreeNode(0, this);
}
else
{
// Now walk the tree, adding all the remaining colors to the list
int paletteIndex = 0;
this.octreePalette = new Color[this.octreeColorCount + (this.octreeHasTransparent ? 1 : 0)];
// Add the transparent color if we need it
if (this.octreeHasTransparent)
{
this.octreePalette[paletteIndex++] = Color.Transparent;
}
// Have the nodes insert their leaf colors
this.octreeRoot.AddColorsToPalette(this.octreePalette, ref paletteIndex);
}
}
return this.octreePalette;
}
/// <summary>set up the values we need to reuse the given pointer if the next color is argb</summary>
/// <param name="node">last node to which we added a color</param>
/// <param name="argb">last color we added</param>
private void SetLastNode(OctreeNode node, int argb)
{
this.octreeLastNode = node;
this.octreeLastArgb = argb;
}
/// <summary>When a reducible node is added, this method is called to add it to the appropriate
/// reducible node list (given its level)</summary>
/// <param name="reducibleNode">node to add to a reducible list</param>
private void AddReducibleNode(OctreeNode reducibleNode)
{
// hook this node into the front of the list.
// this means the last one added will be the first in the list.
reducibleNode.NextReducibleNode = this.octreeReducibleNodes[reducibleNode.Level];
this.octreeReducibleNodes[reducibleNode.Level] = reducibleNode;
}
#region OctreeNode class
/// <summary>Node for an Octree structure</summary>
private class OctreeNode
{
/// <summary>The s_level masks.</summary>
private static readonly byte[] NodeLevelMasks = { 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01 };
/// <summary>The m_level.</summary>
private readonly int nodeLevel;
/// <summary>The m_octree.</summary>
private readonly Octree nodeOctree;
/// <summary>The m_blue sum.</summary>
private int nodeBlueSum;
/// <summary>The m_child nodes.</summary>
private OctreeNode[] nodeChildNodes;
/// <summary>The m_green sum.</summary>
private int nodeGreenSum;
/// <summary>The m_is leaf.</summary>
private bool nodeIsLeaf;
/// <summary>The m_palette index.</summary>
private int nodePaletteIndex;
/// <summary>
/// The pixel count.Information we need to calculate the average color for a set of pixels
/// </summary>
private int nodePixelCount;
/// <summary>The m_red sum.</summary>
private int nodeRedSum;
/// <summary>Initializes a new instance of the <see cref="OctreeNode"/> class. Constructor</summary>
/// <param name="level">level for this node</param>
/// <param name="octree">owning octree</param>
internal OctreeNode(int level, Octree octree)
{
this.nodeOctree = octree;
this.nodeLevel = level;
// Since there are only eight levels, if we get to level 7
// We automatically make this a leaf node
this.nodeIsLeaf = level == 7;
if (!this.nodeIsLeaf)
{
// Create the child array
this.nodeChildNodes = new OctreeNode[8];
// Add it to the tree's reducible node list
this.nodeOctree.AddReducibleNode(this);
}
}
/// <summary>Gets Level.</summary>
internal int Level
{
get { return this.nodeLevel; }
}
/// <summary>
/// Gets or sets NextReducibleNode.
/// Once we compute a palette, this will be set
/// to the palette index associated with this leaf node.
/// Nodes are arranged in linked lists of reducible nodes for a given level.
/// this field and property is used to traverse that list.
/// </summary>
internal OctreeNode NextReducibleNode { get; set; }
/// <summary>
/// Gets the average color for this node.
/// </summary>
private Color NodeColor
{
get
{
// Average color is the sum of each channel divided by the pixel count
return Color.FromArgb(
this.nodeRedSum / this.nodePixelCount,
this.nodeGreenSum / this.nodePixelCount,
this.nodeBlueSum / this.nodePixelCount);
}
}
/// <summary>
/// Add the given color to this node if it is a leaf, otherwise recurse
/// down the appropriate child
/// </summary>
/// <param name="pixel">color to add</param>
/// <returns>true if a new color was added to the octree</returns>
internal bool AddColor(Pixel pixel)
{
bool colorAdded;
if (this.nodeIsLeaf)
{
// Increase the pixel count for this node, and if
// the result is 1, then this is a new color
colorAdded = ++this.nodePixelCount == 1;
// Add the color to the running sum for this node
this.nodeRedSum += pixel.Red;
this.nodeGreenSum += pixel.Green;
this.nodeBlueSum += pixel.Blue;
// Set the last node so we can quickly process adjacent pixels
// with the same color
this.nodeOctree.SetLastNode(this, pixel.Argb);
}
else
{
// Get the index at this level for the rgb values
int childIndex = this.GetChildIndex(pixel);
// If there is no child, add one now to the next level
if (this.nodeChildNodes[childIndex] == null)
{
this.nodeChildNodes[childIndex] = new OctreeNode(this.nodeLevel + 1, this.nodeOctree);
}
// Recurse...
colorAdded = this.nodeChildNodes[childIndex].AddColor(pixel);
}
return colorAdded;
}
/// <summary>
/// Given a source color, return the palette index to use for the reduced image.
/// Returns -1 if the color is not represented in the octree (this happens if
/// the color has been dithered into a new color that did not appear in the
/// original image when the octree was formed in pass 1.
/// </summary>
/// <param name="pixel">source color to look up</param>
/// <returns>palette index to use</returns>
internal int GetPaletteIndex(Pixel pixel)
{
int paletteIndex = -1;
if (this.nodeIsLeaf)
{
// Use this leaf node's palette index
paletteIndex = this.nodePaletteIndex;
}
else
{
// Get the index at this level for the rgb values
var childIndex = this.GetChildIndex(pixel);
if (this.nodeChildNodes[childIndex] != null)
{
// Recurse...
paletteIndex = this.nodeChildNodes[childIndex].GetPaletteIndex(pixel);
}
}
return paletteIndex;
}
/// <summary>Reduce this node by combining all child nodes</summary>
/// <returns>number of nodes removed</returns>
internal int Reduce()
{
int numReduced = 0;
if (!this.nodeIsLeaf)
{
// For each child
foreach (OctreeNode node in this.nodeChildNodes)
{
if (node != null)
{
OctreeNode childNode = node;
// add the pixel count from the child
this.nodePixelCount += childNode.nodePixelCount;
// add the running color sums from the child
this.nodeRedSum += childNode.nodeRedSum;
this.nodeGreenSum += childNode.nodeGreenSum;
this.nodeBlueSum += childNode.nodeBlueSum;
++numReduced;
}
}
this.nodeChildNodes = null;
this.nodeIsLeaf = true;
}
return numReduced;
}
/// <summary>
/// If this is a leaf node, add its color to the palette array at the given index
/// and increment the index. If not a leaf, recurse the children nodes.
/// </summary>
/// <param name="colorArray">array of colors</param>
/// <param name="paletteIndex">index of the next empty slot in the array</param>
internal void AddColorsToPalette(Color[] colorArray, ref int paletteIndex)
{
if (this.nodeIsLeaf)
{
// Save our index and increment the running index
this.nodePaletteIndex = paletteIndex++;
// The color for this node is the average color, which is created by
// dividing the running sums for each channel by the pixel count
colorArray[this.nodePaletteIndex] = this.NodeColor;
}
else
{
// Just run through all the non-null children and recurse
foreach (OctreeNode node in this.nodeChildNodes)
{
if (node != null)
{
node.AddColorsToPalette(colorArray, ref paletteIndex);
}
}
}
}
/// <summary>
/// Return the child index for a given color.
/// Depends on which level this node is in.
/// </summary>
/// <param name="pixel">color pixel to compute</param>
/// <returns>child index (0-7)</returns>
private int GetChildIndex(Pixel pixel)
{
// lvl: 0 1 2 3 4 5 6 7
// bit: 7 6 5 4 3 2 1 0
var shift = 7 - this.nodeLevel;
int mask = NodeLevelMasks[this.nodeLevel];
return ((pixel.Red & mask) >> (shift - 2)) |
((pixel.Green & mask) >> (shift - 1)) |
((pixel.Blue & mask) >> shift);
}
}
#endregion
}
#endregion
#region Pixel class for ARGB values
/// <summary>
/// Structure of a Format32bppArgb pixel in memory.
/// </summary>
private class Pixel
{
/// <summary>
/// Gets or sets the blue component of the pixel.
/// </summary>
public byte Blue { get; set; }
/// <summary>
/// Gets or sets the green component of the pixel.
/// </summary>
public byte Green { get; set; }
/// <summary>
/// Gets or sets the red component of the pixel.
/// </summary>
public byte Red { get; set; }
/// <summary>
/// Gets or sets the alpha component of the pixel.
/// </summary>
public byte Alpha { get; set; }
/// <summary>
/// Gets the argb combination of the pixel.
/// </summary>
public int Argb
{
get
{
return this.Alpha << 24 | this.Red << 16 | this.Green << 8 | this.Blue;
}
}
}
#endregion
}
}

4
src/ImageProcessor/Imaging/Filters/GothamMatrixFilter.cs

@ -76,11 +76,11 @@ namespace ImageProcessor.Imaging.Filters
}
// Add brightness and contrast to finish the effect.
factory.Image = newImage;
factory.Update(newImage);
Brightness brightness = new Brightness { DynamicParameter = 5 };
newImage = (Bitmap)brightness.ProcessImage(factory);
factory.Image = newImage;
factory.Update(newImage);
Contrast contrast = new Contrast { DynamicParameter = 85 };
newImage = (Bitmap)contrast.ProcessImage(factory);

2
src/ImageProcessor/Imaging/Filters/LomographMatrixFilter.cs

@ -57,7 +57,7 @@ namespace ImageProcessor.Imaging.Filters
}
// Add a vignette to finish the effect.
factory.Image = newImage;
factory.Update(newImage);
Vignette vignette = new Vignette();
newImage = (Bitmap)vignette.ProcessImage(factory);

2
src/ImageProcessor/Imaging/Filters/PolaroidMatrixFilter.cs

@ -86,7 +86,7 @@ namespace ImageProcessor.Imaging.Filters
}
// Add a vignette to finish the effect.
factory.Image = newImage;
factory.Update(newImage);
Vignette vignette = new Vignette();
newImage = (Bitmap)vignette.ProcessImage(factory);

61
src/ImageProcessor/Imaging/ImageUtils.cs

@ -1,14 +1,18 @@
// -----------------------------------------------------------------------
// --------------------------------------------------------------------------------------------------------------------
// <copyright file="ImageUtils.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>
// Encapsulates useful image utility methods.
// </summary>
// --------------------------------------------------------------------------------------------------------------------
namespace ImageProcessor.Imaging
{
#region Using
using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Linq;
@ -24,7 +28,7 @@ namespace ImageProcessor.Imaging
/// <summary>
/// The image format regex.
/// </summary>
private static readonly Regex FormatRegex = new Regex(@"j(pg|peg)|bmp|png|gif", RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.RightToLeft);
private static readonly Regex FormatRegex = new Regex(@"(\.?)(j(pg|peg)|bmp|png|gif|ti(f|ff))$", RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.RightToLeft);
/// <summary>
/// Returns the correct response type based on the given request path.
@ -39,14 +43,17 @@ namespace ImageProcessor.Imaging
{
foreach (Match match in FormatRegex.Matches(request))
{
switch (match.Value)
switch (match.Value.ToUpperInvariant())
{
case "png":
case "PNG":
return ResponseType.Png;
case "bmp":
case "BMP":
return ResponseType.Bmp;
case "gif":
case "GIF":
return ResponseType.Gif;
case "TIF":
case "TIFF":
return ResponseType.Tiff;
default:
return ResponseType.Jpeg;
}
@ -75,6 +82,9 @@ namespace ImageProcessor.Imaging
return ImageFormat.Bmp;
case ".GIF":
return ImageFormat.Gif;
case ".TIF":
case ".TIFF":
return ImageFormat.Tiff;
default:
// Should be a jpeg.
return ImageFormat.Jpeg;
@ -104,6 +114,10 @@ namespace ImageProcessor.Imaging
return ".bmp";
case "Png":
return ".png";
case "Tif":
return ".tif";
case "Tiff":
return ".tif";
default:
return ".jpg";
}
@ -126,6 +140,8 @@ namespace ImageProcessor.Imaging
return ImageFormat.Bmp;
case ResponseType.Gif:
return ImageFormat.Gif;
case ResponseType.Tiff:
return ImageFormat.Tiff;
default:
// Should be a jpeg.
return ImageFormat.Jpeg;
@ -181,25 +197,16 @@ namespace ImageProcessor.Imaging
/// <returns>True the value contains a valid image extension, otherwise false.</returns>
public static bool IsValidImageExtension(string fileName)
{
bool isValid = false;
if (!string.IsNullOrWhiteSpace(fileName))
{
string[] fileExtensions = { ".BMP", ".JPG", ".PNG", ".GIF", ".JPEG" };
Parallel.ForEach(
fileExtensions,
(extension, loop) =>
{
if (fileName.ToUpperInvariant().EndsWith(extension))
{
isValid = true;
loop.Stop();
}
});
}
return FormatRegex.IsMatch(fileName);
}
return isValid;
/// <summary>Returns a value indicating whether or not the given bitmap is indexed.</summary>
/// <param name="image">The image to check</param>
/// <returns>Whether or not the given bitmap is indexed.</returns>
public static bool IsIndexed(Image image)
{
// Test value of flags using bitwise AND.
return (image.PixelFormat & PixelFormat.Indexed) != 0;
}
}
}

543
src/ImageProcessor/Imaging/OctreeQuantizer.cs

@ -1,543 +0,0 @@
// -----------------------------------------------------------------------
// <copyright file="OctreeQuantizer.cs" company="James South">
// Copyright (c) James South.
// Licensed under the Apache License, Version 2.0.
// </copyright>
// -----------------------------------------------------------------------
namespace ImageProcessor.Imaging
{
#region Using
using System;
using System.Collections;
using System.Drawing;
using System.Drawing.Imaging;
#endregion
/// <summary>
/// Encapsulates methods to calculate the colour palette if an image using an octree pattern.
/// </summary>
internal class OctreeQuantizer : Quantizer
{
#region Fields
/// <summary>
/// Stores the tree.
/// </summary>
private readonly Octree octree;
/// <summary>
/// The maximum allowed color depth.
/// </summary>
private readonly int maxColors;
#endregion
/// <summary>
/// Initializes a new instance of the <see cref="T:ImageProcessor.Imaging.OctreeQuantizer">OctreeQuantizer</see> class.
/// </summary>
/// <remarks>
/// The Octree quantizer is a two pass algorithm. The initial pass sets up the octree,
/// the second pass quantizes a colour based on the nodes in the tree
/// </remarks>
/// <param name="maxColors">The maximum number of colours to return, maximum 255.</param>
/// <param name="maxColorBits">The number of significant bits minimum 1, maximum 8.</param>
public OctreeQuantizer(int maxColors, int maxColorBits)
: base(false)
{
if (maxColors > 255)
{
throw new ArgumentOutOfRangeException("maxColors", maxColors, "The number of colours should be less than 256");
}
if ((maxColorBits < 1) | (maxColorBits > 8))
{
throw new ArgumentOutOfRangeException("maxColorBits", maxColorBits, "This should be between 1 and 8");
}
// Construct the octree
this.octree = new Octree(maxColorBits);
this.maxColors = maxColors;
}
/// <summary>
/// Process the pixel in the first pass of the algorithm.
/// </summary>
/// <param name="pixel">The pixel to quantize</param>
/// <remarks>
/// This function need only be overridden if your quantize algorithm needs two passes,
/// such as an Octree quantizer.
/// </remarks>
protected override void InitialQuantizePixel(Color32 pixel)
{
// Add the colour to the octree
this.octree.AddColor(pixel);
}
/// <summary>
/// Override this to process the pixel in the second pass of the algorithm.
/// </summary>
/// <param name="pixel">The pixel to quantize</param>
/// <returns>The quantized value.</returns>
protected override byte QuantizePixel(Color32 pixel)
{
// The colour at [this.maxColors] is set to transparent
byte paletteIndex;
// Get the palette index if this non-transparent
if (pixel.Alpha > 0)
{
paletteIndex = (byte)this.octree.GetPaletteIndex(pixel);
}
else
{
paletteIndex = (byte)this.maxColors;
}
return paletteIndex;
}
/// <summary>
/// Retrieve the palette for the quantized image
/// </summary>
/// <param name="original">Any old palette, this is overwritten</param>
/// <returns>The new colour palette</returns>
protected override ColorPalette GetPalette(ColorPalette original)
{
// First off convert the octree to this.maxColors colours
ArrayList palette = this.octree.Palletize(this.maxColors - 1);
// Then convert the palette based on those colours
for (int index = 0; index < palette.Count; index++)
{
original.Entries[index] = (Color)palette[index];
}
// Add the transparent colour
original.Entries[this.maxColors] = Color.FromArgb(0, 0, 0, 0);
return original;
}
/// <summary>
/// Describes a tree data structure in which each internal node has exactly eight children.
/// </summary>
private class Octree
{
#region Fields
/// <summary>
/// Mask used when getting the appropriate pixels for a given node
/// </summary>
private static readonly int[] mask = new int[8] { 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01 };
/// <summary>
/// The root of the octree
/// </summary>
private readonly OctreeNode root;
/// <summary>
/// Number of leaves in the tree
/// </summary>
private int leafCount;
/// <summary>
/// Array of reducible nodes
/// </summary>
private OctreeNode[] reducibleNodes;
/// <summary>
/// Maximum number of significant bits in the image
/// </summary>
private int maxColorBits;
/// <summary>
/// Store the last node quantized
/// </summary>
private OctreeNode previousNode;
/// <summary>
/// Cache the previous color quantized
/// </summary>
private int previousColor;
#endregion
#region Constructors
/// <summary>
/// Initializes a new instance of the <see cref="T:ImageProcessor.Imaging.OctreeQuantizer.Octree">Octree</see> class.
/// </summary>
/// <param name="maxBits">The maximum number of significant bits in the image</param>
public Octree(int maxBits)
{
this.maxColorBits = maxBits;
this.leafCount = 0;
this.reducibleNodes = new OctreeNode[9];
this.root = new OctreeNode(0, this.maxColorBits, this);
this.previousColor = 0;
this.previousNode = null;
}
#endregion
#region Properties
/// <summary>
/// Gets or sets the number of leaves in the tree
/// </summary>
public int Leaves
{
get { return this.leafCount; }
set { this.leafCount = value; }
}
/// <summary>
/// Gets the array of reducible nodes
/// </summary>
protected OctreeNode[] ReducibleNodes
{
get { return this.reducibleNodes; }
}
#endregion
/// <summary>
/// Add a given colour value to the octree
/// </summary>
/// <param name="pixel">
/// The color value to add.
/// </param>
public void AddColor(Color32 pixel)
{
// Check if this request is for the same colour as the last
if (this.previousColor == pixel.ARGB)
{
// If so, check if I have a previous node setup. This will only occur if the first colour in the image
// happens to be black, with an alpha component of zero.
if (null == this.previousNode)
{
this.previousColor = pixel.ARGB;
this.root.AddColor(pixel, this.maxColorBits, 0, this);
}
else
{
// Just update the previous node
this.previousNode.Increment(pixel);
}
}
else
{
this.previousColor = pixel.ARGB;
this.root.AddColor(pixel, this.maxColorBits, 0, this);
}
}
/// <summary>
/// Reduce the depth of the tree
/// </summary>
public void Reduce()
{
// Find the deepest level containing at least one reducible node
int index = this.maxColorBits - 1;
while ((index > 0) && (this.reducibleNodes[index] == null))
{
index--;
}
// Reduce the node most recently added to the list at level 'index'
OctreeNode node = this.reducibleNodes[index];
this.reducibleNodes[index] = node.NextReducible;
// Decrement the leaf count after reducing the node
this.leafCount -= node.Reduce();
// And just in case I've reduced the last color to be added, and the next color to
// be added is the same, invalidate the previousNode...
this.previousNode = null;
}
/// <summary>
/// Convert the nodes in the octree to a palette with a maximum of colorCount colours
/// </summary>
/// <param name="colorCount">The maximum number of colours</param>
/// <returns>An array list with the palletized colours</returns>
public ArrayList Palletize(int colorCount)
{
while (this.Leaves > colorCount)
{
this.Reduce();
}
// Now palletize the nodes
ArrayList palette = new ArrayList(this.Leaves);
int paletteIndex = 0;
this.root.ConstructPalette(palette, ref paletteIndex);
// And return the palette
return palette;
}
/// <summary>
/// Get the palette index for the passed colour.
/// </summary>
/// <param name="pixel">
/// The color to return the palette index for.
/// </param>
/// <returns>
/// The palette index for the passed colour.
/// </returns>
public int GetPaletteIndex(Color32 pixel)
{
return this.root.GetPaletteIndex(pixel, 0);
}
/// <summary>
/// Keep track of the previous node that was quantized
/// </summary>
/// <param name="node">The node last quantized</param>
protected void TrackPrevious(OctreeNode node)
{
this.previousNode = node;
}
/// <summary>
/// Class which encapsulates each node in the tree
/// </summary>
protected class OctreeNode
{
#region Fields
/// <summary>
/// Flag indicating that this is a leaf node
/// </summary>
private bool leaf;
/// <summary>
/// Number of pixels in this node
/// </summary>
private int pixelCount;
/// <summary>
/// Red component
/// </summary>
private int red;
/// <summary>
/// Green Component
/// </summary>
private int green;
/// <summary>
/// Blue component
/// </summary>
private int blue;
/// <summary>
/// Pointers to any child nodes
/// </summary>
private OctreeNode[] children;
/// <summary>
/// The index of this node in the palette
/// </summary>
private int paletteIndex;
#endregion
#region Constructors
/// <summary>
/// Initializes a new instance of the <see cref="OctreeNode"/> class.
/// </summary>
/// <param name="level">
/// The level in the tree = 0 - 7
/// </param>
/// <param name="colorBits">
/// The number of significant color bits in the image
/// </param>
/// <param name="octree">
/// The tree to which this node belongs
/// </param>
public OctreeNode(int level, int colorBits, Octree octree)
{
// Construct the new node
this.leaf = level == colorBits;
this.red = this.green = this.blue = 0;
this.pixelCount = 0;
// If a leaf, increment the leaf count
if (this.leaf)
{
octree.Leaves++;
this.NextReducible = null;
this.children = null;
}
else
{
// Otherwise add this to the reducible nodes
this.NextReducible = octree.ReducibleNodes[level];
octree.ReducibleNodes[level] = this;
this.children = new OctreeNode[8];
}
}
#endregion
#region Properties
/// <summary>
/// Gets or the next reducible node
/// </summary>
public OctreeNode NextReducible { get; private set; }
/// <summary>
/// Gets the child nodes
/// </summary>
private OctreeNode[] Children
{
get { return this.children; }
}
#endregion
#region Methods
/// <summary>
/// Add a color into the tree
/// </summary>
/// <param name="pixel">The color</param>
/// <param name="colorBits">The number of significant color bits</param>
/// <param name="level">The level in the tree</param>
/// <param name="octree">The tree to which this node belongs</param>
public void AddColor(Color32 pixel, int colorBits, int level, Octree octree)
{
// Update the color information if this is a leaf
if (this.leaf)
{
this.Increment(pixel);
// Setup the previous node
octree.TrackPrevious(this);
}
else
{
// Go to the next level down in the tree
int shift = 7 - level;
int index = ((pixel.Red & mask[level]) >> (shift - 2)) |
((pixel.Green & mask[level]) >> (shift - 1)) |
((pixel.Blue & mask[level]) >> shift);
OctreeNode child = this.Children[index];
if (null == child)
{
// Create a new child node & store in the array
child = new OctreeNode(level + 1, colorBits, octree);
this.Children[index] = child;
}
// Add the color to the child node
child.AddColor(pixel, colorBits, level + 1, octree);
}
}
/// <summary>
/// Reduce this node by removing all of its children
/// </summary>
/// <returns>The number of leaves removed</returns>
public int Reduce()
{
this.red = this.green = this.blue = 0;
int childPosition = 0;
// Loop through all children and add their information to this node
for (int index = 0; index < 8; index++)
{
if (null != this.Children[index])
{
this.red += this.Children[index].red;
this.green += this.Children[index].green;
this.blue += this.Children[index].blue;
this.pixelCount += this.Children[index].pixelCount;
++childPosition;
this.Children[index] = null;
}
}
// Now change this to a leaf node
this.leaf = true;
// Return the number of nodes to decrement the leaf count by
return childPosition - 1;
}
/// <summary>
/// Traverse the tree, building up the color palette
/// </summary>
/// <param name="palette">The palette</param>
/// <param name="currentPaletteIndex">The current palette index</param>
public void ConstructPalette(ArrayList palette, ref int currentPaletteIndex)
{
if (this.leaf)
{
// Consume the next palette index
this.paletteIndex = currentPaletteIndex++;
// And set the color of the palette entry
palette.Add(Color.FromArgb(this.red / this.pixelCount, this.green / this.pixelCount, this.blue / this.pixelCount));
}
else
{
// Loop through children looking for leaves
for (int index = 0; index < 8; index++)
{
if (null != this.children[index])
{
this.children[index].ConstructPalette(palette, ref currentPaletteIndex);
}
}
}
}
/// <summary>
/// Return the palette index for the passed color.
/// </summary>
/// <param name="pixel">
/// The pixel.
/// </param>
/// <param name="level">
/// The level.
/// </param>
/// <returns>
/// The palette index for the passed color.
/// </returns>
public int GetPaletteIndex(Color32 pixel, int level)
{
int currentPaletteIndex = this.paletteIndex;
if (!this.leaf)
{
int shift = 7 - level;
int index = ((pixel.Red & mask[level]) >> (shift - 2)) |
((pixel.Green & mask[level]) >> (shift - 1)) |
((pixel.Blue & mask[level]) >> shift);
if (null != this.children[index])
{
currentPaletteIndex = this.children[index].GetPaletteIndex(pixel, level + 1);
}
else
{
throw new Exception("Didn't expect this!");
}
}
return currentPaletteIndex;
}
/// <summary>
/// Increment the pixel count and add to the color information
/// </summary>
/// <param name="pixel">
/// The pixel.
/// </param>
public void Increment(Color32 pixel)
{
this.pixelCount++;
this.red += pixel.Red;
this.green += pixel.Green;
this.blue += pixel.Blue;
}
#endregion
}
}
}
}

315
src/ImageProcessor/Imaging/Quantizer.cs

@ -1,315 +0,0 @@
// -----------------------------------------------------------------------
// <copyright file="Quantizer.cs" company="James South">
// Copyright (c) James South.
// Licensed under the Apache License, Version 2.0.
// </copyright>
// -----------------------------------------------------------------------
namespace ImageProcessor.Imaging
{
#region Using
using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.Runtime.InteropServices;
#endregion
/// <summary>
/// Encapsulates methods to calculate the color palette of an image.
/// </summary>
internal abstract class Quantizer
{
#region Fields
/// <summary>
/// The flag used to indicate whether a single pass or two passes are needed for quantization.
/// </summary>
private readonly bool singlePass;
/// <summary>
/// The size in bytes of the 32 bpp Colour structure.
/// </summary>
private readonly int pixelSize;
#endregion
/// <summary>
/// Initializes a new instance of the <see cref="T:ImageProcessor.Imaging.Quantizer">Quantizer</see> class.
/// </summary>
/// <param name="singlePass">
/// If set to <see langword="true"/>, then the quantizer will loop through the source pixels once;
/// otherwise, <see langword="false"/>.
/// </param>
protected Quantizer(bool singlePass)
{
this.singlePass = singlePass;
this.pixelSize = Marshal.SizeOf(typeof(Color32));
}
/// <summary>
/// Quantizes the given <see cref="T:System.Drawing.Image">Image</see> and returns the resulting output
/// <see cref="T:System.Drawing.Bitmap">Bitmap.</see>
/// </summary>
/// <param name="source">The image to quantize</param>
/// <returns>
/// A quantized <see cref="T:System.Drawing.Bitmap">Bitmap</see> version of the <see cref="T:System.Drawing.Image">Image</see>
/// </returns>
public Bitmap Quantize(Image source)
{
// Get the size of the source image
int height = source.Height;
int width = source.Width;
// And construct a rectangle from these dimensions
Rectangle bounds = new Rectangle(0, 0, width, height);
// First off take a 32bpp copy of the image
using (Bitmap copy = new Bitmap(width, height, PixelFormat.Format32bppArgb))
{
Bitmap output = null;
// Define a pointer to the bitmap data
BitmapData sourceData = null;
try
{
// And construct an 8bpp version
output = new Bitmap(width, height, PixelFormat.Format8bppIndexed);
// Now lock the bitmap into memory
using (Graphics graphics = Graphics.FromImage(copy))
{
graphics.PageUnit = GraphicsUnit.Pixel;
// Draw the source image onto the copy bitmap,
// which will effect a widening as appropriate.
graphics.DrawImage(source, bounds);
}
// Get the source image bits and lock into memory
sourceData = copy.LockBits(bounds, ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
// Call the FirstPass function if not a single pass algorithm.
// For something like an octree quantizer, this will run through
// all image pixels, build a data structure, and create a palette.
if (!this.singlePass)
{
this.FirstPass(sourceData, width, height);
}
// Then set the colour palette on the output bitmap. I'm passing in the current palette
// as there's no way to construct a new, empty palette.
output.Palette = this.GetPalette(output.Palette);
// Then call the second pass which actually does the conversion
this.SecondPass(sourceData, output, width, height, bounds);
}
catch
{
if (output != null)
{
output.Dispose();
}
}
finally
{
// Ensure that the bits are unlocked
copy.UnlockBits(sourceData);
}
// Last but not least, return the output bitmap
return output;
}
}
/// <summary>
/// Execute the first pass through the pixels in the image
/// </summary>
/// <param name="sourceData">The source data</param>
/// <param name="width">The width in pixels of the image</param>
/// <param name="height">The height in pixels of the image</param>
protected virtual void FirstPass(BitmapData sourceData, int width, int height)
{
// Define the source data pointers. The source row is a byte to
// keep addition of the stride value easier (as this is in bytes)
IntPtr sourceRow = sourceData.Scan0;
// Loop through each row
for (int row = 0; row < height; row++)
{
// Set the source pixel to the first pixel in this row
IntPtr sourcePixel = sourceRow;
// And loop through each column
for (int col = 0; col < width; col++)
{
this.InitialQuantizePixel(new Color32(sourcePixel));
sourcePixel = (IntPtr)((int)sourcePixel + this.pixelSize);
}
// Now I have the pixel, call the FirstPassQuantize function.
// Add the stride to the source row
sourceRow = (IntPtr)((long)sourceRow + sourceData.Stride);
}
}
/// <summary>
/// Execute a second pass through the bitmap
/// </summary>
/// <param name="sourceData">The source bitmap, locked into memory</param>
/// <param name="output">The output bitmap</param>
/// <param name="width">The width in pixels of the image</param>
/// <param name="height">The height in pixels of the image</param>
/// <param name="bounds">The bounding rectangle</param>
protected virtual void SecondPass(BitmapData sourceData, Bitmap output, int width, int height, Rectangle bounds)
{
BitmapData outputData = null;
try
{
// Lock the output bitmap into memory
outputData = output.LockBits(bounds, ImageLockMode.WriteOnly, PixelFormat.Format8bppIndexed);
// Define the source data pointers. The source row is a byte to
// keep addition of the stride value easier (as this is in bytes)
IntPtr sourceRow = sourceData.Scan0;
IntPtr sourcePixel = sourceRow;
IntPtr previousPixel = sourcePixel;
// Now define the destination data pointers
IntPtr destinationRow = outputData.Scan0;
IntPtr destinationPixel = destinationRow;
// And convert the first pixel, so that I have values going into the loop.
byte pixelValue = this.QuantizePixel(new Color32(sourcePixel));
// Assign the value of the first pixel
Marshal.WriteByte(destinationPixel, pixelValue);
// Loop through each row
for (int row = 0; row < height; row++)
{
// Set the source pixel to the first pixel in this row
sourcePixel = sourceRow;
// And set the destination pixel pointer to the first pixel in the row
destinationPixel = destinationRow;
// Loop through each pixel on this scan line
for (int col = 0; col < width; col++)
{
// Check if this is the same as the last pixel. If so use that value
// rather than calculating it again. This is an inexpensive optimisation.
if (Marshal.ReadByte(previousPixel) != Marshal.ReadByte(sourcePixel))
{
// Quantize the pixel
pixelValue = this.QuantizePixel(new Color32(sourcePixel));
// And setup the previous pointer
previousPixel = sourcePixel;
}
// And set the pixel in the output
Marshal.WriteByte(destinationPixel, pixelValue);
sourcePixel = (IntPtr)((long)sourcePixel + this.pixelSize);
destinationPixel = (IntPtr)((long)destinationPixel + 1);
}
// Add the stride to the source row
sourceRow = (IntPtr)((long)sourceRow + sourceData.Stride);
// And to the destination row
destinationRow = (IntPtr)((long)destinationRow + outputData.Stride);
}
}
finally
{
// Ensure that I unlock the output bits
output.UnlockBits(outputData);
}
}
/// <summary>
/// Override this to process the pixel in the first pass of the algorithm
/// </summary>
/// <param name="pixel">The pixel to quantize</param>
/// <remarks>
/// This function need only be overridden if your quantize algorithm needs two passes,
/// such as an Octree quantizer.
/// </remarks>
protected virtual void InitialQuantizePixel(Color32 pixel)
{
}
/// <summary>
/// Override this to process the pixel in the second pass of the algorithm.
/// </summary>
/// <param name="pixel">The pixel to quantize</param>
/// <returns>The quantized value.</returns>
protected abstract byte QuantizePixel(Color32 pixel);
/// <summary>
/// Retrieve the palette for the quantized image
/// </summary>
/// <param name="original">Any old palette, this is overwritten</param>
/// <returns>The new color palette</returns>
protected abstract ColorPalette GetPalette(ColorPalette original);
/// <summary>
/// Structure that defines a 32 bit color
/// </summary>
/// <remarks>
/// This structure is used to read data from a 32 bits per pixel image
/// in memory, and is ordered in this manner as this is the way that
/// the data is laid out in memory
/// </remarks>
[StructLayout(LayoutKind.Explicit)]
public struct Color32
{
/// <summary>
/// Holds the blue component of the color
/// </summary>
[FieldOffset(0)]
public byte Blue;
/// <summary>
/// Holds the green component of the color
/// </summary>
[FieldOffset(1)]
public byte Green;
/// <summary>
/// Holds the red component of the color
/// </summary>
[FieldOffset(2)]
public byte Red;
/// <summary>
/// Holds the alpha component of the color
/// </summary>
[FieldOffset(3)]
public byte Alpha;
/// <summary>
/// Permits the color32 to be treated as a 32 bit integer.
/// </summary>
[FieldOffset(0)]
public int ARGB;
/// <summary>
/// Initializes a new instance of the <see cref="T:ImageProcessor.Imaging.Quantizer.Color32">Color32</see> structure.
/// </summary>
/// <param name="sourcePixel">The pointer to the pixel.</param>
public Color32(IntPtr sourcePixel)
{
this = (Color32)Marshal.PtrToStructure(sourcePixel, typeof(Color32));
}
/// <summary>
/// Gets the color for this Color32 object
/// </summary>
public Color Color
{
get { return Color.FromArgb(this.Alpha, this.Red, this.Green, this.Blue); }
}
}
}
}

24
src/ImageProcessor/Processors/Format.cs

@ -1,9 +1,12 @@
// -----------------------------------------------------------------------
// --------------------------------------------------------------------------------------------------------------------
// <copyright file="Format.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>
// Sets the output of the image to a specific format.
// </summary>
// --------------------------------------------------------------------------------------------------------------------
namespace ImageProcessor.Processors
{
@ -22,7 +25,7 @@ namespace ImageProcessor.Processors
/// <summary>
/// The regular expression to search strings for.
/// </summary>
private static readonly Regex QueryRegex = new Regex(@"format=(jpeg|png|bmp|gif)", RegexOptions.Compiled);
private static readonly Regex QueryRegex = new Regex(@"format=(jpeg|png|png8|bmp|gif|tif)", RegexOptions.Compiled);
#region IGraphicsProcessor Members
/// <summary>
@ -110,17 +113,26 @@ namespace ImageProcessor.Processors
public Image ProcessImage(ImageFactory factory)
{
string format = this.DynamicParameter;
bool isIndexed = false;
ImageFormat imageFormat;
switch (format)
{
case "png":
imageFormat = ImageFormat.Png;
break;
case "png8":
imageFormat = ImageFormat.Png;
isIndexed = true;
break;
case "bmp":
imageFormat = ImageFormat.Bmp;
break;
case "gif":
imageFormat = ImageFormat.Gif;
isIndexed = true;
break;
case "tif":
imageFormat = ImageFormat.Tiff;
break;
default:
// Should be a jpeg.
@ -129,7 +141,7 @@ namespace ImageProcessor.Processors
}
// Set the internal property.
factory.Format(imageFormat);
factory.Format(imageFormat, isIndexed);
return factory.Image;
}

4
src/ImageProcessor/Properties/AssemblyInfo.cs

@ -32,6 +32,6 @@ using System.Security;
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
[assembly: AssemblyVersion("1.6.0.0")]
[assembly: AssemblyFileVersion("1.6.0.0")]
[assembly: AssemblyVersion("1.7.0.0")]
[assembly: AssemblyFileVersion("1.7.0.0")]

11
src/ImageProcessor/Settings.StyleCop

@ -0,0 +1,11 @@
<StyleCopSettings Version="105">
<Analyzers>
<Analyzer AnalyzerId="StyleCop.CSharp.DocumentationRules">
<AnalyzerSettings>
<StringProperty Name="CompanyName">James South</StringProperty>
<StringProperty Name="Copyright">Copyright (c) James South.
Licensed under the Apache License, Version 2.0.</StringProperty>
</AnalyzerSettings>
</Analyzer>
</Analyzers>
</StyleCopSettings>

BIN
src/Nuget/ImageProcessor.1.3.0.0.nupkg

Binary file not shown.

BIN
src/Nuget/ImageProcessor.1.4.0.0.nupkg

Binary file not shown.

BIN
src/Nuget/ImageProcessor.1.4.1.0.nupkg

Binary file not shown.

BIN
src/Nuget/ImageProcessor.1.4.2.0.nupkg

Binary file not shown.

BIN
src/Nuget/ImageProcessor.1.5.0.0.nupkg

Binary file not shown.

BIN
src/Nuget/ImageProcessor.1.6.0.0.nupkg

Binary file not shown.

BIN
src/Nuget/ImageProcessor.1.7.0.0.nupkg

Binary file not shown.

BIN
src/Nuget/ImageProcessor.Web.1.3.0.0.nupkg

Binary file not shown.

BIN
src/Nuget/ImageProcessor.Web.2.0.0.0.nupkg

Binary file not shown.

BIN
src/Nuget/ImageProcessor.Web.2.0.1.0.nupkg

Binary file not shown.

BIN
src/Nuget/ImageProcessor.Web.2.1.0.0.nupkg

Binary file not shown.

BIN
src/Nuget/ImageProcessor.Web.2.1.0.1.nupkg

Binary file not shown.

BIN
src/Nuget/ImageProcessor.Web.2.1.0.2.nupkg

Binary file not shown.

BIN
src/Nuget/ImageProcessor.Web.2.1.0.3.nupkg

Binary file not shown.

1
src/Nuget/ImageProcessor.Web.2.1.0.4.nupkg.REMOVED.git-id

@ -1 +0,0 @@
eaff612b7db9e40f185c91161fd9c977faec69bb

1
src/Nuget/ImageProcessor.Web.2.1.1.0.nupkg.REMOVED.git-id

@ -1 +0,0 @@
2af35ccdf0476cbe432b2440be45ffd0f6c414f4

1
src/Nuget/ImageProcessor.Web.2.1.2.0.nupkg.REMOVED.git-id

@ -1 +0,0 @@
1ac41e14e3ae5f8ac9b06bcfbbacc6c4a9841863

1
src/Nuget/ImageProcessor.Web.2.2.0.0.nupkg.REMOVED.git-id

@ -1 +0,0 @@
13403db94dce99fd4e73114b3334d4ef0c2b4ae5

1
src/Nuget/ImageProcessor.Web.2.2.0.1.nupkg.REMOVED.git-id

@ -1 +0,0 @@
8a3fd4491298fec4626034f03e534caac7f22941

43
src/Nuget/ImageProcessor.Web.2.2.0.1.nuspec

@ -1,43 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<package xmlns="http://schemas.microsoft.com/packaging/2011/08/nuspec.xsd">
<metadata>
<id>ImageProcessor.Web</id>
<version>2.2.0.1</version>
<title>ImageProcessor.Web</title>
<authors>James South</authors>
<owners>James South</owners>
<projectUrl>http://jimbobsquarepants.github.com/ImageProcessor/</projectUrl>
<requireLicenseAcceptance>false</requireLicenseAcceptance>
<description>ImageProcessor.Web adds a configurable HttpModule to your website which allows on-the-fly processing of image files. The module also comes with a file and browser based cache that can handle up to 12,960,000 images increasing your processing output and saving precious server memory.
Methods include; Resize, Rotate, Flip, Crop, Watermark, Filter, Saturation, Brightness, Contrast, Quality, Format, Vignette, and Transparency.
This package also requires Microsoft.Bcl.Async -pre on .NET 4.0 which will be added in the background on install if applicable.
If you use ImageProcessor please get in touch via my twitter @james_m_south
Feedback is always welcome.</description>
<summary>An extension to ImageProcessor that allows on-the-fly processing of image files in an ASP.NET website</summary>
<releaseNotes>Fixed cache bug which caused unneccessary processing of images.
If upgrading from &lt; 2.2.0.0 You will have to delete your cache if upgrading to this version as the database differs.</releaseNotes>
<copyright>James South</copyright>
<language>en-GB</language>
<tags>Image, Imaging, ASP, Performance, Processing, HttpModule, Cache, Resize, Rotate, Flip, Crop, Filter, Effects, Quality, Watermark, Alpha, Vignette, Saturation, Brightness, Contrast, Gif, Jpeg, Bitmap, Png, Fluent</tags>
<dependencies>
<dependency id="ImageProcessor" version="1.5.0.0" />
<dependency id="Csharp-Sqlite" version="3.7.7.1" />
</dependencies>
</metadata>
<files>
<file src="content\net40\web.config.transform" target="content\net40\web.config.transform" />
<file src="content\net45\web.config.transform" target="content\net45\web.config.transform" />
<file src="..\ImageProcessor.Web\bin\Release\ImageProcessor.Web.dll" target="lib\net40\ImageProcessor.Web.dll" />
<file src="lib\net40\System.Runtime.dll" target="lib\net40\System.Runtime.dll" />
<file src="lib\net40\System.Threading.Tasks.dll" target="lib\net40\System.Threading.Tasks.dll" />
<file src="..\ImageProcessor.Web\bin\Release\ImageProcessor.Web.dll" target="lib\net45\ImageProcessor.Web.dll" />
<file src="tools\net40\install.ps1" target="tools\net40\install.ps1" />
<file src="tools\net45\install.ps1" target="tools\net45\install.ps1" />
</files>
</package>

1
src/Nuget/ImageProcessor.Web.2.2.1.0.nupkg.REMOVED.git-id

@ -1 +0,0 @@
46b009d93ab9f1ea75f1ea1efb0073b3d369d3e5

1
src/Nuget/ImageProcessor.Web.2.2.2.0.nupkg.REMOVED.git-id

@ -1 +0,0 @@
50dc5dc47c964ccc80bb8abb22650a579ae796c3

1
src/Nuget/ImageProcessor.Web.2.2.3.0.nupkg.REMOVED.git-id

@ -1 +0,0 @@
9142f8cdad57d5c52d8721112c18a8d26c6f9817

1
src/Nuget/ImageProcessor.Web.2.2.3.1.nupkg.REMOVED.git-id

@ -1 +0,0 @@
24114542de37d7b4463b56749e64e34b0d43a9cc

1
src/Nuget/ImageProcessor.Web.2.2.3.2.nupkg.REMOVED.git-id

@ -1 +0,0 @@
3de0aa82f042cfdda2764554fb34e686b401df85

1
src/Nuget/ImageProcessor.Web.2.3.0.0.nupkg.REMOVED.git-id

@ -0,0 +1 @@
8b33cb0b4f13802b62d2511239e212680ad67158

BIN
src/Nuget/imageprocessor.128.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.1 KiB

After

Width:  |  Height:  |  Size: 6.5 KiB

37
src/Packages.dgml

@ -0,0 +1,37 @@
<?xml version="1.0" encoding="utf-8"?>
<DirectedGraph GraphDirection="LeftToRight" xmlns="http://schemas.microsoft.com/vs/2009/dgml">
<Nodes>
<Node Id="ImageProcessor.Web_NET45" Label="ImageProcessor.Web_NET45" Category="Project" />
<Node Id="Csharp-Sqlite 3.7.7.1" Label="Csharp-Sqlite 3.7.7.1" Category="Package" />
<Node Id="sqlite-net 1.0.7" Label="sqlite-net 1.0.7" Category="Package" />
<Node Id="ImageProcessor.Web" Label="ImageProcessor.Web" Category="Project" />
<Node Id="Csharp-Sqlite 3.7.7.1" Label="Csharp-Sqlite 3.7.7.1" Category="Package" />
<Node Id="Microsoft.Bcl 1.0.19" Label="Microsoft.Bcl 1.0.19" Category="Package" />
<Node Id="Microsoft.Bcl.Async 1.0.16" Label="Microsoft.Bcl.Async 1.0.16" Category="Package" />
<Node Id="Microsoft.Bcl.Build 1.0.6" Label="Microsoft.Bcl.Build 1.0.6" Category="Package" />
<Node Id="sqlite-net 1.0.7" Label="sqlite-net 1.0.7" Category="Package" />
</Nodes>
<Links>
<Link Source="ImageProcessor.Web_NET45" Target="Csharp-Sqlite 3.7.7.1" Category="Installed Package" />
<Link Source="ImageProcessor.Web_NET45" Target="sqlite-net 1.0.7" Category="Installed Package" />
<Link Source="Microsoft.Bcl 1.0.19" Target="Microsoft.Bcl.Build 1.0.6" Category="Package Dependency" />
<Link Source="Microsoft.Bcl.Async 1.0.16" Target="Microsoft.Bcl 1.0.19" Category="Package Dependency" />
<Link Source="ImageProcessor.Web" Target="Csharp-Sqlite 3.7.7.1" Category="Installed Package" />
<Link Source="ImageProcessor.Web" Target="Microsoft.Bcl.Async 1.0.16" Category="Installed Package" />
<Link Source="ImageProcessor.Web" Target="sqlite-net 1.0.7" Category="Installed Package" />
</Links>
<Categories>
<Category Id="Project" />
<Category Id="Package" />
</Categories>
<Styles>
<Style TargetType="Node" GroupLabel="Project" ValueLabel="True">
<Condition Expression="HasCategory('Project')" />
<Setter Property="Background" Value="Blue" />
</Style>
<Style TargetType="Link" GroupLabel="Package Dependency" ValueLabel="True">
<Condition Expression="HasCategory('Package Dependency')" />
<Setter Property="Background" Value="Yellow" />
</Style>
</Styles>
</DirectedGraph>

212
src/TestWebsites/NET4/Content/flexo.css

@ -1,212 +0,0 @@
/* ==|== Flexo 2.0.1 =============================================================
Author: James South
twitter : http://twitter.com/James_M_South
github : https://github.com/JimBobSquarePants/Flexo
Copyright (c) James South.
Licensed under the Apache License v2.0.
============================================================================== */
/* =============================================================================
Base
========================================================================== */
html {
/*Use the iOS devices hardware accelerator to provide native scrolling*/
-webkit-overflow-scrolling: touch;
/* Prevents iOS text size adjust after orientation change, without disabling user zoom. */
-webkit-text-size-adjust: 100%;
-ms-text-size-adjust: 100%;
}
html, body {
height: 100%;
margin: 0;
position: relative;
}
.page {
min-height: 100%;
position: relative;
margin-bottom: -150px;
padding-bottom: 150px;
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
-ms-box-sizing: border-box;
box-sizing: border-box;
}
.page.no-box {
padding-bottom: 0;
}
.page-push, .page-footer {
height: 150px;
}
.page-footer {
margin: 0 auto;
position: relative;
z-index: 1;
}
.container {
margin: 0 auto;
/* Manages width in a single place */
width: 95%;
max-width: 1140px;
}
/* Contains floats so all columns can float left*/
.container:before,
.container:after,
.row:before,
.row:after {
content: "";
display: table;
}
.container:after,
.row:after {
clear: both;
}
/* =============================================================================
Grid
========================================================================== */
[class*="clmn"] {
display: block;
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
-ms-box-sizing: border-box;
box-sizing: border-box;
min-height: 1px;
float: left;
}
/* ==|== media queries ===================================================
Portrait phone viewport to Landscape phone < 767px
========================================================================== */
@media screen and (max-width: 767px) {
body:not(.flexo-fixed) [class*="clmn"],
body:not(.flexo-fixed) [class*="offset"] {
float: none;
width: 100%;
margin-left: 0!important;
}
}
/* =============================================================================
Grid
========================================================================== */
[class*="clmn"] + [class*="clmn"]:not([class*="offset"]) {
margin-left: 2%;
}
/* Columns */
/* Full width calculated with margins */
.clmn1 {
width: 100%;
}
/* 2 column */
.clmn2 {
width: 49%;
}
/* 3 column */
.clmn3 {
width: 32%;
}
/* 4 column */
.clmn4 {
width: 23.5%;
}
/* 5 column */
.clmn5 {
width: 18.4%;
}
/* Fillers*/
/* 2/3 column */
.clmn2-3 {
width: 66%;
}
/* 3/4 column */
.clmn3-4 {
width: 74.5%;
}
/* 2/5 column */
.clmn2-5 {
width: 38.8%;
}
/* 3/5 column */
.clmn3-5 {
width: 59.2%;
}
/* 4/5 column */
.clmn4-5 {
width: 79.6%;
}
/* Offsetting columns */
/*offset 1/2*/
.offset2 {
margin-left: 51%;
}
/*offset 1/3 */
.offset3 {
margin-left: 34%;
}
/*offset 1/4 */
.offset4 {
margin-left: 25.5%;
}
/*offset 1/5 */
.offset5 {
margin-left: 20.4%;
}
/* offset 2/3 */
.offset2-3 {
margin-left: 68%;
}
/* offset 3/4 */
.offset3-4 {
margin-left: 76.5%;
}
/* offset 2/5 */
.offset2-5 {
margin-left: 40.8%;
}
/* offset 3/5 */
.offset3-5 {
margin-left: 61.2%;
}
/* offset 4/5 */
.offset4-5 {
margin-left: 81.6%;
}
/* =============================================================================
Fixed Grid
========================================================================== */
.flexo-fixed .container {
/* Manages width in a single place */
width: 1140px;
}

3
src/TestWebsites/NET4/Content/responsive-legacy.min.css

File diff suppressed because one or more lines are too long

3
src/TestWebsites/NET4/Content/responsive.min.css

File diff suppressed because one or more lines are too long

64
src/TestWebsites/NET4/Content/style.css

@ -1,64 +0,0 @@
body {
font-family: "Segoe UI",Tahoma,Arial,Verdana,Sans-Serif;
color: #333;
}
h1, h2, h3 {
font-family: "Segoe UI Light", "Segoe UI",Tahoma,Arial,Verdana,Sans-Serif;
font-weight: 400;
}
h1 {
margin-top: 0;
font-size: 3em;
}
section section {
padding-bottom: 1em;
margin-bottom: 2em;
}
section section:nth-child(2n) {
background-color: #f3f3f3;
}
.no-bullets {
padding-left: 0;
}
.no-bullets > li {
list-style: none;
float: left;
margin-right: .5em;
}
/*
* Clearfix: contain floats
*
* For modern browsers
* 1. The space content is one way to avoid an Opera bug when the
* `contenteditable` attribute is included anywhere else in the document.
* Otherwise it causes space to appear at the top and bottom of elements
* that receive the `clearfix` class.
* 2. The use of `table` rather than `block` is only necessary if using
* `:before` to contain the top-margins of child elements.
*/
.clearfix:before,
.clearfix:after {
content: " "; /* 1 */
display: table; /* 2 */
}
.clearfix:after {
clear: both;
}
/*
* For IE 6/7 only
* Include this rule to trigger hasLayout and contain floats.
*/
.clearfix {
*zoom: 1;
}

147
src/TestWebsites/NET4/Controllers/HomeController.cs

@ -6,156 +6,15 @@ using System.Web.Mvc;
namespace Test.Controllers
{
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Threading.Tasks;
using System.Web.Hosting;
using ImageProcessor;
using ImageProcessor.Helpers.Extensions;
using ImageProcessor.Imaging;
//using ImageProcessor.Web.Caching;
public class HomeController : Controller
{
public ActionResult Index()
{
ViewBag.Message = "ImageProcessor test website";
return View();
}
public ActionResult Upload()
{
return View();
}
//
// GET: /Home/
[HttpPost]
public ActionResult Upload(HttpPostedFileBase file)
public ActionResult Index()
{
Stream upload = file.InputStream;
int quality = 70;
ImageFormat format = ImageFormat.Jpeg;
Size size460 = new Size(460, 0);
Size size320 = new Size(320, 0);
Size size240 = new Size(240, 0);
// Make sure the directory exists as Image.Save will not work without an existing directory.
string outputPath = HostingEnvironment.MapPath("~/Resized");
if (outputPath != null)
{
DirectoryInfo directoryInfo = new DirectoryInfo(outputPath);
if (!directoryInfo.Exists)
{
directoryInfo.Create();
}
// Make the three file paths
string outputfile1 = Path.Combine(outputPath, "460px_" + file.FileName);
string outputfile2 = Path.Combine(outputPath, "320px_" + file.FileName);
string outputfile3 = Path.Combine(outputPath, "240px_" + file.FileName);
using (MemoryStream inStream = new MemoryStream())
{
// Copy the stream across.
upload.CopyTo(inStream);
using (ImageFactory imageFactory = new ImageFactory())
{
// Load, resize, set the format and quality and save an image.
imageFactory.Load(inStream)
.Format(format)
.Quality(quality)
.Resize(size460)
.Save(outputfile1)
.Reset()
.Format(format)
.Quality(quality)
.Resize(size320)
.Save(outputfile2)
.Reset()
.Format(format)
.Quality(quality)
.Resize(size240)
.Save(outputfile3);
}
}
}
return View();
}
public ActionResult About()
{
List<string> images = new List<string>();
const string Path = "/images/";
string folder = HostingEnvironment.MapPath(Path);
if (folder != null)
{
DirectoryInfo directoryInfo = new DirectoryInfo(folder);
if (directoryInfo.Exists)
{
// Get all the files in the cache ordered by LastAccessTime - oldest first.
List<FileInfo> fileInfos = directoryInfo.EnumerateFiles("*", SearchOption.AllDirectories).OrderBy(x => x.LastAccessTime).ToList();
int counter = fileInfos.Count;
Parallel.ForEach(
fileInfos,
fileInfo => images.Add(Path + fileInfo.Name));
}
}
return View(images);
}
public ActionResult Responsive()
{
return this.View();
}
public ActionResult Collisions()
{
DateTime start = DateTime.Now;
List<double> collisions = new List<double>();
const int Iterations = 1;
const int Maxitems = 3600000;
for (int i = 0; i < Iterations; i++)
{
List<string> paths = new List<string>();
for (int j = 0; j < Maxitems; j++)
{
string path = Path.GetRandomFileName().ToMD5Fingerprint();
path = string.Format("/{0}/{1}/{2}", path.Substring(0, 1), path.Substring(31, 1), path.Substring(0, 8));
paths.Add(path);
}
int count = paths.Distinct().Count();
double collisionRate = ((Maxitems - count) * 100D) / Maxitems;
collisions.Add(collisionRate);
}
double averageCollisionRate = collisions.Average();
TimeSpan timeSpan = DateTime.Now - start;
ViewBag.Collision = averageCollisionRate;
return this.View(timeSpan);
}
}
}

BIN
src/TestWebsites/NET4/Resized/240px_228406_276791782435436_815038966_n.jpg

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

BIN
src/TestWebsites/NET4/Resized/240px_MSwanson - Wide Large - Rock 02.jpg

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

BIN
src/TestWebsites/NET4/Resized/240px_Neck2-1.jpg

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

BIN
src/TestWebsites/NET4/Resized/320px_228406_276791782435436_815038966_n.jpg

Binary file not shown.

Before

Width:  |  Height:  |  Size: 28 KiB

BIN
src/TestWebsites/NET4/Resized/320px_MSwanson - Wide Large - Rock 02.jpg

Binary file not shown.

Before

Width:  |  Height:  |  Size: 27 KiB

BIN
src/TestWebsites/NET4/Resized/320px_Neck2-1.jpg

Binary file not shown.

Before

Width:  |  Height:  |  Size: 39 KiB

BIN
src/TestWebsites/NET4/Resized/460px_228406_276791782435436_815038966_n.jpg

Binary file not shown.

Before

Width:  |  Height:  |  Size: 56 KiB

BIN
src/TestWebsites/NET4/Resized/460px_MSwanson - Wide Large - Rock 02.jpg

Binary file not shown.

Before

Width:  |  Height:  |  Size: 28 KiB

BIN
src/TestWebsites/NET4/Resized/460px_Neck2-1.jpg

Binary file not shown.

Before

Width:  |  Height:  |  Size: 40 KiB

17
src/TestWebsites/NET4/Test_Website.csproj

@ -84,8 +84,8 @@
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
<Content Include="Content\flexo.css" />
<Content Include="Content\style.css" />
<Content Include="Content\responsive-legacy.min.css" />
<Content Include="Content\responsive.min.css" />
<Content Include="Global.asax" />
<Content Include="Images\1182076_e8c402e938_z.jpg" />
<Content Include="Images\Desert.jpg" />
@ -110,9 +110,6 @@
<DependentUpon>Web.config</DependentUpon>
</Content>
<Content Include="Views\_ViewStart.cshtml" />
<Content Include="Views\Home\About.cshtml" />
<Content Include="Views\Home\Index.cshtml" />
<Content Include="Views\Shared\Error.cshtml" />
<Content Include="Views\Shared\_Layout.cshtml" />
<Content Include="Views\Web.config" />
</ItemGroup>
@ -121,7 +118,7 @@
<Folder Include="Models\" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\ImageProcessor.Web\ImageProcessor.Web.csproj">
<ProjectReference Include="..\..\ImageProcessor.Web\NET4\ImageProcessor.Web.csproj">
<Project>{4f7050f2-465f-4e10-8db2-2fb97ac6aa43}</Project>
<Name>ImageProcessor.Web</Name>
</ProjectReference>
@ -131,13 +128,7 @@
</ProjectReference>
</ItemGroup>
<ItemGroup>
<Content Include="Views\Home\Responsive.cshtml" />
</ItemGroup>
<ItemGroup>
<Content Include="Views\Home\Collisions.cshtml" />
</ItemGroup>
<ItemGroup>
<Content Include="Views\Home\Upload.cshtml" />
<Content Include="Views\Home\Index.cshtml" />
</ItemGroup>
<PropertyGroup>
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">10.0</VisualStudioVersion>

14
src/TestWebsites/NET4/Views/Home/About.cshtml

@ -1,14 +0,0 @@
@model List<string>
@{
ViewBag.Title = "About Us";
}
<h2>About</h2>
<p>
@foreach(string image in Model)
{
string path = image + "?width=150";
<img src="@path" alt="@image"/>
}
</p>

20
src/TestWebsites/NET4/Views/Home/Collisions.cshtml

@ -1,20 +0,0 @@
@model TimeSpan
@{
Layout = null;
double s = Model.TotalMilliseconds;
}
<!DOCTYPE html>
<html>
<head>
<title>@s</title>
</head>
<body>
<div>
Speed In Milliseconds: @s<br/>
Collision Rate: @ViewBag.Collision%
</div>
</body>
</html>

457
src/TestWebsites/NET4/Views/Home/Index.cshtml

@ -2,115 +2,114 @@
ViewBag.Title = "Home Page";
}
<article>
<h1 class="container">Jpg</h1>
<h1>Jpg</h1>
<section>
<div class="container">
<div class="clmn2">
<div class="row">
<div class="column-6">
<h2>Resized</h2>
<img src="/images/Penguins.jpg?width=300" />
<h3>Foreign language test.</h3>
<img src="/images/udendørs.jpg?width=300" />
</div>
<div class="clmn2">
<div class="column-6">
<h2>Cropped </h2>
<img src="/images/Penguins.jpg?crop=0-0-300-225" />
</div>
</div>
</section>
<section>
<div class="container">
<h2>Filter</h2>
<ul class="no-bullets clearfix">
<li>
<h3>blackwhite</h3>
<img src="/images/Penguins.jpg?width=300&filter=blackwhite" />
</li>
<li>
<h3>comic</h3>
<img src="/images/Penguins.jpg?width=300&filter=comic" />
</li>
<li>
<h3>lomograph</h3>
<img src="/images/Penguins.jpg?width=300&filter=lomograph" />
</li>
<li>
<h3>greyscale</h3>
<img src="/images/Penguins.jpg?width=300&filter=greyscale" />
</li>
<li>
<h3>polaroid</h3>
<img src="/images/Penguins.jpg?width=300&filter=polaroid" />
</li>
<li>
<h3>sepia</h3>
<img src="/images/Penguins.jpg?width=300&filter=sepia" />
</li>
<li>
<h3>gotham</h3>
<img src="/images/Penguins.jpg?width=300&filter=gotham" />
</li>
<li>
<h3>hisatch</h3>
<img src="/images/Penguins.jpg?width=300&filter=hisatch" />
</li>
<li>
<h3>losatch</h3>
<img src="/images/Penguins.jpg?width=300&filter=losatch" />
</li>
<li>
<h3>invert</h3>
<img src="/images/negative.png?filter=invert" />
</li>
<li>
<h3>invert</h3>
<img src="/images/negative2.png?filter=invert" />
</li>
</ul>
<h2>Filter</h2>
<div class="row">
<div class="column-6">
<h3>blackwhite</h3>
<img src="/images/Penguins.jpg?width=300&filter=blackwhite" />
</div>
<div class="column-6">
<h3>comic</h3>
<img src="/images/Penguins.jpg?width=300&filter=comic" />
</div>
</div>
<div class="row">
<div class="column-6">
<h3>lomograph</h3>
<img src="/images/Penguins.jpg?width=300&filter=lomograph" />
</div>
<div class="column-6">
<h3>greyscale</h3>
<img src="/images/Penguins.jpg?width=300&filter=greyscale" />
</div>
</div>
<div class="row">
<div class="column-6">
<h3>polaroid</h3>
<img src="/images/Penguins.jpg?width=300&filter=polaroid" />
</div>
<div class="column-6">
<h3>sepia</h3>
<img src="/images/Penguins.jpg?width=300&filter=sepia" />
</div>
</div>
<div class="row">
<div class="column-6">
<h3>gotham</h3>
<img src="/images/Penguins.jpg?width=300&filter=gotham" />
</div>
<div class="column-6">
<h3>hisatch</h3>
<img src="/images/Penguins.jpg?width=300&filter=hisatch" />
</div>
</div>
<div class="row">
<div class="column-6">
<h3>losatch</h3>
<img src="/images/Penguins.jpg?width=300&filter=losatch" />
</div>
</div>
</section>
<section>
<div class="container">
<div class="clmn2">
<div class="row">
<div class="column-6">
<h2>Watermark</h2>
<img src="/images/Penguins.jpg?width=300&watermark=text-test|color-fff|size-48|style-italic|opacity-100|position-100-100|shadow-true|font-arial" />
</div>
<div class="clmn2">
<div class="column-6">
<h2>Format</h2>
<img src="/images/Penguins.jpg?width=300&format=gif" />
</div>
</div>
</section>
<section>
<div class="container">
<div class="clmn2">
<div class="row">
<div class="column-6">
<h2>Rotate</h2>
<img src="/images/Penguins.jpg?width=300&rotate=angle-54|bgcolor-fff" />
</div>
<div class="clmn2">
<div class="column-6">
<h2>Quality</h2>
<img src="/images/Penguins.jpg?width=300&quality=5" />
</div>
</div>
</section>
<section>
<div class="container">
<div class="clmn2">
<div class="row">
<div class="column-6">
<h2>Alpha</h2>
<img src="/images/Penguins.jpg?width=300&format=png&alpha=50" />
</div>
<div class="clmn2">
<div class="column-6">
<h2>Remote</h2>
<img src="/remote.axd?http://images.mymovies.net/images/film/cin/500x377/fid11707.jpg?width=300" />
@*<img src="/remote.axd?http://www.theworldeffect.com/images/6a00e54fa8abf78833011570697305970b-800wi.jpg?width=300" />*@
</div>
</div>
</section>
<section>
<div class="container">
<div class="clmn2">
<div class="row">
<div class="column-6">
<h2>Flip - horizontal</h2>
<img src="/images/Penguins.jpg?width=300&flip=horizontal" />
</div>
<div class="clmn2">
<div class="column-6">
<h2>Flip - vertical</h2>
<img src="/images/Penguins.jpg?width=300&flip=vertical" />
</div>
@ -118,89 +117,95 @@
</section>
</article>
<article>
<h1 class="container">Gif</h1>
<h1>Gif</h1>
<section>
<div class="container">
<div class="clmn2">
<div class="row">
<div class="column-6">
<h2>Resized</h2>
<img src="/images/Penguins.gif?width=300" />
</div>
<div class="clmn2">
<div class="column-6">
<h2>Cropped </h2>
<img src="/images/Penguins.gif?crop=0-0-300-225" />
</div>
</div>
</section>
<section>
<div class="container">
<h2>Filter</h2>
<ul class="no-bullets clearfix">
<li>
<h3>blackwhite</h3>
<img src="/images/Penguins.gif?width=300&filter=blackwhite" />
</li>
<li>
<h3>comic</h3>
<img src="/images/Penguins.gif?width=300&filter=comic" />
</li>
<li>
<h3>lomograph</h3>
<img src="/images/Penguins.gif?width=300&filter=lomograph" />
</li>
<li>
<h3>greyscale</h3>
<img src="/images/Penguins.gif?width=300&filter=greyscale" />
</li>
<li>
<h3>polaroid</h3>
<img src="/images/Penguins.gif?width=300&filter=polaroid" />
</li>
<li>
<h3>sepia</h3>
<img src="/images/Penguins.gif?width=300&filter=sepia" />
</li>
<li>
<h3>gotham</h3>
<img src="/images/Penguins.gif?width=300&filter=gotham" />
</li>
<li>
<h3>hisatch</h3>
<img src="/images/Penguins.gif?width=300&filter=hisatch" />
</li>
<li>
<h3>losatch</h3>
<img src="/images/Penguins.gif?width=300&filter=losatch" />
</li>
</ul>
<h2>Filter</h2>
<div class="row">
<div class="column-6">
<h3>blackwhite</h3>
<img src="/images/Penguins.gif?width=300&filter=blackwhite" />
</div>
<div class="column-6">
<h3>comic</h3>
<img src="/images/Penguins.gif?width=300&filter=comic" />
</div>
</div>
<div class="row">
<div class="column-6">
<h3>lomograph</h3>
<img src="/images/Penguins.gif?width=300&filter=lomograph" />
</div>
<div class="column-6">
<h3>greyscale</h3>
<img src="/images/Penguins.gif?width=300&filter=greyscale" />
</div>
</div>
<div class="row">
<div class="column-6">
<h3>polaroid</h3>
<img src="/images/Penguins.gif?width=300&filter=polaroid" />
</div>
<div class="column-6">
<h3>sepia</h3>
<img src="/images/Penguins.gif?width=300&filter=sepia" />
</div>
</div>
<div class="row">
<div class="column-6">
<h3>gotham</h3>
<img src="/images/Penguins.gif?width=300&filter=gotham" />
</div>
<div class="column-6">
<h3>hisatch</h3>
<img src="/images/Penguins.gif?width=300&filter=hisatch" />
</div>
</div>
<div class="row">
<div class="column-6">
<h3>losatch</h3>
<img src="/images/Penguins.gif?width=300&filter=losatch" />
</div>
</div>
</section>
<section>
<div class="container">
<div class="clmn2">
<div class="row">
<div class="column-6">
<h2>Watermark</h2>
<img src="/images/Penguins.gif?width=300&watermark=text-test|color-fff|size-48|style-italic|opacity-100|position-100-100|shadow-true|font-arial" />
</div>
<div class="clmn2">
<div class="column-6">
<h2>Format</h2>
<img src="/images/Penguins.gif?width=300&format=png" />
</div>
</div>
</section>
<section>
<div class="container">
<div class="clmn2">
<div class="row">
<div class="column-6">
<h2>Rotate</h2>
<img src="/images/Penguins.gif?width=300&rotate=angle-54|bgcolor-fff" />
</div>
<div class="clmn2">
<div class="column-6">
<h2>Quality</h2>
<img src="/images/Penguins.gif?width=300&quality=5" />
</div>
</div>
</section>
<section>
<div class="container">
<div class="clmn2">
<div class="row">
<div class="column-6">
<h2>Alpha</h2>
<img src="/images/Penguins.gif?width=300&alpha=50" />
</div>
@ -208,89 +213,95 @@
</section>
</article>
<article>
<h1 class="container">Png</h1>
<h1>Png</h1>
<section>
<div class="container">
<div class="clmn2">
<div class="row">
<div class="column-6">
<h2>Resized</h2>
<img src="/images/Penguins.png?width=300" />
</div>
<div class="clmn2">
<div class="column-6">
<h2>Cropped </h2>
<img src="/images/Penguins.png?crop=0-0-300-225" />
</div>
</div>
</section>
<section>
<div class="container">
<h2>Filter</h2>
<ul class="no-bullets clearfix">
<li>
<h3>blackwhite</h3>
<img src="/images/Penguins.png?width=300&filter=blackwhite" />
</li>
<li>
<h3>comic</h3>
<img src="/images/Penguins.png?width=300&filter=comic" />
</li>
<li>
<h3>lomograph</h3>
<img src="/images/Penguins.png?width=300&filter=lomograph" />
</li>
<li>
<h3>greyscale</h3>
<img src="/images/Penguins.png?width=300&filter=greyscale" />
</li>
<li>
<h3>polaroid</h3>
<img src="/images/Penguins.png?width=300&filter=polaroid" />
</li>
<li>
<h3>sepia</h3>
<img src="/images/Penguins.png?width=300&filter=sepia" />
</li>
<li>
<h3>gotham</h3>
<img src="/images/Penguins.png?width=300&filter=gotham" />
</li>
<li>
<h3>hisatch</h3>
<img src="/images/Penguins.png?width=300&filter=hisatch" />
</li>
<li>
<h3>losatch</h3>
<img src="/images/Penguins.png?width=300&filter=losatch" />
</li>
</ul>
<h2>Filter</h2>
<div class="row">
<div class="column-6">
<h3>blackwhite</h3>
<img src="/images/Penguins.png?width=300&filter=blackwhite" />
</div>
<div class="column-6">
<h3>comic</h3>
<img src="/images/Penguins.png?width=300&filter=comic" />
</div>
</div>
<div class="row">
<div class="column-6">
<h3>lomograph</h3>
<img src="/images/Penguins.png?width=300&filter=lomograph" />
</div>
<div class="column-6">
<h3>greyscale</h3>
<img src="/images/Penguins.png?width=300&filter=greyscale" />
</div>
</div>
<div class="row">
<div class="column-6">
<h3>polaroid</h3>
<img src="/images/Penguins.png?width=300&filter=polaroid" />
</div>
<div class="column-6">
<h3>sepia</h3>
<img src="/images/Penguins.png?width=300&filter=sepia" />
</div>
</div>
<div class="row">
<div class="column-6">
<h3>gotham</h3>
<img src="/images/Penguins.png?width=300&filter=gotham" />
</div>
<div class="column-6">
<h3>hisatch</h3>
<img src="/images/Penguins.png?width=300&filter=hisatch" />
</div>
</div>
<div class="row">
<div class="column-6">
<h3>losatch</h3>
<img src="/images/Penguins.png?width=300&filter=losatch" />
</div>
</div>
</section>
<section>
<div class="container">
<div class="clmn2">
<div class="row">
<div class="column-6">
<h2>Watermark</h2>
<img src="/images/Penguins.png?width=300&watermark=text-test|color-fff|size-48|style-italic|opacity-100|position-100-100|shadow-true|font-arial" />
</div>
<div class="clmn2">
<div class="column-6">
<h2>Format</h2>
<img src="/images/Penguins.png?width=300&format=bmp" />
</div>
</div>
</section>
<section>
<div class="container">
<div class="clmn2">
<div class="row">
<div class="column-6">
<h2>Rotate</h2>
<img src="/images/Penguins.png?width=300&rotate=angle-54|bgcolor-fff" />
</div>
<div class="clmn2">
<div class="column-6">
<h2>Quality</h2>
<img src="/images/Penguins.png?width=300&quality=5" />
</div>
</div>
</section>
<section>
<div class="container">
<div class="clmn2">
<div class="row">
<div class="column-6">
<h2>Alpha</h2>
<img src="/images/Penguins.png?width=300&alpha=50" />
</div>
@ -298,89 +309,95 @@
</section>
</article>
<article>
<h1 class="container">Bmp</h1>
<h1>Bmp</h1>
<section>
<div class="container">
<div class="clmn2">
<div class="row">
<div class="column-6">
<h2>Resized</h2>
<img src="/images/Penguins.bmp?width=300" />
</div>
<div class="clmn2">
<div class="column-6">
<h2>Cropped </h2>
<img src="/images/Penguins.bmp?crop=0-0-300-225" />
</div>
</div>
</section>
<section>
<div class="container">
<h2>Filter</h2>
<ul class="no-bullets clearfix">
<li>
<h3>blackwhite</h3>
<img src="/images/Penguins.bmp?width=300&filter=blackwhite" />
</li>
<li>
<h3>comic</h3>
<img src="/images/Penguins.bmp?width=300&filter=comic" />
</li>
<li>
<h3>lomograph</h3>
<img src="/images/Penguins.bmp?width=300&filter=lomograph" />
</li>
<li>
<h3>greyscale</h3>
<img src="/images/Penguins.bmp?width=300&filter=greyscale" />
</li>
<li>
<h3>polaroid</h3>
<img src="/images/Penguins.bmp?width=300&filter=polaroid" />
</li>
<li>
<h3>sepia</h3>
<img src="/images/Penguins.bmp?width=300&filter=sepia" />
</li>
<li>
<h3>gotham</h3>
<img src="/images/Penguins.bmp?width=300&filter=gotham" />
</li>
<li>
<h3>hisatch</h3>
<img src="/images/Penguins.bmp?width=300&filter=hisatch" />
</li>
<li>
<h3>losatch</h3>
<img src="/images/Penguins.bmp?width=300&filter=losatch" />
</li>
</ul>
<h2>Filter</h2>
<div class="row">
<div class="column-6">
<h3>blackwhite</h3>
<img src="/images/Penguins.bmp?width=300&filter=blackwhite" />
</div>
<div class="column-6">
<h3>comic</h3>
<img src="/images/Penguins.bmp?width=300&filter=comic" />
</div>
</div>
<div class="row">
<div class="column-6">
<h3>lomograph</h3>
<img src="/images/Penguins.bmp?width=300&filter=lomograph" />
</div>
<div class="column-6">
<h3>greyscale</h3>
<img src="/images/Penguins.bmp?width=300&filter=greyscale" />
</div>
</div>
<div class="row">
<div class="column-6">
<h3>polaroid</h3>
<img src="/images/Penguins.bmp?width=300&filter=polaroid" />
</div>
<div class="column-6">
<h3>sepia</h3>
<img src="/images/Penguins.bmp?width=300&filter=sepia" />
</div>
</div>
<div class="row">
<div class="column-6">
<h3>gotham</h3>
<img src="/images/Penguins.bmp?width=300&filter=gotham" />
</div>
<div class="column-6">
<h3>hisatch</h3>
<img src="/images/Penguins.bmp?width=300&filter=hisatch" />
</div>
</div>
<div class="row">
<div class="column-6">
<h3>losatch</h3>
<img src="/images/Penguins.bmp?width=300&filter=losatch" />
</div>
</div>
</section>
<section>
<div class="container">
<div class="clmn2">
<div class="row">
<div class="column-6">
<h2>Watermark</h2>
<img src="/images/Penguins.bmp?width=300&watermark=text-test|color-fff|size-48|style-italic|opacity-100|position-100-100|shadow-true|font-arial" />
</div>
<div class="clmn2">
<div class="column-6">
<h2>Format</h2>
<img src="/images/Penguins.bmp?width=300&format=jpg" />
</div>
</div>
</section>
<section>
<div class="container">
<div class="clmn2">
<div class="row">
<div class="column-6">
<h2>Rotate</h2>
<img src="/images/Penguins.bmp?width=300&rotate=angle-54|bgcolor-fff" />
</div>
<div class="clmn2">
<div class="column-6">
<h2>Quality</h2>
<img src="/images/Penguins.bmp?width=300&quality=5" />
</div>
</div>
</section>
<section>
<div class="container">
<div class="clmn2">
<div class="row">
<div class="column-6">
<h2>Alpha</h2>
<img src="/images/Penguins.bmp?width=300&alpha=50" />
</div>

18
src/TestWebsites/NET4/Views/Home/Responsive.cshtml

@ -1,18 +0,0 @@
@{
ViewBag.Title = "Responsive";
}
<style type="text/css">
img
{
max-width: 100%;
}
</style>
<h2>
Responsive</h2>
<img src="/Images/desert.jpg?width=480" srcset="/Images/desert.jpg?width=768 480w, /Images/penguins.jpg?width=979 640w 2x, /Images/jellyfish.jpg?width=480 2x"
alt="desert" />
@*<img src="/Images/desert.jpg?width=480" srcset="/Images/desert.jpg?width=768 480w, /Images/jellyfish.jpg?width=480 2x, /Images/penguins.jpg?width=979 640w 2x"
alt="desert" />*@ @*<img src="/Images/desert.jpg?width=480" srcset="/Images/desert.jpg?width=768 480w, /Images/desert.jpg?width=979 768w"
alt="desert" />*@
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
<script src="/Scripts/img.srcsect.pollyfill.js" type="text/javascript"></script>

5
src/TestWebsites/NET4/Views/Home/Upload.cshtml

@ -1,5 +0,0 @@
@using (Html.BeginForm("Upload", "Home", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
<input type="file" name="file" />
<button type="submit">Upload</button>
}

9
src/TestWebsites/NET4/Views/Shared/Error.cshtml

@ -1,9 +0,0 @@
@model System.Web.Mvc.HandleErrorInfo
@{
ViewBag.Title = "Error";
}
<h2>
Sorry, an error occurred while processing your request.
</h2>

25
src/TestWebsites/NET4/Views/Shared/_Layout.cshtml

@ -3,22 +3,17 @@
<head>
<meta charset="utf-8" />
<title>@ViewBag.Title</title>
<link href="@Url.Content("~/Content/flexo.css")" rel="stylesheet" type="text/css" />
<link href="@Url.Content("~/Content/style.css")" rel="stylesheet" type="text/css" />
<link href="@Url.Content("~/Content/responsive.min.css")" rel="stylesheet" type="text/css" media="all and (min-width: 1em)" />
<!--[if lt IE 9 &!(IEMobile)]>
<link href="@Url.Content("~/Content/responsive-legacy.min.css")" rel="stylesheet" type="text/css" />
<![endif]-->
</head>
<body>
<div class="page">
<header>
<div class="container">
<h1>ImageProcessor NET4.0</h1>
</div>
</header>
<section id="main">
@RenderBody()
</section>
</div>
<footer class="page-footer">
</footer>
<header class="container">
<h1>ImageProcessor NET4</h1>
</header>
<section class="container">
@RenderBody()
</section>
</body>
</html>

8
src/TestWebsites/NET4/Web.config

@ -48,7 +48,9 @@
</system.web>
<system.webServer>
<validation validateIntegratedModeConfiguration="false" />
<modules runAllManagedModulesForAllRequests="true" />
<modules runAllManagedModulesForAllRequests="true">
<add name="ImageProcessorModule" type="ImageProcessor.Web.HttpModules.ImageProcessingModule, ImageProcessor.Web" />
</modules>
</system.webServer>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
@ -58,11 +60,11 @@
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Runtime" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-2.5.19.0" newVersion="2.5.19.0" />
<bindingRedirect oldVersion="0.0.0.0-2.6.3.0" newVersion="2.6.3.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Threading.Tasks" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-2.5.19.0" newVersion="2.5.19.0" />
<bindingRedirect oldVersion="0.0.0.0-2.6.3.0" newVersion="2.6.3.0" />
</dependentAssembly>
</assemblyBinding>
</runtime>

BIN
src/TestWebsites/NET4/cache/0/0/0af9c9c3ac0bd099667ef1890991ecf0.jpg

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

BIN
src/TestWebsites/NET4/cache/0/2/0b5ec0dd58da4a94241a4a0c84fbcf92.jpg

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

1
src/TestWebsites/NET4/cache/0/3/0ed1b21b56f58f1cc566014f5f5cf5e3.bmp.REMOVED.git-id

@ -1 +0,0 @@
f4e00752418f01964b99ce300d96c16a9aa8d239

1
src/TestWebsites/NET4/cache/0/4/0b64a147662ae5f841029e61c5e88984.png.REMOVED.git-id

@ -1 +0,0 @@
fd46e83948190f508b8906f0822eca8dd4eda2ef

1
src/TestWebsites/NET4/cache/0/7/09f4cdcadedc15e2bb3fb3647d6e4a87.bmp.REMOVED.git-id

@ -1 +0,0 @@
aa7c907774ef5492ae25ffb7e3ff9755257731bd

1
src/TestWebsites/NET4/cache/0/c/016bbd2c44ab6af915e4dc26a715d5ec.bmp.REMOVED.git-id

@ -1 +0,0 @@
1038ebe89d7cfb28ec96a421867a2b0efc6dfdb4

1
src/TestWebsites/NET4/cache/0/e/0b24c3d312abd3bfcc04452e8eaca81e.bmp.REMOVED.git-id

@ -1 +0,0 @@
1456713687c96cd486c4ec8e57d3c4f6f6437f10

1
src/TestWebsites/NET4/cache/0/f/07d78f73ba8fe89fe3197254c394da4f.bmp.REMOVED.git-id

@ -1 +0,0 @@
4c16fd6b5b6b8cc426bc290d15ab41523be29403

1
src/TestWebsites/NET4/cache/1/3/1de0e9e101bdd9bc8122039f22bcc073.bmp.REMOVED.git-id

@ -1 +0,0 @@
bbf8bc24452deb732adf66ef3488793859f4f5b7

BIN
src/TestWebsites/NET4/cache/2/8/28d7c32164bdb0423a972759b7cf68a8.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

BIN
src/TestWebsites/NET4/cache/2/d/218fc888534353242520d7c4975e43fd.gif

Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

BIN
src/TestWebsites/NET4/cache/3/4/3470eab4ef380d70769da7c043814fe4.jpg

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

BIN
src/TestWebsites/NET4/cache/3/5/3bc1aeca44cbb62786c612395a5de385.jpg

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save