From 3c30c2153406111845a694a14670763915d35153 Mon Sep 17 00:00:00 2001 From: James South Date: Mon, 1 Sep 2014 21:46:25 +0100 Subject: [PATCH 1/3] Initial CAIR plugin addition Former-commit-id: 04aa2a6ae553cf5539dcf32f741b45ee1bd3407f --- src/ImageProcessor.Web/Processors/Resize.cs | 8 +- src/ImageProcessor.sln | 17 + .../ImageProcessorConsole.csproj | 4 + src/ImageProcessorConsole/Program.cs | 12 +- .../input/2006-citybus.jpg.REMOVED.git-id | 1 + .../images/input/2008.jpg.REMOVED.git-id | 1 + .../input/2012-citybus.jpg.REMOVED.git-id | 1 + .../Arc-de-Triomphe-France.jpg.REMOVED.git-id | 1 + .../input/Image with gaps.jpg.REMOVED.git-id | 1 + ...e_triomphe_paris_france.jpg.REMOVED.git-id | 1 + .../images/input/monster.png.REMOVED.git-id | 1 + .../images/input/mountain.jpg.REMOVED.git-id | 1 + .../input/night-bridge.jpg.REMOVED.git-id | 1 + ...Arc_de_triomphe-square1.jpg.REMOVED.git-id | 1 + .../images/input/test.jpg.REMOVED.git-id | 1 + .../images/input/tower.jpg.REMOVED.git-id | 1 + .../images/output/120430.gif.REMOVED.git-id | 2 +- .../output/2006-citybus.jpg.REMOVED.git-id | 1 + .../images/output/2008.jpg.REMOVED.git-id | 1 + .../output/2012-citybus.jpg.REMOVED.git-id | 1 + .../Arc-de-Triomphe-France.jpg.REMOVED.git-id | 1 + .../output/Image with gaps.jpg.REMOVED.git-id | 1 + .../images/output/Tl4Yb.gif.REMOVED.git-id | 2 +- ...e_triomphe_paris_france.jpg.REMOVED.git-id | 1 + .../images/output/circle.png | Bin 2905 -> 5001 bytes .../images/output/monster.png.REMOVED.git-id | 1 + .../images/output/mountain.jpg.REMOVED.git-id | 1 + .../images/output/nLpfllv.gif.REMOVED.git-id | 2 +- .../images/output/night-bridge.jpg | Bin 0 -> 56360 bytes .../images/output/rotate.jpg | Bin 18422 -> 0 bytes .../images/output/rotate.jpg.REMOVED.git-id | 1 + ...Arc_de_triomphe-square1.jpg.REMOVED.git-id | 1 + .../images/output/test.jpg.REMOVED.git-id | 1 + .../images/output/tower.jpg.REMOVED.git-id | 1 + .../CairBootstrapper.cs | 109 ++++ .../ImageFactoryExtensions.cs | 77 +++ .../ImageProcessor.Plugins.Cair.csproj | 75 +++ .../ContentAwareResizeConvolutionType.cs | 43 ++ .../Imaging/ContentAwareResizeLayer.cs | 179 +++++++ .../Imaging/EnergyFunction.cs | 29 ++ .../Processors/ContentAwareResize.cs | 239 +++++++++ .../Properties/AssemblyInfo.cs | 36 ++ .../Unmanaged/x86/CAIR.exe.REMOVED.git-id | 1 + .../Resources/Unmanaged/x86/GPL.txt | 473 ++++++++++++++++++ .../Resources/Unmanaged/x86/ReadMe.txt | 282 +++++++++++ .../x86/pthreadVSE2.dll.REMOVED.git-id | 1 + .../Settings.StyleCop | 9 + .../Imaging/Formats/NativeMethods.cs | 13 +- .../Properties/AssemblyInfo.cs | 4 +- 49 files changed, 1625 insertions(+), 16 deletions(-) create mode 100644 src/ImageProcessorConsole/images/input/2006-citybus.jpg.REMOVED.git-id create mode 100644 src/ImageProcessorConsole/images/input/2008.jpg.REMOVED.git-id create mode 100644 src/ImageProcessorConsole/images/input/2012-citybus.jpg.REMOVED.git-id create mode 100644 src/ImageProcessorConsole/images/input/Arc-de-Triomphe-France.jpg.REMOVED.git-id create mode 100644 src/ImageProcessorConsole/images/input/Image with gaps.jpg.REMOVED.git-id create mode 100644 src/ImageProcessorConsole/images/input/arc_de_triomphe_paris_france.jpg.REMOVED.git-id create mode 100644 src/ImageProcessorConsole/images/input/monster.png.REMOVED.git-id create mode 100644 src/ImageProcessorConsole/images/input/mountain.jpg.REMOVED.git-id create mode 100644 src/ImageProcessorConsole/images/input/night-bridge.jpg.REMOVED.git-id create mode 100644 src/ImageProcessorConsole/images/input/shutterstock_19173982_Arc_de_triomphe-square1.jpg.REMOVED.git-id create mode 100644 src/ImageProcessorConsole/images/input/test.jpg.REMOVED.git-id create mode 100644 src/ImageProcessorConsole/images/input/tower.jpg.REMOVED.git-id create mode 100644 src/ImageProcessorConsole/images/output/2006-citybus.jpg.REMOVED.git-id create mode 100644 src/ImageProcessorConsole/images/output/2008.jpg.REMOVED.git-id create mode 100644 src/ImageProcessorConsole/images/output/2012-citybus.jpg.REMOVED.git-id create mode 100644 src/ImageProcessorConsole/images/output/Arc-de-Triomphe-France.jpg.REMOVED.git-id create mode 100644 src/ImageProcessorConsole/images/output/Image with gaps.jpg.REMOVED.git-id create mode 100644 src/ImageProcessorConsole/images/output/arc_de_triomphe_paris_france.jpg.REMOVED.git-id create mode 100644 src/ImageProcessorConsole/images/output/monster.png.REMOVED.git-id create mode 100644 src/ImageProcessorConsole/images/output/mountain.jpg.REMOVED.git-id create mode 100644 src/ImageProcessorConsole/images/output/night-bridge.jpg delete mode 100644 src/ImageProcessorConsole/images/output/rotate.jpg create mode 100644 src/ImageProcessorConsole/images/output/rotate.jpg.REMOVED.git-id create mode 100644 src/ImageProcessorConsole/images/output/shutterstock_19173982_Arc_de_triomphe-square1.jpg.REMOVED.git-id create mode 100644 src/ImageProcessorConsole/images/output/test.jpg.REMOVED.git-id create mode 100644 src/ImageProcessorConsole/images/output/tower.jpg.REMOVED.git-id create mode 100644 src/Plugins/ImageProcessor/ImageProcessor.Plugins.Cair/CairBootstrapper.cs create mode 100644 src/Plugins/ImageProcessor/ImageProcessor.Plugins.Cair/ImageFactoryExtensions.cs create mode 100644 src/Plugins/ImageProcessor/ImageProcessor.Plugins.Cair/ImageProcessor.Plugins.Cair.csproj create mode 100644 src/Plugins/ImageProcessor/ImageProcessor.Plugins.Cair/Imaging/ContentAwareResizeConvolutionType.cs create mode 100644 src/Plugins/ImageProcessor/ImageProcessor.Plugins.Cair/Imaging/ContentAwareResizeLayer.cs create mode 100644 src/Plugins/ImageProcessor/ImageProcessor.Plugins.Cair/Imaging/EnergyFunction.cs create mode 100644 src/Plugins/ImageProcessor/ImageProcessor.Plugins.Cair/Processors/ContentAwareResize.cs create mode 100644 src/Plugins/ImageProcessor/ImageProcessor.Plugins.Cair/Properties/AssemblyInfo.cs create mode 100644 src/Plugins/ImageProcessor/ImageProcessor.Plugins.Cair/Resources/Unmanaged/x86/CAIR.exe.REMOVED.git-id create mode 100644 src/Plugins/ImageProcessor/ImageProcessor.Plugins.Cair/Resources/Unmanaged/x86/GPL.txt create mode 100644 src/Plugins/ImageProcessor/ImageProcessor.Plugins.Cair/Resources/Unmanaged/x86/ReadMe.txt create mode 100644 src/Plugins/ImageProcessor/ImageProcessor.Plugins.Cair/Resources/Unmanaged/x86/pthreadVSE2.dll.REMOVED.git-id create mode 100644 src/Plugins/ImageProcessor/ImageProcessor.Plugins.Cair/Settings.StyleCop diff --git a/src/ImageProcessor.Web/Processors/Resize.cs b/src/ImageProcessor.Web/Processors/Resize.cs index 3c1772911..cfcc7b633 100644 --- a/src/ImageProcessor.Web/Processors/Resize.cs +++ b/src/ImageProcessor.Web/Processors/Resize.cs @@ -29,7 +29,7 @@ namespace ImageProcessor.Web.Processors /// /// The regular expression to search strings for. /// - private static readonly Regex QueryRegex = new Regex(@"(width|height)=|(width|height)ratio=|mode=|anchor=|center=|upscale=", RegexOptions.Compiled); + private static readonly Regex QueryRegex = new Regex(@"(width|height)=|(width|height)ratio=|mode=(carve)?|anchor=|center=|upscale=", RegexOptions.Compiled); /// /// The regular expression to search strings for the size attribute. @@ -111,6 +111,12 @@ namespace ImageProcessor.Web.Processors { if (match.Success) { + // We don't want any resize carve requests to interfere. + if (match.Value.ToUpperInvariant().Contains("CARVE")) + { + break; + } + if (index == 0) { // Set the index on the first instance only. diff --git a/src/ImageProcessor.sln b/src/ImageProcessor.sln index 5009fba41..0909ba654 100644 --- a/src/ImageProcessor.sln +++ b/src/ImageProcessor.sln @@ -32,6 +32,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Web.Tests", "Web.Test\Web.T EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Test_Website_MVC", "TestWebsites\MVC\Test_Website_MVC.csproj", "{F6A208E9-C18F-43E9-B051-3C6EED30FDAF}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ImageProcessor.Plugins.Cair", "Plugins\ImageProcessor\ImageProcessor.Plugins.Cair\ImageProcessor.Plugins.Cair.csproj", "{C7D1F0DD-CBD6-4127-82B4-51949EFF0BF5}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution All|Any CPU = All|Any CPU @@ -164,6 +166,21 @@ Global {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 + {C7D1F0DD-CBD6-4127-82B4-51949EFF0BF5}.All|Any CPU.ActiveCfg = Release|Any CPU + {C7D1F0DD-CBD6-4127-82B4-51949EFF0BF5}.All|Any CPU.Build.0 = Release|Any CPU + {C7D1F0DD-CBD6-4127-82B4-51949EFF0BF5}.All|Mixed Platforms.ActiveCfg = Release|Any CPU + {C7D1F0DD-CBD6-4127-82B4-51949EFF0BF5}.All|Mixed Platforms.Build.0 = Release|Any CPU + {C7D1F0DD-CBD6-4127-82B4-51949EFF0BF5}.All|x86.ActiveCfg = Release|Any CPU + {C7D1F0DD-CBD6-4127-82B4-51949EFF0BF5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C7D1F0DD-CBD6-4127-82B4-51949EFF0BF5}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C7D1F0DD-CBD6-4127-82B4-51949EFF0BF5}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {C7D1F0DD-CBD6-4127-82B4-51949EFF0BF5}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {C7D1F0DD-CBD6-4127-82B4-51949EFF0BF5}.Debug|x86.ActiveCfg = Debug|Any CPU + {C7D1F0DD-CBD6-4127-82B4-51949EFF0BF5}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C7D1F0DD-CBD6-4127-82B4-51949EFF0BF5}.Release|Any CPU.Build.0 = Release|Any CPU + {C7D1F0DD-CBD6-4127-82B4-51949EFF0BF5}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {C7D1F0DD-CBD6-4127-82B4-51949EFF0BF5}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {C7D1F0DD-CBD6-4127-82B4-51949EFF0BF5}.Release|x86.ActiveCfg = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/src/ImageProcessorConsole/ImageProcessorConsole.csproj b/src/ImageProcessorConsole/ImageProcessorConsole.csproj index 1afd8ef0e..3d3b992cc 100644 --- a/src/ImageProcessorConsole/ImageProcessorConsole.csproj +++ b/src/ImageProcessorConsole/ImageProcessorConsole.csproj @@ -56,6 +56,10 @@ {3B5DD734-FB7A-487D-8CE6-55E7AF9AEA7E} ImageProcessor + + {c7d1f0dd-cbd6-4127-82b4-51949eff0bf5} + ImageProcessor.Plugins.Cair + {2cf69699-959a-44dc-a281-4e2596c25043} ImageProcessor.Plugins.WebP diff --git a/src/ImageProcessorConsole/Program.cs b/src/ImageProcessorConsole/Program.cs index 73490f97c..6293a3edc 100644 --- a/src/ImageProcessorConsole/Program.cs +++ b/src/ImageProcessorConsole/Program.cs @@ -16,6 +16,7 @@ namespace ImageProcessorConsole using System.IO; using System.Linq; using ImageProcessor; + using ImageProcessor.Plugins.Cair; /// /// The program. @@ -40,8 +41,8 @@ namespace ImageProcessorConsole di.Create(); } - //IEnumerable files = GetFilesByExtensions(di, ".jpg"); - IEnumerable files = GetFilesByExtensions(di, ".gif", ".webp", ".bmp", ".jpg", ".png"); + IEnumerable files = GetFilesByExtensions(di, ".jpg"); + //IEnumerable files = GetFilesByExtensions(di, ".gif", ".webp", ".bmp", ".jpg", ".png"); foreach (FileInfo fileInfo in files) { @@ -52,11 +53,14 @@ namespace ImageProcessorConsole { using (ImageFactory imageFactory = new ImageFactory(true)) { - Size size = new Size(200, 200); + Size size = new Size(800, 0); // Load, resize, set the format and quality and save an image. imageFactory.Load(inStream) - .Constrain(size) + //.BackgroundColor(Color.White) + //.Resize(new Size((int)(size.Width * 1.1), 0)) + .ContentAwareResize(size) + //.Constrain(size) .Save(Path.GetFullPath(Path.Combine(Path.GetDirectoryName(path), @"..\..\images\output", fileInfo.Name))); } } diff --git a/src/ImageProcessorConsole/images/input/2006-citybus.jpg.REMOVED.git-id b/src/ImageProcessorConsole/images/input/2006-citybus.jpg.REMOVED.git-id new file mode 100644 index 000000000..7b98fa949 --- /dev/null +++ b/src/ImageProcessorConsole/images/input/2006-citybus.jpg.REMOVED.git-id @@ -0,0 +1 @@ +7f6786517fa67c9dfccac831e8491e4d08866d24 \ No newline at end of file diff --git a/src/ImageProcessorConsole/images/input/2008.jpg.REMOVED.git-id b/src/ImageProcessorConsole/images/input/2008.jpg.REMOVED.git-id new file mode 100644 index 000000000..9e3731b87 --- /dev/null +++ b/src/ImageProcessorConsole/images/input/2008.jpg.REMOVED.git-id @@ -0,0 +1 @@ +7eb554b7681119b1170b70f1c1c2fc0de28a60ac \ No newline at end of file diff --git a/src/ImageProcessorConsole/images/input/2012-citybus.jpg.REMOVED.git-id b/src/ImageProcessorConsole/images/input/2012-citybus.jpg.REMOVED.git-id new file mode 100644 index 000000000..5d7234332 --- /dev/null +++ b/src/ImageProcessorConsole/images/input/2012-citybus.jpg.REMOVED.git-id @@ -0,0 +1 @@ +8d39e89104598b85035a2c29592b847edcfdb8ac \ No newline at end of file diff --git a/src/ImageProcessorConsole/images/input/Arc-de-Triomphe-France.jpg.REMOVED.git-id b/src/ImageProcessorConsole/images/input/Arc-de-Triomphe-France.jpg.REMOVED.git-id new file mode 100644 index 000000000..6423c7d48 --- /dev/null +++ b/src/ImageProcessorConsole/images/input/Arc-de-Triomphe-France.jpg.REMOVED.git-id @@ -0,0 +1 @@ +ff6cd6bf1cd388e8933071ec36880c33d1bc08f2 \ No newline at end of file diff --git a/src/ImageProcessorConsole/images/input/Image with gaps.jpg.REMOVED.git-id b/src/ImageProcessorConsole/images/input/Image with gaps.jpg.REMOVED.git-id new file mode 100644 index 000000000..169a4049b --- /dev/null +++ b/src/ImageProcessorConsole/images/input/Image with gaps.jpg.REMOVED.git-id @@ -0,0 +1 @@ +68e14cae5c31c58b8b66d26bca6eb67c79ecd203 \ No newline at end of file diff --git a/src/ImageProcessorConsole/images/input/arc_de_triomphe_paris_france.jpg.REMOVED.git-id b/src/ImageProcessorConsole/images/input/arc_de_triomphe_paris_france.jpg.REMOVED.git-id new file mode 100644 index 000000000..5aa90ba7d --- /dev/null +++ b/src/ImageProcessorConsole/images/input/arc_de_triomphe_paris_france.jpg.REMOVED.git-id @@ -0,0 +1 @@ +c679b986c1ccbd9f6f8d72d7e4717f380b923a75 \ No newline at end of file diff --git a/src/ImageProcessorConsole/images/input/monster.png.REMOVED.git-id b/src/ImageProcessorConsole/images/input/monster.png.REMOVED.git-id new file mode 100644 index 000000000..3d53156f1 --- /dev/null +++ b/src/ImageProcessorConsole/images/input/monster.png.REMOVED.git-id @@ -0,0 +1 @@ +6b1252209f60025427722f765dbbc271d125114e \ No newline at end of file diff --git a/src/ImageProcessorConsole/images/input/mountain.jpg.REMOVED.git-id b/src/ImageProcessorConsole/images/input/mountain.jpg.REMOVED.git-id new file mode 100644 index 000000000..d2d29b9de --- /dev/null +++ b/src/ImageProcessorConsole/images/input/mountain.jpg.REMOVED.git-id @@ -0,0 +1 @@ +66b1f9f5ef7ca628ca4a44de9188e11e4af17229 \ No newline at end of file diff --git a/src/ImageProcessorConsole/images/input/night-bridge.jpg.REMOVED.git-id b/src/ImageProcessorConsole/images/input/night-bridge.jpg.REMOVED.git-id new file mode 100644 index 000000000..22294d823 --- /dev/null +++ b/src/ImageProcessorConsole/images/input/night-bridge.jpg.REMOVED.git-id @@ -0,0 +1 @@ +414f5a48bd8d020beae85c2dee480cb5d22ec9b7 \ No newline at end of file diff --git a/src/ImageProcessorConsole/images/input/shutterstock_19173982_Arc_de_triomphe-square1.jpg.REMOVED.git-id b/src/ImageProcessorConsole/images/input/shutterstock_19173982_Arc_de_triomphe-square1.jpg.REMOVED.git-id new file mode 100644 index 000000000..8de5c3abf --- /dev/null +++ b/src/ImageProcessorConsole/images/input/shutterstock_19173982_Arc_de_triomphe-square1.jpg.REMOVED.git-id @@ -0,0 +1 @@ +a2cccdee0f806b2d41bfcdbb2dc9a1fe3d8656c6 \ No newline at end of file diff --git a/src/ImageProcessorConsole/images/input/test.jpg.REMOVED.git-id b/src/ImageProcessorConsole/images/input/test.jpg.REMOVED.git-id new file mode 100644 index 000000000..a144a0d2b --- /dev/null +++ b/src/ImageProcessorConsole/images/input/test.jpg.REMOVED.git-id @@ -0,0 +1 @@ +99704952050f56a69f591220bb9f0f2014215c7f \ No newline at end of file diff --git a/src/ImageProcessorConsole/images/input/tower.jpg.REMOVED.git-id b/src/ImageProcessorConsole/images/input/tower.jpg.REMOVED.git-id new file mode 100644 index 000000000..d45f646a2 --- /dev/null +++ b/src/ImageProcessorConsole/images/input/tower.jpg.REMOVED.git-id @@ -0,0 +1 @@ +98c3f8fce4fdd9eebafe12431c8e014fd39d243f \ No newline at end of file diff --git a/src/ImageProcessorConsole/images/output/120430.gif.REMOVED.git-id b/src/ImageProcessorConsole/images/output/120430.gif.REMOVED.git-id index 71ce555c1..7c7807f6d 100644 --- a/src/ImageProcessorConsole/images/output/120430.gif.REMOVED.git-id +++ b/src/ImageProcessorConsole/images/output/120430.gif.REMOVED.git-id @@ -1 +1 @@ -30ec5c05548fd350f9b7c699715848b9fbfb8ca9 \ No newline at end of file +e41022eb5fe724ba5fe2b7aeda29a1f4b6878484 \ No newline at end of file diff --git a/src/ImageProcessorConsole/images/output/2006-citybus.jpg.REMOVED.git-id b/src/ImageProcessorConsole/images/output/2006-citybus.jpg.REMOVED.git-id new file mode 100644 index 000000000..5fe88ad75 --- /dev/null +++ b/src/ImageProcessorConsole/images/output/2006-citybus.jpg.REMOVED.git-id @@ -0,0 +1 @@ +33f7e25da5675197f18bb2fa2c9fe5fa366e84ec \ No newline at end of file diff --git a/src/ImageProcessorConsole/images/output/2008.jpg.REMOVED.git-id b/src/ImageProcessorConsole/images/output/2008.jpg.REMOVED.git-id new file mode 100644 index 000000000..fcb030451 --- /dev/null +++ b/src/ImageProcessorConsole/images/output/2008.jpg.REMOVED.git-id @@ -0,0 +1 @@ +f24f17627804b11d823240d49c91ec17fb7fd55d \ No newline at end of file diff --git a/src/ImageProcessorConsole/images/output/2012-citybus.jpg.REMOVED.git-id b/src/ImageProcessorConsole/images/output/2012-citybus.jpg.REMOVED.git-id new file mode 100644 index 000000000..3ade52d60 --- /dev/null +++ b/src/ImageProcessorConsole/images/output/2012-citybus.jpg.REMOVED.git-id @@ -0,0 +1 @@ +def19dd7469cf2eba1f595e7263d9d48fda85825 \ No newline at end of file diff --git a/src/ImageProcessorConsole/images/output/Arc-de-Triomphe-France.jpg.REMOVED.git-id b/src/ImageProcessorConsole/images/output/Arc-de-Triomphe-France.jpg.REMOVED.git-id new file mode 100644 index 000000000..83ecfe032 --- /dev/null +++ b/src/ImageProcessorConsole/images/output/Arc-de-Triomphe-France.jpg.REMOVED.git-id @@ -0,0 +1 @@ +8cf61b55acca1a3d1a69177ddc439685ee0ba192 \ No newline at end of file diff --git a/src/ImageProcessorConsole/images/output/Image with gaps.jpg.REMOVED.git-id b/src/ImageProcessorConsole/images/output/Image with gaps.jpg.REMOVED.git-id new file mode 100644 index 000000000..7ea690341 --- /dev/null +++ b/src/ImageProcessorConsole/images/output/Image with gaps.jpg.REMOVED.git-id @@ -0,0 +1 @@ +629284a6f834f5d1cf185e3603a50c484dd9121a \ No newline at end of file diff --git a/src/ImageProcessorConsole/images/output/Tl4Yb.gif.REMOVED.git-id b/src/ImageProcessorConsole/images/output/Tl4Yb.gif.REMOVED.git-id index 6515d65a0..60a69fbf6 100644 --- a/src/ImageProcessorConsole/images/output/Tl4Yb.gif.REMOVED.git-id +++ b/src/ImageProcessorConsole/images/output/Tl4Yb.gif.REMOVED.git-id @@ -1 +1 @@ -fdc62fc2d056ab885eb9e8fd12b9155ee86d7c43 \ No newline at end of file +f5681324d193a42492647f4952057c2b72026096 \ No newline at end of file diff --git a/src/ImageProcessorConsole/images/output/arc_de_triomphe_paris_france.jpg.REMOVED.git-id b/src/ImageProcessorConsole/images/output/arc_de_triomphe_paris_france.jpg.REMOVED.git-id new file mode 100644 index 000000000..e3f15eac7 --- /dev/null +++ b/src/ImageProcessorConsole/images/output/arc_de_triomphe_paris_france.jpg.REMOVED.git-id @@ -0,0 +1 @@ +3d652e0628f2042e7aca0751384ba21f1182ef5f \ No newline at end of file diff --git a/src/ImageProcessorConsole/images/output/circle.png b/src/ImageProcessorConsole/images/output/circle.png index 41fdcd72af59ba2158b19120e7ba11f4cad0180d..893ca4021338c63cbc790daeb1a81e0d967e4367 100644 GIT binary patch literal 5001 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 diff --git a/src/ImageProcessorConsole/images/output/monster.png.REMOVED.git-id b/src/ImageProcessorConsole/images/output/monster.png.REMOVED.git-id new file mode 100644 index 000000000..11e46ba6d --- /dev/null +++ b/src/ImageProcessorConsole/images/output/monster.png.REMOVED.git-id @@ -0,0 +1 @@ +d8d3354b684cad79d9a46f92ed3a58747a808ad1 \ No newline at end of file diff --git a/src/ImageProcessorConsole/images/output/mountain.jpg.REMOVED.git-id b/src/ImageProcessorConsole/images/output/mountain.jpg.REMOVED.git-id new file mode 100644 index 000000000..05e668428 --- /dev/null +++ b/src/ImageProcessorConsole/images/output/mountain.jpg.REMOVED.git-id @@ -0,0 +1 @@ +1c48519b2675b9dd90e8e95d6421148b25b8c317 \ No newline at end of file diff --git a/src/ImageProcessorConsole/images/output/nLpfllv.gif.REMOVED.git-id b/src/ImageProcessorConsole/images/output/nLpfllv.gif.REMOVED.git-id index 4487aede0..f187b0ed5 100644 --- a/src/ImageProcessorConsole/images/output/nLpfllv.gif.REMOVED.git-id +++ b/src/ImageProcessorConsole/images/output/nLpfllv.gif.REMOVED.git-id @@ -1 +1 @@ -23a1c81a2d1422076373796e0c47f5d968c56d0b \ No newline at end of file +b65d9e937cad7ddd02ff0d01a3be2f09c55e63e8 \ No newline at end of file diff --git a/src/ImageProcessorConsole/images/output/night-bridge.jpg b/src/ImageProcessorConsole/images/output/night-bridge.jpg new file mode 100644 index 0000000000000000000000000000000000000000..8ca2a95c74077fb6168330bba783cb06d29835a4 GIT binary patch literal 56360 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 E+17TJ82|tP literal 0 HcmV?d00001 diff --git a/src/ImageProcessorConsole/images/output/rotate.jpg b/src/ImageProcessorConsole/images/output/rotate.jpg deleted file mode 100644 index 9e982a5ad461cd566d08e4882ddcdafa422ef5c1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 18422 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 +// Copyright (c) James South. +// Licensed under the Apache License, Version 2.0. +// +// +// Defines the CairBootstrapper type. +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace ImageProcessor.Plugins.Cair +{ + using System; + using System.IO; + using System.Reflection; + + using ImageProcessor.Configuration; + + /// + /// The cair bootstrapper. + /// + internal static class CairBootstrapper + { + /// + /// Initializes static members of the class. + /// + static CairBootstrapper() + { + RegisterCairExecutable(); + } + + /// + /// Gets the cair path. + /// + public static string CairPath { get; private set; } + + /// + /// Gets the cair image path. + /// + public static string CairImagePath { get; private set; } + + /// + /// Registers the embedded CAIR executable. + /// + public static void RegisterCairExecutable() + { + // None of the tools used here are called using dllimport so we don't go through the normal registration channel. + string folder = ImageProcessorBootstrapper.Instance.NativeBinaryFactory.Is64BitEnvironment ? "x64" : "x86"; + Assembly assembly = Assembly.GetExecutingAssembly(); + string targetBasePath = new Uri(assembly.Location).LocalPath; + string multithreaderTargetPath = Path.GetFullPath(Path.Combine(targetBasePath, "..\\" + folder + "\\" + "pthreadVSE2.dll")); + + // Set the global variable. + CairPath = Path.GetFullPath(Path.Combine(targetBasePath, "..\\" + folder + "\\" + "CAIR.exe")); + CairImagePath = Path.GetFullPath(Path.Combine(targetBasePath, "..\\" + folder + "\\" + "cairimages\\")); + + // Get the resources and copy them across. + const string CairResourcePath = "ImageProcessor.Plugins.Cair.Resources.Unmanaged.x86.CAIR.exe"; + const string MultithreaderResourcePath = "ImageProcessor.Plugins.Cair.Resources.Unmanaged.x86.pthreadVSE2.dll"; + + // Write the two files out to the bin folder. + // Copy out the threading binary. + using (Stream resourceStream = Assembly.GetExecutingAssembly().GetManifestResourceStream(MultithreaderResourcePath)) + { + if (resourceStream != null) + { + // ReSharper disable once AssignNullToNotNullAttribute + DirectoryInfo threaderDirectoryInfo = new DirectoryInfo(Path.GetDirectoryName(multithreaderTargetPath)); + if (!threaderDirectoryInfo.Exists) + { + threaderDirectoryInfo.Create(); + } + + using (FileStream fileStream = File.OpenWrite(multithreaderTargetPath)) + { + resourceStream.CopyTo(fileStream); + } + } + } + + // Copy out the cair executable. + using (Stream resourceStream = Assembly.GetExecutingAssembly().GetManifestResourceStream(CairResourcePath)) + { + if (resourceStream != null) + { + // ReSharper disable once AssignNullToNotNullAttribute + DirectoryInfo cairDirectoryInfo = new DirectoryInfo(Path.GetDirectoryName(CairPath)); + if (!cairDirectoryInfo.Exists) + { + cairDirectoryInfo.Create(); + } + + using (FileStream fileStream = File.OpenWrite(CairPath)) + { + resourceStream.CopyTo(fileStream); + } + } + } + + // Lastly create the image folder for storing temporary images. + // ReSharper disable once AssignNullToNotNullAttribute + DirectoryInfo directoryInfo = new DirectoryInfo(Path.GetDirectoryName(CairImagePath)); + if (!directoryInfo.Exists) + { + directoryInfo.Create(); + } + } + } +} diff --git a/src/Plugins/ImageProcessor/ImageProcessor.Plugins.Cair/ImageFactoryExtensions.cs b/src/Plugins/ImageProcessor/ImageProcessor.Plugins.Cair/ImageFactoryExtensions.cs new file mode 100644 index 000000000..cba46c403 --- /dev/null +++ b/src/Plugins/ImageProcessor/ImageProcessor.Plugins.Cair/ImageFactoryExtensions.cs @@ -0,0 +1,77 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) James South. +// Licensed under the Apache License, Version 2.0. +// +// +// Extends the ImageFactory class to provide a fluent API. +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace ImageProcessor.Plugins.Cair +{ + using System.Collections.Generic; + using System.Drawing; + + using ImageProcessor.Plugins.Cair.Imaging; + using ImageProcessor.Plugins.Cair.Processors; + + /// + /// Extends the ImageFactory class to provide a fluent API. + /// + public static class ImageFactoryExtensions + { + /// + /// Resizes the current image to the given dimensions using Content Aware Resizing. + /// + /// + /// The current instance of the class + /// that this method extends. + /// + /// + /// The containing the width and height to set the image to. + /// + /// + /// The current instance of the class. + /// + public static ImageFactory ContentAwareResize(this ImageFactory factory, Size size) + { + if (factory.ShouldProcess) + { + int width = size.Width; + int height = size.Height; + + ContentAwareResizeLayer resizeLayer = new ContentAwareResizeLayer(new Size(width, height)); + return factory.ContentAwareResize(resizeLayer); + } + + return factory; + } + + /// + /// Resizes the current image to the given dimensions using Content Aware Resizing. + /// + /// + /// The current instance of the class + /// that this method extends. + /// + /// + /// The containing the properties required to resize the image. + /// + /// + /// The current instance of the class. + /// + public static ImageFactory ContentAwareResize(this ImageFactory factory, ContentAwareResizeLayer layer) + { + if (factory.ShouldProcess) + { + Dictionary resizeSettings = new Dictionary { { "MaxWidth", layer.Size.Width.ToString("G") }, { "MaxHeight", layer.Size.Height.ToString("G") } }; + + ContentAwareResize resize = new ContentAwareResize { DynamicParameter = layer, Settings = resizeSettings }; + factory.CurrentImageFormat.ApplyProcessor(resize.ProcessImage, factory); + } + + return factory; + } + } +} diff --git a/src/Plugins/ImageProcessor/ImageProcessor.Plugins.Cair/ImageProcessor.Plugins.Cair.csproj b/src/Plugins/ImageProcessor/ImageProcessor.Plugins.Cair/ImageProcessor.Plugins.Cair.csproj new file mode 100644 index 000000000..75ba8715e --- /dev/null +++ b/src/Plugins/ImageProcessor/ImageProcessor.Plugins.Cair/ImageProcessor.Plugins.Cair.csproj @@ -0,0 +1,75 @@ + + + + + Debug + AnyCPU + {C7D1F0DD-CBD6-4127-82B4-51949EFF0BF5} + Library + Properties + ImageProcessor.Plugins.Cair + ImageProcessor.Plugins.Cair + v4.5 + 512 + + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + false + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + false + + + + + + + + + + + + + + + + + + + + + + + {3b5dd734-fb7a-487d-8ce6-55e7af9aea7e} + ImageProcessor + + + + + + + + + + + + \ No newline at end of file diff --git a/src/Plugins/ImageProcessor/ImageProcessor.Plugins.Cair/Imaging/ContentAwareResizeConvolutionType.cs b/src/Plugins/ImageProcessor/ImageProcessor.Plugins.Cair/Imaging/ContentAwareResizeConvolutionType.cs new file mode 100644 index 000000000..143b0fd3c --- /dev/null +++ b/src/Plugins/ImageProcessor/ImageProcessor.Plugins.Cair/Imaging/ContentAwareResizeConvolutionType.cs @@ -0,0 +1,43 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) James South. +// Licensed under the Apache License, Version 2.0. +// +// +// Provides enumeration of the content aware resize convolution types. +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace ImageProcessor.Plugins.Cair.Imaging +{ + /// + /// Provides enumeration of the content aware resize convolution types. + /// + public enum ContentAwareResizeConvolutionType + { + /// + /// The Prewitt kernel convolution type. + /// + Prewitt = 0, + + /// + /// The V1 kernel convolution type. + /// + V1 = 1, + + /// + /// The VSquare kernel convolution type. + /// + VSquare = 2, + + /// + /// The Sobel kernel convolution type. + /// + Sobel = 3, + + /// + /// The Laplacian kernel convolution type. + /// + Laplacian = 4 + } +} \ No newline at end of file diff --git a/src/Plugins/ImageProcessor/ImageProcessor.Plugins.Cair/Imaging/ContentAwareResizeLayer.cs b/src/Plugins/ImageProcessor/ImageProcessor.Plugins.Cair/Imaging/ContentAwareResizeLayer.cs new file mode 100644 index 000000000..d81b29907 --- /dev/null +++ b/src/Plugins/ImageProcessor/ImageProcessor.Plugins.Cair/Imaging/ContentAwareResizeLayer.cs @@ -0,0 +1,179 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) James South. +// Licensed under the Apache License, Version 2.0. +// +// +// Encapsulates the properties required to resize an image using content aware resizing. +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace ImageProcessor.Plugins.Cair.Imaging +{ + using System.Drawing; + + /// + /// Encapsulates the properties required to resize an image using content aware resizing. + /// + public class ContentAwareResizeLayer + { + /// + /// The convolution type to apply to the layer. + /// + private ContentAwareResizeConvolutionType convolutionType = ContentAwareResizeConvolutionType.Prewitt; + + /// + /// The energy function to apply to the layer. + /// + private EnergyFunction energyFunction = EnergyFunction.Forward; + + /// + /// Whether to assign multiple threads to the resizing method. + /// + private bool parallelize = true; + + /// + /// Whether to pre-scale the image to reduce errors in the output. + /// + private bool prescale = true; + + /// + /// The timeout in milliseconds to attempt to resize for. + /// + private int timeout = 60000; + + /// + /// Initializes a new instance of the class. + /// + /// + /// The containing the width and height to set the image to. + /// + public ContentAwareResizeLayer(Size size) + { + this.Size = size; + } + + /// + /// Gets or sets the size. + /// + public Size Size { get; set; } + + /// + /// Gets or sets the content aware resize convolution type (Default ContentAwareResizeConvolutionType.Prewitt). + /// + public ContentAwareResizeConvolutionType ConvolutionType + { + get + { + return this.convolutionType; + } + + set + { + this.convolutionType = value; + } + } + + /// + /// Gets or sets the energy function (Default EnergyFunction.Forward). + /// + public EnergyFunction EnergyFunction + { + get + { + return this.energyFunction; + } + + set + { + this.energyFunction = value; + } + } + + /// + /// Gets or sets a value indicating whether to assign multiple threads to the resizing method. + /// (Default true) + /// + public bool Parallelize + { + get + { + return this.parallelize; + } + + set + { + this.parallelize = value; + } + } + + /// + /// Gets or sets a value indicating whether to pre-scale the image to reduce errors in the output. + /// (Default true) + /// + public bool PreScale + { + get + { + return this.prescale; + } + + set + { + this.prescale = value; + } + } + + /// + /// Gets or sets the timeout in milliseconds to attempt to resize for (Default 60000). + /// + public int Timeout + { + get + { + return this.timeout; + } + + set + { + this.timeout = value; + } + } + + /// + /// Returns a value that indicates whether the specified object is an + /// object that is equivalent to + /// this object. + /// + /// + /// The object to test. + /// + /// + /// True if the given object is an object that is equivalent to + /// this object; otherwise, false. + /// + public override bool Equals(object obj) + { + ContentAwareResizeLayer resizeLayer = obj as ContentAwareResizeLayer; + + if (resizeLayer == null) + { + return false; + } + + return this.Size == resizeLayer.Size + && this.ConvolutionType == resizeLayer.ConvolutionType; + } + + /// + /// Returns a hash code value that represents this object. + /// + /// + /// A hash code that represents this object. + /// + public override int GetHashCode() + { + return this.Size.GetHashCode() + this.ConvolutionType.GetHashCode(); + } + } +} diff --git a/src/Plugins/ImageProcessor/ImageProcessor.Plugins.Cair/Imaging/EnergyFunction.cs b/src/Plugins/ImageProcessor/ImageProcessor.Plugins.Cair/Imaging/EnergyFunction.cs new file mode 100644 index 000000000..f9e5a2f56 --- /dev/null +++ b/src/Plugins/ImageProcessor/ImageProcessor.Plugins.Cair/Imaging/EnergyFunction.cs @@ -0,0 +1,29 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) James South. +// Licensed under the Apache License, Version 2.0. +// +// +// Enumerates the energy functions available to the resize method. +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace ImageProcessor.Plugins.Cair.Imaging +{ + /// + /// Enumerates the energy functions available to the resize method. + /// + public enum EnergyFunction + { + /// + /// The standard energy function. + /// + Backward = 0, + + /// + /// The forward energy function. A look-ahead is performed to reduce jagged edges + /// caused by removing areas of low energy. + /// + Forward = 1 + } +} diff --git a/src/Plugins/ImageProcessor/ImageProcessor.Plugins.Cair/Processors/ContentAwareResize.cs b/src/Plugins/ImageProcessor/ImageProcessor.Plugins.Cair/Processors/ContentAwareResize.cs new file mode 100644 index 000000000..c85f5b660 --- /dev/null +++ b/src/Plugins/ImageProcessor/ImageProcessor.Plugins.Cair/Processors/ContentAwareResize.cs @@ -0,0 +1,239 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) James South. +// Licensed under the Apache License, Version 2.0. +// +// +// Resizes an image to the given dimensions using content aware resizing. +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace ImageProcessor.Plugins.Cair.Processors +{ + using System; + using System.Collections.Generic; + using System.Diagnostics; + using System.Drawing; + using System.Drawing.Imaging; + using System.Globalization; + using System.IO; + + using ImageProcessor.Common.Exceptions; + using ImageProcessor.Imaging; + using ImageProcessor.Plugins.Cair.Imaging; + using ImageProcessor.Processors; + + /// + /// Resizes an image to the given dimensions using content aware resizing. + /// + public class ContentAwareResize : IGraphicsProcessor + { + /// + /// Initializes a new instance of the class. + /// + public ContentAwareResize() + { + this.Settings = new Dictionary(); + } + + /// + /// Gets or sets DynamicParameter. + /// + public dynamic DynamicParameter + { + get; + set; + } + + /// + /// Gets or sets any additional settings required by the processor. + /// + public Dictionary Settings + { + get; + set; + } + + /// + /// Processes the image. + /// + /// + /// The current instance of the class containing + /// the image to process. + /// + /// + /// The processed image from the current instance of the class. + /// + public System.Drawing.Image ProcessImage(ImageFactory factory) + { + string fileName = Guid.NewGuid().ToString(); + + // Use bmp's as the temporary files since they are lossless and support transparency. + string sourcePath = Path.Combine(CairBootstrapper.CairImagePath, fileName + ".bmp"); + string resizedPath = Path.Combine(CairBootstrapper.CairImagePath, fileName + "-r.bmp"); + + // Gather the parameters. + int width = this.DynamicParameter.Size.Width ?? 0; + int height = this.DynamicParameter.Size.Height ?? 0; + ContentAwareResizeConvolutionType convolutionType = this.DynamicParameter.ConvolutionType; + EnergyFunction energyFunction = this.DynamicParameter.EnergyFunction; + bool prescale = this.DynamicParameter.PreScale; + bool parallelize = this.DynamicParameter.Parallelize; + int timeout = this.DynamicParameter.Timeout ?? 60000; + + int defaultMaxWidth; + int defaultMaxHeight; + + int.TryParse(this.Settings["MaxWidth"], NumberStyles.Any, CultureInfo.InvariantCulture, out defaultMaxWidth); + int.TryParse(this.Settings["MaxHeight"], NumberStyles.Any, CultureInfo.InvariantCulture, out defaultMaxHeight); + + Bitmap newImage = null; + Image image = factory.Image; + + try + { + int sourceWidth = image.Width; + int sourceHeight = image.Height; + + // Fractional variants for preserving aspect ratio. + double percentHeight = Math.Abs(height / (double)sourceHeight); + double percentWidth = Math.Abs(width / (double)sourceWidth); + + int maxWidth = defaultMaxWidth > 0 ? defaultMaxWidth : int.MaxValue; + int maxHeight = defaultMaxHeight > 0 ? defaultMaxHeight : int.MaxValue; + + // If height or width is not passed we assume that the standard ratio is to be kept. + if (height == 0) + { + height = (int)Math.Ceiling(sourceHeight * percentWidth); + } + + if (width == 0) + { + width = (int)Math.Ceiling(sourceWidth * percentHeight); + } + + if (width > 0 && height > 0 && width <= maxWidth && height <= maxHeight) + { + if (prescale) + { + if (width < image.Width || height < image.Height) + { + int preWidth = Math.Min(image.Width, width + 50); //(int)Math.Ceiling(width * 1.25)); + ResizeLayer layer = new ResizeLayer(new Size(preWidth, 0)); + Dictionary resizeSettings = new Dictionary + { + { + "MaxWidth", image.Width.ToString("G") + }, + { + "MaxHeight", image.Height.ToString("G") + } + }; + Resize resize = new Resize { DynamicParameter = layer, Settings = resizeSettings }; + image = resize.ProcessImage(factory); + } + } + + // Save the temporary bitmap. + image.Save(sourcePath, ImageFormat.Bmp); + + // Process the image using the CAIR executable. + string arguments = string.Format( + " -I \"{0}\" -O \"{1}\" -C {2} -X {3} -Y {4} -E {5} -T {6}", + sourcePath, + resizedPath, + (int)convolutionType, + width, + height, + (int)energyFunction, + parallelize ? Math.Min(4, Environment.ProcessorCount) : 1); + + bool success = this.ProcessCairImage(arguments, timeout); + + if (!success) + { + throw new ImageProcessingException( + "Error processing image with " + this.GetType().Name + " due to timeout."); + } + + // Assign the new image. + newImage = new Bitmap(resizedPath); + newImage.MakeTransparent(); + + // Reassign the image. + image.Dispose(); + image = newImage; + } + } + catch (Exception ex) + { + if (newImage != null) + { + newImage.Dispose(); + } + + throw new ImageProcessingException("Error processing image with " + this.GetType().Name, ex); + } + finally + { + FileInfo sourceFileInfo = new FileInfo(sourcePath); + if (sourceFileInfo.Exists) + { + sourceFileInfo.Delete(); + } + + FileInfo resizedFileInfo = new FileInfo(resizedPath); + if (resizedFileInfo.Exists) + { + resizedFileInfo.Delete(); + } + } + + return image; + } + + /// + /// The process cair image. + /// + /// + /// The arguments. + /// + /// + /// The time in milliseconds to attempt to resize the image for. + /// + /// + /// The . + /// + private bool ProcessCairImage(string arguments, int timeout) + { + // Set up and start a new process to resize the image. + ProcessStartInfo start = new ProcessStartInfo(CairBootstrapper.CairPath, arguments) + { + WindowStyle = ProcessWindowStyle.Hidden, + UseShellExecute = false, + RedirectStandardInput = true, + RedirectStandardError = true, + RedirectStandardOutput = true, + CreateNoWindow = true, + }; + + using (Process process = Process.Start(start)) + { + if (process != null) + { + bool result = process.WaitForExit(timeout); + + if (!result) + { + process.Kill(); + } + + return result; + } + } + + return false; + } + } +} diff --git a/src/Plugins/ImageProcessor/ImageProcessor.Plugins.Cair/Properties/AssemblyInfo.cs b/src/Plugins/ImageProcessor/ImageProcessor.Plugins.Cair/Properties/AssemblyInfo.cs new file mode 100644 index 000000000..2926ca75d --- /dev/null +++ b/src/Plugins/ImageProcessor/ImageProcessor.Plugins.Cair/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("ImageProcessor.Plugins.Cair")] +[assembly: AssemblyDescription("Adds Content Aware Image Resizing to ImageProcessor")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("ImageProcessor.Plugins.Cair")] +[assembly: AssemblyCopyright("Copyright James South © 2014")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("e0e88a19-d3ea-4f9c-ab3d-8c871359dc59")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/src/Plugins/ImageProcessor/ImageProcessor.Plugins.Cair/Resources/Unmanaged/x86/CAIR.exe.REMOVED.git-id b/src/Plugins/ImageProcessor/ImageProcessor.Plugins.Cair/Resources/Unmanaged/x86/CAIR.exe.REMOVED.git-id new file mode 100644 index 000000000..9d07329a4 --- /dev/null +++ b/src/Plugins/ImageProcessor/ImageProcessor.Plugins.Cair/Resources/Unmanaged/x86/CAIR.exe.REMOVED.git-id @@ -0,0 +1 @@ +83a4594cf9aeb54e509a1cd04528e414eb673161 \ No newline at end of file diff --git a/src/Plugins/ImageProcessor/ImageProcessor.Plugins.Cair/Resources/Unmanaged/x86/GPL.txt b/src/Plugins/ImageProcessor/ImageProcessor.Plugins.Cair/Resources/Unmanaged/x86/GPL.txt new file mode 100644 index 000000000..594162448 --- /dev/null +++ b/src/Plugins/ImageProcessor/ImageProcessor.Plugins.Cair/Resources/Unmanaged/x86/GPL.txt @@ -0,0 +1,473 @@ +CAIR - Content Aware Image Resizer +Copyright (C) 2008 Joseph Auman (brain.recall@gmail.com) +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + + + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, +not price. Our General Public Licenses are designed to make sure that +you have the freedom to distribute copies of free software (and charge +for this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS diff --git a/src/Plugins/ImageProcessor/ImageProcessor.Plugins.Cair/Resources/Unmanaged/x86/ReadMe.txt b/src/Plugins/ImageProcessor/ImageProcessor.Plugins.Cair/Resources/Unmanaged/x86/ReadMe.txt new file mode 100644 index 000000000..2da7fd858 --- /dev/null +++ b/src/Plugins/ImageProcessor/ImageProcessor.Plugins.Cair/Resources/Unmanaged/x86/ReadMe.txt @@ -0,0 +1,282 @@ +User's ReadMe v2.18 + +CAIR - Content Aware Image Resizer +Copyright (C) 2008 Joseph Auman (brain.recall@gmail.com) + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + ++=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + +CAIR is an image resizing library that is based on the works of Shai Avidan and +Ariel Shamir. It is a high-performance multi-threaded library written in C++. +It is intended to be multi-platform and multi-architecture. + + +I am looking into implementing Poisson image reconstruction, which is mentioned +in the paper, to be used in CAIR_HD(). See the paper on the subject here: +http://research.microsoft.com/vision/cambridge/papers/perez_siggraph03.pdf +However, I’m having a bit of difficulty understanding the method and how I can +apply it to seam removal. If you know something about digital image processing +and are willing to help, please email me at brain.recall@gmail.com + + +Compiling CAIR is not difficult. A Makefile for Linux is included to demonstrate. +Compiling under Visual Studio is a bit different, since the pthread DLL library +and object library must be included for the linker. I suggest Google to see how +it's done. Whenever possible, I *highly* suggest using the Intel C++ compiler, +which gives about a 10% speed boost when all the optimization options are +turned on. It's freely available for the Linux platform, but Windows and Mac +license are in the $600 range outside of the 30 day trial. + ++=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + +In this file I'm going to present each file and its functions. This is going to +targeted at "users" of the library (those actually making a GUI with it). Further +detail can be gained by reading the source code (don't worry, I take *some* pride +in my comments, but pthread experience would be helpful). + + +CAIR_CML.h +================================================================================= +The CAIR Matrix Library. A template class used to hold the image information +in CAIR. The CML requires a size when creating the object. See main.cpp for +some examples in declaring and interfacing with the CML_Matrix. + +- Depends on: nothing outside of the STL + +- Types defined: +-- CML_byte - An unsigned char used for each color channel. +-- CML_RGBA - Structure for a 32 bit color pixel. + - Each channel is a CML_byte, named as: red, green, blue, alpha +-- CML_color - A color matrix, replaces CML_Matrix; use for images. +-- CML_int - An integer matrix, replaces CML_Matrix; use for weights. + +- Methods (the important ones, at least): +-- CML_Matrix( int x, int y ) +--- Simple constructor. Requires the intended size of the matrix (can be changed + later, so dummy values of (1,1) could be used). +-- void Fill( T value ) +--- Sets all elements of the matrix to the given value. +-- operator()( int x, int y ) +--- Accessor and assignment methods, used to set and get matrix values. +--- These have no bounds checking. +-- int Width() +--- Returns the width of the matrix. +-- int Height() +--- Returns the height of the matrix. +-- void Transpose( CML_Matrix * Source ) +--- Rotates Source on edge, storing the result into the matrix. +-- T Get( int x, int y ) +--- Accessor function with full bounds checking. Out-of-bound accesses will be + constrained back into the matrix. +-- void D_Resize( int x, int y ) +--- Destructively resize the matrix to the given values. +-- void Resize_Width( int x ) +--- Careful with this one. Performs non-destructive "resizing" but only in the x + direction. Essentially only changes what Width() will report. Enlarging should + be done only after a Reserve(), for performance reasons. +-- void Shift_Row( int x, int y, int shift ) +--- Shift the elements of a row, starting the (x,y) element. Shift determines + amount of shift and direction. Negative will shift left, positive for right. + + + +CAIR.h +================================================================================= +The CAIR function declarations. + +Depends on: CAIR_CML.h +Types defined: +-- CAIR_NUM_THREADS - The number of default threads that will be used for Grayscale, Edge, and Add/Remove operations. +-- CAIR_direction - An enumeration for CAIR_Removal() with the values of AUTO, + VERTICAL, and HORIZONTAL. AUTO lets CAIR_Remvoal() determine + the best direction to remove seams. VERTICAL and HORIZONTAL + force the function to remove from their respective directions. +-- CAIR_convolution - An enumeration for all CAIR operations. It defines the available + convolution kernels. They include: + Prewitt: An X-Y kernel for decent edge detection. + Sobel: Works very much like Prewitt. + V1: Only the X-component of the Prewitt. More of an object detector + than strictly edges. Works well under some cases. + V_SQUARE: The result of V1 squared. This provides some of the + best object detection, thus some of the best operation. + Laplacian: A second-order edge detector. Nothing spectacular. +-- CAIR_energy - An enumeration for all CAIR energy algorithms. + Backward: The traditional energy algorithm. + Forward: The new energy algorithm that determines future edge changes and tries + to redirect seams away from potential artifacts. Comes at a slight performance hit. + +Functions: +- void CAIR_Threads( int thread_count ) +-- thread_count: the number of threads that the Grayscale/Edge/Add/Remove operations should use. Minimum of two. + +- bool CAIR( CML_color * Source, + CML_int * S_Weights, + int goal_x, + int goal_y, + CAIR_convolution conv, + CAIR_energy ener, + CML_int * D_Weights, + CML_color * Dest, + bool (*CAIR_callback)(float) ) +-- Source: pointer to the source image +-- S_Weights: pointer to the weights of the image, must be the same size as Source + The weights allow for linear protection and removal of desired portions of an + image. The values of the weights should not exceed -2,000,000 to 2,000,000 to + avoid integer overflows. Generally, I found a -10,000 to 10,000 range to be + adequate. Large values will protect pixel, while small values will make it + more likely to be removed first. ALWAYS use negative values for removal. When + no preference is given to a pixel, leave its value to zero. (I suggest Fill()'ing + the weight matrix with 0 before use, since the memory is not initialized when + allocated.) +-- goal_x: the desired width of the Dest image +-- goal_y: the desired height of the Dest image +-- conv: The possible convolution kernels to use. See the above discussion. + It is important to note that if using V_SQUARE the weights must be at least an order + of magnitude larger for similar operation. add_weight needs to be several orders of + magnitude larger to avoid some stretching. This is because V_SQUARE produces larger + edge values, and thus large energy values. +-- ener: The possible energy algorithms to use. See the above discussion. +-- D_Weights: pointer to the Destination Weights (contents will be destroyed) +-- Dest: pointer to the Destination image (contents will be destroyed) +-- CAIR_callback: a function pointer to a status/callback system. The function is expected + to take a float of the percent complete (from 0 to 1) and is to return a false if the + resize is to be canceled, or true otherwise. If the resize is canceled, CAIR() will return + a false, leaving Dest and D_Weights in an unknown state. Set to NULL if not used. +-- RETURNS: true if the resize ran to completion, false if it was canceled by CAIR_callback. + +- void CAIR_Grayscale( CML_color * Source, CML_color * Dest ) +-- Source: pointer to the source image +-- Dest: The grayscale of Source image. The gray value will be computed, then applied + to the three color channels to give the grayscale equivalent. +- void CAIR_Edge( CML_color * Source, CAIR_convolution conv, CML_color * Dest ) +-- Source: pointer to the source image +-- conv: The edge detection kernel. +-- Dest: The dge detection of the source image. Values larger than a CML_byte + (255 in decimal) will be clipped down to 255. + +- CAIR_V_Energy( CML_color * Source, CAIR_convolution conv, CAIR_energy ener, CML_color * Dest ) and CAIR_H_Energy( CML_color * Source, CAIR_convolution conv, CAIR_energy ener, CML_color * Dest ) +-- Source: pointer to the source image +-- conv: The edge detection kernel. +-- ener: The energy algorithm. +-- Dest: The grayscale equivalent of the energy map of the source image. All values + are scaled down realtive to the largest value. Weights are assumed all zero, + since when they are not they dominate the image and produce uninteresting results. + +- bool CAIR_Removal( CML_color * Source, + CML_int * S_Weights, + CAIR_direction choice, + int max_attempts, + CAIR_convolution conv, + CAIR_energy ener, + CML_int * D_Weights, + CML_color * Dest, + bool (*CAIR_callback)(float) ) +-- EXPERIMENTAL +-- S_Weights: pointer to the given weights of the image +-- choice: How the algorithm will remove the seams. In AUTO mode, it will count the + negative rows (for horizontal removal) and the negative columns (for vertical removal) + and then removes the least amount in that direction. Other settings will cause it to + remove in thier respective directions. After the removal, it is expanded back out to + its origional dimensions. +-- max_attempts: The number of retries the algorithm will do to remove remaining negative + weights. Sometimes the algorithm may not remove everything in one pass, and this attempts + to give the algorithm another chance at it. There are situations, however, where the + algorithm will not be able to remove the requested portions due to other areas makred + for protection with a high weight. +-- conv: The edge detection kernel. +-- ener: The energy algorithm. +-- D_Weights: pointer to the destination weights +-- Dest: pointer to the destination image +-- CAIR_callback: a function pointer to a status/callback system +-- RETURNS: true if the resize ran to completion, false if it was canceled by CAIR_callback. + +- bool CAIR_HD( CML_color * Source, + CML_int * S_Weights, + int goal_x, + int goal_y, + CAIR_convolution conv, + CAIR_energy ener, + CML_int * D_Weights, + CML_color * Dest, + bool (*CAIR_callback)(float) ) +-- See CAIR() for the same paramaters. +-- CAIR_HD() is designed for quality, not speed. At each itteration, CAIR_HD() + determines which direction produces the least energy path for removal. It then + removes that path. CAIR_HD() can enlarge, but currently employs standard CAIR() + to perform it. + +CAIR.cpp +================================================================================= +The CAIR function definitions. Nothing really important to the user, except its +dependencies. + +Depends on: CAIR_CML.h, CAIR.h, pthread.h +Types defined: none visible +Functions: none visible + + + +main.cpp +================================================================================= +An example application that uses CAIR (mostly for testing by me). Functions to +read the source on are BMP_to_CML() and CML_to_BMP() to get an example on how to +convert to and from the CML. + +- Depends on: CAIR_CML.h, CAIR.h, EasyBMP.h +Types defined: none +Functions: nothing really important + + ++=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ +Content Amplification + +This is described in the paper, but I'll mention it here as well. This method +allows an object in the image to appear larger. Do this as following: +1) Enlarge an image using a standard linear technique by about 10% or so (more + than 25% might cause some artifacts). +2) Optional: Set a large weight for the desired object. +3) Seam carve the enlarged image back down to the origional size. + ++=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + + +Other Links: +http://brain.recall.googlepages.com/cair +http://c-a-i-r.wiki.sourceforge.net/ +http://sourceforge.net/projects/c-a-i-r/ +http://code.google.com/p/seam-carving-gui/ +http://www.faculty.idc.ac.il/arik/papers/imret.pdf +http://www.faculty.idc.ac.il/arik/papers/vidRet.pdf + +Special Thanks: +Ariel Shamir +Shai Avidan +Michael Rubinstein +Ramin Sabet +Brett Taylor +Gabe Rudy +Jean-Baptiste (Jib) +David Phillip Oster +Matt Newell +Klaus Nordby +Alexandre Prokoudine +Peter Berrington + +Further questions on CAIR can be directed to the source code, or my email. + +Sincerely, +Brain_ReCall aka Joe Auman +brain.recall@gmail.com diff --git a/src/Plugins/ImageProcessor/ImageProcessor.Plugins.Cair/Resources/Unmanaged/x86/pthreadVSE2.dll.REMOVED.git-id b/src/Plugins/ImageProcessor/ImageProcessor.Plugins.Cair/Resources/Unmanaged/x86/pthreadVSE2.dll.REMOVED.git-id new file mode 100644 index 000000000..c52d6fc50 --- /dev/null +++ b/src/Plugins/ImageProcessor/ImageProcessor.Plugins.Cair/Resources/Unmanaged/x86/pthreadVSE2.dll.REMOVED.git-id @@ -0,0 +1 @@ +af74faa46395cff6167217e471d0e9d8108bc829 \ No newline at end of file diff --git a/src/Plugins/ImageProcessor/ImageProcessor.Plugins.Cair/Settings.StyleCop b/src/Plugins/ImageProcessor/ImageProcessor.Plugins.Cair/Settings.StyleCop new file mode 100644 index 000000000..50b7964dd --- /dev/null +++ b/src/Plugins/ImageProcessor/ImageProcessor.Plugins.Cair/Settings.StyleCop @@ -0,0 +1,9 @@ + + + + cair + laplacian + sobel + + + \ No newline at end of file diff --git a/src/Plugins/ImageProcessor/ImageProcessor.Plugins.WebP/Imaging/Formats/NativeMethods.cs b/src/Plugins/ImageProcessor/ImageProcessor.Plugins.WebP/Imaging/Formats/NativeMethods.cs index a04c44923..a3add3488 100644 --- a/src/Plugins/ImageProcessor/ImageProcessor.Plugins.WebP/Imaging/Formats/NativeMethods.cs +++ b/src/Plugins/ImageProcessor/ImageProcessor.Plugins.WebP/Imaging/Formats/NativeMethods.cs @@ -29,14 +29,15 @@ namespace ImageProcessor.Plugins.WebP.Imaging.Formats { string folder = ImageProcessorBootstrapper.Instance.NativeBinaryFactory.Is64BitEnvironment ? "x64" : "x86"; string name = string.Format("ImageProcessor.Plugins.WebP.Resources.Unmanaged.{0}.libwebp.dll", folder); - Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(name); - - using (MemoryStream memoryStream = new MemoryStream()) + using (Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(name)) { - if (stream != null) + using (MemoryStream memoryStream = new MemoryStream()) { - stream.CopyTo(memoryStream); - ImageProcessorBootstrapper.Instance.NativeBinaryFactory.RegisterNativeBinary("libwebp.dll", memoryStream.ToArray()); + if (stream != null) + { + stream.CopyTo(memoryStream); + ImageProcessorBootstrapper.Instance.NativeBinaryFactory.RegisterNativeBinary("libwebp.dll", memoryStream.ToArray()); + } } } } diff --git a/src/Plugins/ImageProcessor/ImageProcessor.Plugins.WebP/Properties/AssemblyInfo.cs b/src/Plugins/ImageProcessor/ImageProcessor.Plugins.WebP/Properties/AssemblyInfo.cs index 8fe6f724f..0f4b2367b 100644 --- a/src/Plugins/ImageProcessor/ImageProcessor.Plugins.WebP/Properties/AssemblyInfo.cs +++ b/src/Plugins/ImageProcessor/ImageProcessor.Plugins.WebP/Properties/AssemblyInfo.cs @@ -32,5 +32,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("1.0.*")] -[assembly: AssemblyVersion("1.0.0.0")] -[assembly: AssemblyFileVersion("1.0.0.0")] +[assembly: AssemblyVersion("1.0.1.0")] +[assembly: AssemblyFileVersion("1.0.1.0")] From c594ab05d86628244a7dac04e44b2b6aa90fbcb4 Mon Sep 17 00:00:00 2001 From: michael-mason Date: Tue, 2 Sep 2014 16:35:28 +1000 Subject: [PATCH 2/3] fix for allowing the loading of mac tiffs Former-commit-id: de78a6432aff5284ac8eda35a9b14176c97c61a2 --- src/ImageProcessor/Imaging/Formats/TiffFormat.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ImageProcessor/Imaging/Formats/TiffFormat.cs b/src/ImageProcessor/Imaging/Formats/TiffFormat.cs index e761bc4b3..59229dd88 100644 --- a/src/ImageProcessor/Imaging/Formats/TiffFormat.cs +++ b/src/ImageProcessor/Imaging/Formats/TiffFormat.cs @@ -29,8 +29,8 @@ namespace ImageProcessor.Imaging.Formats { return new[] { - new byte[] { 73, 73, 42 }, - new byte[] { 77, 77, 42 } + new byte[] { 73, 73, 42, 0 }, + new byte[] { 77, 77, 0, 42 } }; } } From 090650c9ae569516a25b45860b564554d4c256d7 Mon Sep 17 00:00:00 2001 From: James South Date: Thu, 4 Sep 2014 14:38:40 +0100 Subject: [PATCH 3/3] ImageProcessor v2.1.0 WebP v1.0.1 Former-commit-id: 25d77e459f11790a9251f3169fae9b66b3bd9887 --- build/Build.bat | 4 ++-- src/ImageProcessor.Web/Properties/AssemblyInfo.cs | 2 +- src/ImageProcessor/Properties/AssemblyInfo.cs | 6 +++--- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/build/Build.bat b/build/Build.bat index 0014058f0..f5ec6373b 100644 --- a/build/Build.bat +++ b/build/Build.bat @@ -1,9 +1,9 @@ @ECHO OFF -SET version=2.0.0.0 +SET version=2.0.1.0 SET webversion=4.0.0.0 SET webconfigversion=2.0.0.0 -SET webppluginversion=1.0.0.0 +SET webppluginversion=1.0.1.0 ECHO Building ImageProcessor %version%, ImageProcessor.Web %webversion%, ImageProcessor.Web.Config %webconfigversion%, and ImageProcessor.Plugins.WebP %webppluginversion% diff --git a/src/ImageProcessor.Web/Properties/AssemblyInfo.cs b/src/ImageProcessor.Web/Properties/AssemblyInfo.cs index 4f1c51a1e..89ec3b951 100644 --- a/src/ImageProcessor.Web/Properties/AssemblyInfo.cs +++ b/src/ImageProcessor.Web/Properties/AssemblyInfo.cs @@ -1,4 +1,4 @@ -// -------------------------------------------------------------------------------------------------------------------- +// -------------------------------------------------------------------------------------------------------------------- // // Copyright (c) James South. // Licensed under the Apache License, Version 2.0. diff --git a/src/ImageProcessor/Properties/AssemblyInfo.cs b/src/ImageProcessor/Properties/AssemblyInfo.cs index 9fc155a5a..bbdf7129e 100644 --- a/src/ImageProcessor/Properties/AssemblyInfo.cs +++ b/src/ImageProcessor/Properties/AssemblyInfo.cs @@ -1,4 +1,4 @@ -// -------------------------------------------------------------------------------------------------------------------- +// -------------------------------------------------------------------------------------------------------------------- // // Copyright (c) James South. // Licensed under the Apache License, Version 2.0. @@ -40,5 +40,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.0.0.0")] -[assembly: AssemblyFileVersion("2.0.0.0")] \ No newline at end of file +[assembly: AssemblyVersion("2.0.1.0")] +[assembly: AssemblyFileVersion("2.0.1.0")] \ No newline at end of file