Skip to content

Commit e844556

Browse files
committed
New UseCase - Complete ImageResizer SPA App in 1 page C# + 1 static html page
1 parent 1fde9f8 commit e844556

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

44 files changed

+13485
-0
lines changed

ImageResizer/ImageResizer.sln

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
2+
Microsoft Visual Studio Solution File, Format Version 12.00
3+
# Visual Studio 2012
4+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ImageResizer", "ImageResizer\ImageResizer.csproj", "{6F4EF73A-7D66-4BA6-9708-8C49DBCDE229}"
5+
EndProject
6+
Global
7+
GlobalSection(SolutionConfigurationPlatforms) = preSolution
8+
Debug|Any CPU = Debug|Any CPU
9+
Release|Any CPU = Release|Any CPU
10+
EndGlobalSection
11+
GlobalSection(ProjectConfigurationPlatforms) = postSolution
12+
{6F4EF73A-7D66-4BA6-9708-8C49DBCDE229}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
13+
{6F4EF73A-7D66-4BA6-9708-8C49DBCDE229}.Debug|Any CPU.Build.0 = Debug|Any CPU
14+
{6F4EF73A-7D66-4BA6-9708-8C49DBCDE229}.Release|Any CPU.ActiveCfg = Release|Any CPU
15+
{6F4EF73A-7D66-4BA6-9708-8C49DBCDE229}.Release|Any CPU.Build.0 = Release|Any CPU
16+
EndGlobalSection
17+
GlobalSection(SolutionProperties) = preSolution
18+
HideSolutionNode = FALSE
19+
EndGlobalSection
20+
EndGlobal
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
2+
<s:String x:Key="/Default/FilterSettingsManager/CoverageFilterXml/@EntryValue">&lt;data&gt;&lt;IncludeFilters /&gt;&lt;ExcludeFilters /&gt;&lt;/data&gt;</s:String>
3+
<s:String x:Key="/Default/FilterSettingsManager/AttributeFilterXml/@EntryValue">&lt;data /&gt;</s:String></wpf:ResourceDictionary>
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
<%@ Application Codebehind="Global.asax.cs" Inherits="ImageResizer.Global" Language="C#" %>
Lines changed: 193 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,193 @@
1+
using System;
2+
using System.Drawing.Imaging;
3+
using System.IO;
4+
using System.Linq;
5+
using System.Security.Cryptography;
6+
using System.Text;
7+
using Funq;
8+
using ServiceStack.Common;
9+
using ServiceStack.Common.Utils;
10+
using ServiceStack.Common.Web;
11+
using ServiceStack.ServiceHost;
12+
using ServiceStack.ServiceInterface;
13+
using ServiceStack.Text;
14+
using ServiceStack.WebHost.Endpoints;
15+
using System.Drawing;
16+
using System.Drawing.Drawing2D;
17+
18+
//Entire C# source code for ImageResizer backend - there is no other .cs :)
19+
namespace ImageResizer
20+
{
21+
[Route("/upload")]
22+
public class Upload
23+
{
24+
public string Url { get; set; }
25+
}
26+
27+
[Route("/images")]
28+
public class Images { }
29+
30+
[Route("/resize/{Id}")]
31+
public class Resize
32+
{
33+
public string Id { get; set; }
34+
public string Size { get; set; }
35+
}
36+
37+
public class ImageService : Service
38+
{
39+
const int ThumbnailSize = 100;
40+
readonly string UploadsDir = "~/uploads".MapHostAbsolutePath();
41+
readonly string ThumbnailsDir = "~/uploads/thumbnails".MapHostAbsolutePath();
42+
43+
public object Get(Images request)
44+
{
45+
return Directory.GetFiles(UploadsDir).SafeConvertAll(x => x.SplitOnLast(Path.DirectorySeparatorChar).Last());
46+
}
47+
48+
public object Post(Upload request)
49+
{
50+
if (request.Url != null)
51+
{
52+
using (var ms = new MemoryStream(request.Url.GetBytesFromUrl()))
53+
{
54+
WriteImage(ms);
55+
}
56+
}
57+
58+
foreach (var uploadedFile in RequestContext.Files.Where(uploadedFile => uploadedFile.ContentLength > 0))
59+
{
60+
using (var ms = new MemoryStream())
61+
{
62+
uploadedFile.WriteTo(ms);
63+
WriteImage(ms);
64+
}
65+
}
66+
67+
return HttpResult.Redirect("/");
68+
}
69+
70+
private void WriteImage(Stream ms)
71+
{
72+
var hash = GetMd5Hash(ms);
73+
74+
ms.Position = 0;
75+
var fileName = hash + ".png";
76+
using (var img = Image.FromStream(ms))
77+
{
78+
img.Save(UploadsDir.CombineWith(fileName));
79+
80+
var stream = Resize(img, ThumbnailSize, ThumbnailSize);
81+
File.WriteAllBytes(ThumbnailsDir.CombineWith(fileName), stream.ReadFully());
82+
}
83+
}
84+
85+
[AddHeader(ContentType = "image/jpg")]
86+
public object Get(Resize request)
87+
{
88+
var imagePath = UploadsDir.CombineWith(request.Id + ".png");
89+
if (request.Id == null || !File.Exists(imagePath))
90+
throw HttpError.NotFound(request.Id + " was not found");
91+
92+
using (var stream = File.OpenRead(imagePath))
93+
using (var img = Image.FromStream(stream))
94+
{
95+
96+
var parts = request.Size == null ? null : request.Size.Split('x');
97+
int width = img.Width;
98+
int height = img.Height;
99+
100+
if (parts != null && parts.Length > 0)
101+
int.TryParse(parts[0], out width);
102+
103+
if (parts != null && parts.Length > 1)
104+
int.TryParse(parts[1], out height);
105+
106+
return Resize(img, width, height);
107+
}
108+
}
109+
110+
public static string GetMd5Hash(Stream stream)
111+
{
112+
var hash = MD5.Create().ComputeHash(stream);
113+
var sb = new StringBuilder();
114+
for (var i = 0; i < hash.Length; i++)
115+
{
116+
sb.Append(hash[i].ToString("x2"));
117+
}
118+
return sb.ToString();
119+
}
120+
121+
public static Stream Resize(Image img, int newWidth, int newHeight)
122+
{
123+
if (newWidth != img.Width || newHeight != img.Height)
124+
{
125+
var ratioX = (double)newWidth / img.Width;
126+
var ratioY = (double)newHeight / img.Height;
127+
var ratio = Math.Max(ratioX, ratioY);
128+
129+
var width = (int)(img.Width * ratio);
130+
var height = (int)(img.Height * ratio);
131+
132+
var newImage = new Bitmap(width, height);
133+
Graphics.FromImage(newImage).DrawImage(img, 0, 0, width, height);
134+
img = newImage;
135+
136+
if (img.Width != newWidth || img.Height != newHeight)
137+
{
138+
var startX = (Math.Max(img.Width, newWidth) - Math.Min(img.Width, newWidth)) / 2;
139+
var startY = (Math.Max(img.Height, newHeight) - Math.Min(img.Height, newHeight)) / 2;
140+
img = Crop(img, newWidth, newHeight, startX, startY);
141+
}
142+
}
143+
144+
var ms = new MemoryStream();
145+
img.Save(ms, ImageFormat.Png);
146+
ms.Position = 0;
147+
return ms;
148+
}
149+
150+
public static Image Crop(Image Image, int newWidth, int newHeight, int startX = 0, int startY = 0)
151+
{
152+
if (Image.Height < newHeight)
153+
newHeight = Image.Height;
154+
155+
if (Image.Width < newWidth)
156+
newWidth = Image.Width;
157+
158+
using (var bmp = new Bitmap(newWidth, newHeight, PixelFormat.Format24bppRgb))
159+
{
160+
bmp.SetResolution(72, 72);
161+
using (var g = Graphics.FromImage(bmp))
162+
{
163+
g.SmoothingMode = SmoothingMode.AntiAlias;
164+
g.InterpolationMode = InterpolationMode.HighQualityBicubic;
165+
g.PixelOffsetMode = PixelOffsetMode.HighQuality;
166+
g.DrawImage(Image, new Rectangle(0, 0, newWidth, newHeight), startX, startY, newWidth, newHeight, GraphicsUnit.Pixel);
167+
168+
using (var ms = new MemoryStream())
169+
{
170+
bmp.Save(ms, ImageFormat.Png);
171+
Image.Dispose();
172+
var outimage = Image.FromStream(ms);
173+
return outimage;
174+
}
175+
}
176+
}
177+
}
178+
}
179+
180+
public class AppHost : AppHostBase
181+
{
182+
public AppHost() : base("Image Resizer", typeof(AppHost).Assembly) {}
183+
public override void Configure(Container container) {}
184+
}
185+
186+
public class Global : System.Web.HttpApplication
187+
{
188+
protected void Application_Start(object sender, EventArgs e)
189+
{
190+
new AppHost().Init();
191+
}
192+
}
193+
}
Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
3+
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
4+
<PropertyGroup>
5+
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
6+
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
7+
<ProductVersion>
8+
</ProductVersion>
9+
<SchemaVersion>2.0</SchemaVersion>
10+
<ProjectGuid>{6F4EF73A-7D66-4BA6-9708-8C49DBCDE229}</ProjectGuid>
11+
<ProjectTypeGuids>{349c5851-65df-11da-9384-00065b846f21};{fae04ec0-301f-11d3-bf4b-00c04f79efbc}</ProjectTypeGuids>
12+
<OutputType>Library</OutputType>
13+
<AppDesignerFolder>Properties</AppDesignerFolder>
14+
<RootNamespace>ImageResizer</RootNamespace>
15+
<AssemblyName>ImageResizer</AssemblyName>
16+
<TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
17+
<UseIISExpress>true</UseIISExpress>
18+
<IISExpressSSLPort />
19+
<IISExpressAnonymousAuthentication />
20+
<IISExpressWindowsAuthentication />
21+
<IISExpressUseClassicPipelineMode />
22+
<TargetFrameworkProfile />
23+
</PropertyGroup>
24+
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
25+
<DebugSymbols>true</DebugSymbols>
26+
<DebugType>full</DebugType>
27+
<Optimize>false</Optimize>
28+
<OutputPath>bin\</OutputPath>
29+
<DefineConstants>DEBUG;TRACE</DefineConstants>
30+
<ErrorReport>prompt</ErrorReport>
31+
<WarningLevel>4</WarningLevel>
32+
</PropertyGroup>
33+
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
34+
<DebugType>pdbonly</DebugType>
35+
<Optimize>true</Optimize>
36+
<OutputPath>bin\</OutputPath>
37+
<DefineConstants>TRACE</DefineConstants>
38+
<ErrorReport>prompt</ErrorReport>
39+
<WarningLevel>4</WarningLevel>
40+
</PropertyGroup>
41+
<ItemGroup>
42+
<Reference Include="ServiceStack">
43+
<HintPath>..\packages\ServiceStack.3.9.43\lib\net35\ServiceStack.dll</HintPath>
44+
</Reference>
45+
<Reference Include="ServiceStack.Common">
46+
<HintPath>..\packages\ServiceStack.Common.3.9.43\lib\net35\ServiceStack.Common.dll</HintPath>
47+
</Reference>
48+
<Reference Include="ServiceStack.Interfaces">
49+
<HintPath>..\packages\ServiceStack.Common.3.9.43\lib\net35\ServiceStack.Interfaces.dll</HintPath>
50+
</Reference>
51+
<Reference Include="ServiceStack.OrmLite">
52+
<HintPath>..\packages\ServiceStack.OrmLite.SqlServer.3.9.43\lib\ServiceStack.OrmLite.dll</HintPath>
53+
</Reference>
54+
<Reference Include="ServiceStack.OrmLite.SqlServer">
55+
<HintPath>..\packages\ServiceStack.OrmLite.SqlServer.3.9.43\lib\ServiceStack.OrmLite.SqlServer.dll</HintPath>
56+
</Reference>
57+
<Reference Include="ServiceStack.Redis">
58+
<HintPath>..\packages\ServiceStack.Redis.3.9.43\lib\net35\ServiceStack.Redis.dll</HintPath>
59+
</Reference>
60+
<Reference Include="ServiceStack.ServiceInterface">
61+
<HintPath>..\packages\ServiceStack.3.9.43\lib\net35\ServiceStack.ServiceInterface.dll</HintPath>
62+
</Reference>
63+
<Reference Include="ServiceStack.Text">
64+
<HintPath>..\packages\ServiceStack.Text.3.9.43\lib\net35\ServiceStack.Text.dll</HintPath>
65+
</Reference>
66+
<Reference Include="System.Data.DataSetExtensions" />
67+
<Reference Include="System.Web.DynamicData" />
68+
<Reference Include="System.Web.Entity" />
69+
<Reference Include="System.ComponentModel.DataAnnotations" />
70+
<Reference Include="System" />
71+
<Reference Include="System.Data" />
72+
<Reference Include="System.Web.Extensions" />
73+
<Reference Include="System.Drawing" />
74+
<Reference Include="System.Web" />
75+
<Reference Include="System.Xml" />
76+
<Reference Include="System.Configuration" />
77+
<Reference Include="System.Web.Services" />
78+
<Reference Include="System.EnterpriseServices" />
79+
<Reference Include="System.Xml.Linq" />
80+
</ItemGroup>
81+
<ItemGroup>
82+
<Content Include="default.html" />
83+
<Content Include="Global.asax" />
84+
<Content Include="Web.config" />
85+
</ItemGroup>
86+
<ItemGroup>
87+
<Compile Include="Global.asax.cs">
88+
<DependentUpon>Global.asax</DependentUpon>
89+
</Compile>
90+
<Compile Include="Properties\AssemblyInfo.cs" />
91+
</ItemGroup>
92+
<ItemGroup>
93+
<Content Include="packages.config" />
94+
</ItemGroup>
95+
<ItemGroup>
96+
<Folder Include="uploads\thumbnails\" />
97+
</ItemGroup>
98+
<PropertyGroup>
99+
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">10.0</VisualStudioVersion>
100+
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
101+
</PropertyGroup>
102+
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
103+
<Import Project="$(VSToolsPath)\WebApplications\Microsoft.WebApplication.targets" Condition="'$(VSToolsPath)' != ''" />
104+
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v10.0\WebApplications\Microsoft.WebApplication.targets" Condition="false" />
105+
<ProjectExtensions>
106+
<VisualStudio>
107+
<FlavorProperties GUID="{349c5851-65df-11da-9384-00065b846f21}">
108+
<WebProjectProperties>
109+
<UseIIS>True</UseIIS>
110+
<AutoAssignPort>True</AutoAssignPort>
111+
<DevelopmentServerPort>0</DevelopmentServerPort>
112+
<DevelopmentServerVPath>/</DevelopmentServerVPath>
113+
<IISUrl>http://localhost:52355/</IISUrl>
114+
<NTLMAuthentication>False</NTLMAuthentication>
115+
<UseCustomServer>False</UseCustomServer>
116+
<CustomServerUrl>
117+
</CustomServerUrl>
118+
<SaveServerSettingsInUserFile>False</SaveServerSettingsInUserFile>
119+
</WebProjectProperties>
120+
</FlavorProperties>
121+
</VisualStudio>
122+
</ProjectExtensions>
123+
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
124+
Other similar extension points exist, see Microsoft.Common.targets.
125+
<Target Name="BeforeBuild">
126+
</Target>
127+
<Target Name="AfterBuild">
128+
</Target>
129+
-->
130+
</Project>
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
using System.Reflection;
2+
using System.Runtime.CompilerServices;
3+
using System.Runtime.InteropServices;
4+
5+
// General Information about an assembly is controlled through the following
6+
// set of attributes. Change these attribute values to modify the information
7+
// associated with an assembly.
8+
[assembly: AssemblyTitle("ImageResizer")]
9+
[assembly: AssemblyDescription("")]
10+
[assembly: AssemblyConfiguration("")]
11+
[assembly: AssemblyCompany("")]
12+
[assembly: AssemblyProduct("ImageResizer")]
13+
[assembly: AssemblyCopyright("Copyright © 2013")]
14+
[assembly: AssemblyTrademark("")]
15+
[assembly: AssemblyCulture("")]
16+
17+
// Setting ComVisible to false makes the types in this assembly not visible
18+
// to COM components. If you need to access a type in this assembly from
19+
// COM, set the ComVisible attribute to true on that type.
20+
[assembly: ComVisible(false)]
21+
22+
// The following GUID is for the ID of the typelib if this project is exposed to COM
23+
[assembly: Guid("0d6f4db0-c289-4d2e-a8f0-e36d4f51b3fb")]
24+
25+
// Version information for an assembly consists of the following four values:
26+
//
27+
// Major Version
28+
// Minor Version
29+
// Build Number
30+
// Revision
31+
//
32+
// You can specify all the values or you can default the Revision and Build Numbers
33+
// by using the '*' as shown below:
34+
[assembly: AssemblyVersion("1.0.0.0")]
35+
[assembly: AssemblyFileVersion("1.0.0.0")]

0 commit comments

Comments
 (0)