Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
140 changes: 77 additions & 63 deletions Functions/ImageResizerFunction.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,73 +31,87 @@ public ImageProxyFunction(IImageResizerService imageProxyService,
}


/*
/*
* Main entry point...takes a wildcard.
*/
[FunctionName("ResizeImage")]
public async Task<IActionResult> Run([HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = "ResizeImage/{*restOfPath}")] HttpRequest req, string restOfPath)
[FunctionName("ResizeImage")]
public async Task<IActionResult> Run1([HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = "ResizeImage/{*restOfPath}")] HttpRequest req, string restOfPath)
{
return await ResizeImage(req, restOfPath, false);
}

/*
* Main entry point...takes a wildcard.
*/
[FunctionName("ResizeImageCache")]
public async Task<IActionResult> Run2([HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = "ResizeImageCache/{*restOfPath}")] HttpRequest req, string restOfPath)
{
return await ResizeImage(req, restOfPath, true);
}

private async Task<IActionResult> ResizeImage(HttpRequest req, string restOfPath, bool cache)
{
// check to see if we have a cached version and just leave if we do
if (req.HttpContext.Request.GetTypedHeaders().IfModifiedSince.HasValue)
{
return new StatusCodeResult((int)HttpStatusCode.NotModified);
}

try
{
// get the url
var url = restOfPath.Replace(config.GetValue<string>("AzureContainer"), "");

// we need at least the url
if (string.IsNullOrEmpty(url))
return new BadRequestObjectResult("URL is required");

// figure out the needed variables
// var url = req.Query["url"].ToString();
var size = req.Query.ContainsKey("size") ? req.Query["size"].ToString() : "";
var width = req.Query.ContainsKey("w") ? req.Query["w"].ToString().ToInt() : 0;
var height = req.Query.ContainsKey("h") ? req.Query["h"].ToString().ToInt() : 0;
var output = req.Query.ContainsKey("output") ? req.Query["output"].ToString().Replace(".", "") : url.ToSuffix();
var mode = req.Query.ContainsKey("mode") ? req.Query["mode"].ToString() : "";
var validOutputs = new List<string>() { "jpg", "gif", "png", "webp" };

// validate the output
if (!validOutputs.Contains(output))
output = url.ToSuffix();

// figure out the actual size
if (string.IsNullOrEmpty(size))
size = $"{width}x{height}";

// try to resize the image
var imageStream = await this.imageResizerService.ResizeAsync(url, size, output, mode);

if (imageStream == null)
return new NotFoundResult();

// choose the correct mime type
var mimeType = output switch
{
"jpg" => "image/jpeg",
"gif" => "image/gif",
"png" => "image/png",
"webp" => "image/webp",
_ => "image/jpeg"
};

// set cache
this.SetCacheHeaders(req.HttpContext.Response.GetTypedHeaders());
// return the stream
return new FileStreamResult(imageStream, mimeType);
}
catch(Exception ex)
{
return new BadRequestResult();
}
}
// check to see if we have a cached version and just leave if we do
if (req.HttpContext.Request.GetTypedHeaders().IfModifiedSince.HasValue)
{
return new StatusCodeResult((int)HttpStatusCode.NotModified);
}

try
{
// get the url
var url = restOfPath.Replace(config.GetValue<string>("AzureContainer"), "");

// we need at least the url
if (string.IsNullOrEmpty(url))
return new BadRequestObjectResult("URL is required");

// figure out the needed variables
// var url = req.Query["url"].ToString();
var size = req.Query.ContainsKey("size") ? req.Query["size"].ToString() : "";
var width = req.Query.ContainsKey("w") ? req.Query["w"].ToString().ToInt() : 0;
var height = req.Query.ContainsKey("h") ? req.Query["h"].ToString().ToInt() : 0;
var output = req.Query.ContainsKey("output") ? req.Query["output"].ToString().Replace(".", "") : url.ToSuffix();
var mode = req.Query.ContainsKey("mode") ? req.Query["mode"].ToString() : "";
var validOutputs = new List<string>() { "jpg", "gif", "png", "webp" };

// validate the output
if (!validOutputs.Contains(output))
output = url.ToSuffix();

// figure out the actual size
if (string.IsNullOrEmpty(size))
size = $"{width}x{height}";

// try to resize the image
var imageStream = await this.imageResizerService.ResizeAsync(url, size, output, mode, cache);

if (imageStream == null)
return new NotFoundResult();

// choose the correct mime type
var mimeType = output switch
{
"jpg" => "image/jpeg",
"gif" => "image/gif",
"png" => "image/png",
"webp" => "image/webp",
_ => "image/jpeg"
};

// set cache
//this.SetCacheHeaders(req.HttpContext.Response.GetTypedHeaders());

// return the stream
return new FileStreamResult(imageStream, mimeType);
}
catch (Exception ex)
{
return new BadRequestResult();
}
}

private void SetCacheHeaders(ResponseHeaders responseHeaders)
private void SetCacheHeaders(ResponseHeaders responseHeaders)
{
responseHeaders.CacheControl = new CacheControlHeaderValue { Public = true };
responseHeaders.LastModified = new DateTimeOffset(new DateTime(1900, 1, 1));
Expand Down
4 changes: 2 additions & 2 deletions ImageResizeProxy.csproj
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework>
<AzureFunctionsVersion>v3</AzureFunctionsVersion>
<TargetFramework>net6</TargetFramework>
<AzureFunctionsVersion>v4</AzureFunctionsVersion>
<LangVersion>8.0</LangVersion>
<Nullable>enable</Nullable>
<RootNamespace>RainstormTech.Storm.ImageProxy</RootNamespace>
Expand Down
2 changes: 1 addition & 1 deletion Services/IImageResizerService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,6 @@ namespace RainstormTech.Storm.ImageProxy
{
public interface IImageResizerService
{
Task<Stream> ResizeAsync(string url, string size, string output, string mode);
Task<Stream> ResizeAsync(string url, string size, string output, string mode, bool cache = false);
}
}
30 changes: 24 additions & 6 deletions Services/ImageResizerService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,9 @@ public ImageResizerService(HttpClient httpClient,
/// <param name="output"></param>
/// <param name="mode"></param>
/// <returns></returns>
public async Task<Stream> ResizeAsync(string url, string size, string output, string mode)
public async Task<Stream> ResizeAsync(string url, string size, string output, string mode, bool cache = false)
{
return await this.GetResultStreamAsync(url, StringToImageSize(size), output, mode);
return await this.GetResultStreamAsync(url, StringToImageSize(size), output, mode, cache);
}


Expand All @@ -53,15 +53,15 @@ public async Task<Stream> ResizeAsync(string url, string size, string output, st
/// <param name="output"></param>
/// <param name="mode"></param>
/// <returns></returns>
private async Task<Stream> GetResultStreamAsync(string uri, ImageSize imageSize, string output, string mode)
private async Task<Stream> GetResultStreamAsync(string uri, ImageSize imageSize, string output, string mode, bool cache = false)
{
// Create a BlobServiceClient object which will be used to create a container client
BlobServiceClient blobServiceClient = new BlobServiceClient(config.GetConnectionString("AzureStorage"));

// get the container name
string containerName = config.GetValue("AzureContainer", "storm");

try
try
{
// Create the container and return a container client object
var container = blobServiceClient.GetBlobContainerClient(containerName);
Expand All @@ -70,14 +70,32 @@ private async Task<Stream> GetResultStreamAsync(string uri, ImageSize imageSize,
// Get a reference to a blob
BlobClient blobClient = container.GetBlobClient(uri);

// Get cache image
var cacheUri = $"Cache{uri}_{imageSize.Width}_{imageSize.Height}_{output}_{mode}";
if (cache)
{
var cacheBlobClient = container.GetBlobClient(cacheUri);
if (await cacheBlobClient.ExistsAsync())
{
return (await cacheBlobClient.DownloadStreamingAsync()).Value.Content;
}
}

// Download the blob's contents and save it to a strea
using (var imageStream = new MemoryStream())
{
await blobClient.DownloadToAsync(imageStream);
imageStream.Position = 0;

return GetResizedImage(imageStream, imageSize, output, mode);
}
var newImage = GetResizedImage(imageStream, imageSize, output, mode);
if (cache)
{
// Upload cache image
await container.UploadBlobAsync(cacheUri, newImage);
newImage.Position = 0;
}
return newImage;
}
}
catch(Exception ex)
{
Expand Down