forked from JimBobSquarePants/ImageProcessor
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathResize.cs
More file actions
215 lines (187 loc) · 8.45 KB
/
Copy pathResize.cs
File metadata and controls
215 lines (187 loc) · 8.45 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
// --------------------------------------------------------------------------------------------------------------------
// <copyright file="Resize.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South.
// Licensed under the Apache License, Version 2.0.
// </copyright>
// <summary>
// Resizes an image to the given dimensions.
// </summary>
// --------------------------------------------------------------------------------------------------------------------
namespace ImageProcessor.Web.Processors
{
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Drawing;
using System.Linq;
using System.Net;
using System.Text.RegularExpressions;
using System.Web;
using ImageProcessor.Imaging;
using ImageProcessor.Processors;
using ImageProcessor.Web.Helpers;
/// <summary>
/// Resizes an image to the given dimensions.
/// </summary>
public class Resize : IWebGraphicsProcessor
{
/// <summary>
/// The regular expression to search strings for.
/// </summary>
private static readonly Regex QueryRegex = new Regex(@"(width|height)=((.)?\d+|\d+(.\d+)?)+(px)?", RegexOptions.Compiled);
/// <summary>
/// Initializes a new instance of the <see cref="Resize"/> class.
/// </summary>
public Resize()
{
this.Processor = new ImageProcessor.Processors.Resize();
}
/// <summary>
/// Gets the regular expression to search strings for.
/// </summary>
public Regex RegexPattern => QueryRegex;
/// <summary>
/// Gets the order in which this processor is to be used in a chain.
/// </summary>
public int SortOrder { get; private set; }
/// <summary>
/// Gets the associated graphics processor.
/// </summary>
public IGraphicsProcessor Processor { get; }
/// <summary>
/// The position in the original string where the first character of the captured substring was found.
/// </summary>
/// <param name="queryString">
/// The query string to search.
/// </param>
/// <returns>
/// The zero-based starting position in the original string where the captured substring was found.
/// </returns>
public int MatchRegexIndex(string queryString)
{
this.SortOrder = int.MaxValue;
Match match = this.RegexPattern.Match(queryString);
if (match.Success)
{
this.SortOrder = match.Index;
NameValueCollection queryCollection = HttpUtility.ParseQueryString(queryString);
Size size = this.ParseSize(queryCollection);
ResizeMode mode = QueryParamParser.Instance.ParseValue<ResizeMode>(queryCollection["mode"]);
AnchorPosition position = QueryParamParser.Instance.ParseValue<AnchorPosition>(queryCollection["anchor"]);
bool upscale = queryCollection["upscale"] == null || QueryParamParser.Instance.ParseValue<bool>(queryCollection["upscale"]);
float[] center = queryCollection["center"] != null
? QueryParamParser.Instance.ParseValue<float[]>(queryCollection["center"]) :
new float[] { };
ResizeLayer resizeLayer = new ResizeLayer(size)
{
ResizeMode = mode,
AnchorPosition = position,
Upscale = upscale,
CenterCoordinates = center
};
this.Processor.DynamicParameter = resizeLayer;
// Correctly parse any restrictions.
string restrictions;
this.Processor.Settings.TryGetValue("RestrictTo", out restrictions);
List<Size> restrictedSizes = this.ParseRestrictions(restrictions);
if (restrictedSizes != null && restrictedSizes.Any())
{
bool reject = true;
foreach (Size restrictedSize in restrictedSizes)
{
if (restrictedSize.Height == 0 || restrictedSize.Width == 0)
{
if (restrictedSize.Width == size.Width || restrictedSize.Height == size.Height)
{
reject = false;
}
}
else if (restrictedSize.Width == size.Width && restrictedSize.Height == size.Height)
{
reject = false;
}
}
if (reject)
{
throw new HttpException((int)HttpStatusCode.Forbidden, string.Format("The given size: {0}x{1} is not allowed.", size.Width, size.Height));
}
}
((ImageProcessor.Processors.Resize)this.Processor).RestrictedSizes = this.ParseRestrictions(restrictions);
}
return this.SortOrder;
}
/// <summary>
/// Returns the correct <see cref="Size"/> for the given query collection.
/// </summary>
/// <param name="queryCollection">
/// The <see cref="NameValueCollection"/> containing the query parameters to parse.
/// </param>
/// <returns>
/// The <see cref="Size"/>.
/// </returns>
private Size ParseSize(NameValueCollection queryCollection)
{
string width = queryCollection["width"];
string height = queryCollection["height"];
string widthRatio = queryCollection["widthratio"];
string heightRatio = queryCollection["heightratio"];
Size size = new Size();
// Umbraco calls the API incorrectly so we have to deal with floats.
// We round up so that single pixel lines are not produced.
const MidpointRounding Rounding = MidpointRounding.AwayFromZero;
// First cater for single dimensions.
if (width != null && height == null)
{
width = width.Replace("px", string.Empty);
size = new Size((int)Math.Round(QueryParamParser.Instance.ParseValue<float>(width), Rounding), 0);
}
if (width == null && height != null)
{
height = height.Replace("px", string.Empty);
size = new Size(0, (int)Math.Round(QueryParamParser.Instance.ParseValue<float>(height), Rounding));
}
// Both supplied
if (width != null && height != null)
{
width = width.Replace("px", string.Empty);
height = height.Replace("px", string.Empty);
size = new Size(
(int)Math.Round(QueryParamParser.Instance.ParseValue<float>(width), Rounding),
(int)Math.Round(QueryParamParser.Instance.ParseValue<float>(height), Rounding));
}
// Calculate any ratio driven sizes.
if (size.Width == 0 || size.Height == 0)
{
// Replace 0 width
if (size.Width == 0 && size.Height > 0 && widthRatio != null && heightRatio == null)
{
size.Width = (int)Math.Round(QueryParamParser.Instance.ParseValue<float>(widthRatio) * size.Height, Rounding);
}
// Replace 0 height
if (size.Width > 0 && size.Height == 0 && widthRatio == null && heightRatio != null)
{
size.Height = (int)Math.Round(QueryParamParser.Instance.ParseValue<float>(heightRatio) * size.Width, Rounding);
}
}
return size;
}
/// <summary>
/// Returns a <see cref="List{T}"/> of sizes to restrict resizing to.
/// </summary>
/// <param name="input">
/// The input.
/// </param>
/// <returns>
/// The <see cref="List{Size}"/> to restrict resizing to.
/// </returns>
private List<Size> ParseRestrictions(string input)
{
List<Size> sizes = new List<Size>();
if (!string.IsNullOrWhiteSpace(input))
{
sizes.AddRange(input.Split(',').Select(q => this.ParseSize(HttpUtility.ParseQueryString(q))));
}
return sizes;
}
}
}