Skip to content
This repository has been archived by the owner on Sep 6, 2023. It is now read-only.

Commit

Permalink
Merge branch 'develop' into #664
Browse files Browse the repository at this point in the history
  • Loading branch information
JimBobSquarePants committed Aug 30, 2018
2 parents 77995b7 + 6b25968 commit 8602d4e
Show file tree
Hide file tree
Showing 205 changed files with 2,016 additions and 3,582 deletions.
2 changes: 1 addition & 1 deletion build/NuSpecs/ImageProcessor.Web.PostProcessor.nuspec
Expand Up @@ -23,7 +23,7 @@
<tags>Image Resize Crop Rotate Quality Watermark Gif Jpg Jpeg Bitmap Png Tiff ASP Cache EXIF</tags>
<dependencies>
<group targetFramework=".NETFramework4.5">
<dependency id="ImageProcessor.Web" version="4.9.3.0" />
<dependency id="ImageProcessor.Web" version="4.9.4.0" />
</group>
</dependencies>
</metadata>
Expand Down
4 changes: 2 additions & 2 deletions build/build.ps1
Expand Up @@ -35,7 +35,7 @@ $imageProcessorPluginsWebP = @{

$imageprocessorWeb = @{
name = "ImageProcessor.Web"
version = "4.9.3.${buildNumber}"
version = "4.9.4.${buildNumber}"
folder = Join-Path $buildPath "src\ImageProcessor.Web"
output = Join-Path $binPath "ImageProcessor.Web\lib\net452"
csproj = "ImageProcessor.Web.csproj"
Expand All @@ -58,7 +58,7 @@ $imageProcessorWebPluginsAzureBlobCache = @{

$imageProcessorWebPluginsPostProcessor = @{
name = "ImageProcessor.Web.Plugins.PostProcessor"
version = "1.3.1.${buildNumber}"
version = "1.3.2.${buildNumber}"
folder = Join-Path $buildPath "src\ImageProcessor.Web.Plugins.PostProcessor"
output = Join-Path $binPath "ImageProcessor.Web.Plugins.PostProcessor\lib\net452"
csproj = "ImageProcessor.Web.Plugins.PostProcessor.csproj"
Expand Down
Expand Up @@ -31,7 +31,7 @@ static NativeMethods()
string name = string.Format("ImageProcessor.Plugins.WebP.Resources.Unmanaged.{0}.libwebp.dll", folder);
using (Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(name))
{
using (MemoryStream memoryStream = new MemoryStream())
using (var memoryStream = new MemoryStream())
{
if (stream != null)
{
Expand All @@ -42,7 +42,6 @@ static NativeMethods()
}
}

#region WebP
/// <summary>
/// Validate the WebP image header and retrieve the image height and width. Pointers *width and *height can be passed NULL if deemed irrelevant
/// </summary>
Expand Down Expand Up @@ -150,6 +149,5 @@ static NativeMethods()
/// </returns>
[DllImport("libwebp", CallingConvention = CallingConvention.Cdecl, EntryPoint = "WebPFree")]
public static extern int WebPFree(IntPtr pointer);
#endregion
}
}
16 changes: 5 additions & 11 deletions src/ImageProcessor.Plugins.WebP/Imaging/Formats/WebPFormat.cs
Expand Up @@ -105,13 +105,11 @@ public override Image Load(Stream stream)
/// </returns>
public override Image Save(Stream stream, Image image, long bitDepth)
{
byte[] bytes;

// Encode in webP format.
// If Quality is 100, encode losslessly instead of lossily
if (this.Quality == 100 ? EncodeLosslessly((Bitmap)image, out bytes) : EncodeLossly((Bitmap)image, this.Quality, out bytes))
if (this.Quality == 100 ? EncodeLosslessly((Bitmap)image, out byte[] bytes) : EncodeLossly((Bitmap)image, this.Quality, out bytes))
{
using (MemoryStream memoryStream = new MemoryStream(bytes))
using (var memoryStream = new MemoryStream(bytes))
{
memoryStream.CopyTo(stream);
memoryStream.Position = stream.Position = 0;
Expand Down Expand Up @@ -140,11 +138,9 @@ public override Image Save(Stream stream, Image image, long bitDepth)
/// </returns>
public override Image Save(string path, Image image, long bitDepth)
{
byte[] bytes;

// Encode in webP format.
// If Quality is 100, encode losslessly instead of lossily
if (this.Quality == 100 ? EncodeLosslessly((Bitmap)image, out bytes) : EncodeLossly((Bitmap)image, this.Quality, out bytes))
if (this.Quality == 100 ? EncodeLosslessly((Bitmap)image, out byte[] bytes) : EncodeLossly((Bitmap)image, this.Quality, out bytes))
{
File.WriteAllBytes(path, bytes);
}
Expand All @@ -162,17 +158,15 @@ public override Image Save(string path, Image image, long bitDepth)
private static Bitmap Decode(byte[] webpData)
{
// Get the image width and height
GCHandle pinnedWebP = GCHandle.Alloc(webpData, GCHandleType.Pinned);
var pinnedWebP = GCHandle.Alloc(webpData, GCHandleType.Pinned);
IntPtr ptrData = pinnedWebP.AddrOfPinnedObject();
uint dataSize = (uint)webpData.Length;

Bitmap bitmap = null;
BitmapData bitmapData = null;
IntPtr outputBuffer = IntPtr.Zero;
int width;
int height;

if (NativeMethods.WebPGetInfo(ptrData, dataSize, out width, out height) != 1)
if (NativeMethods.WebPGetInfo(ptrData, dataSize, out int width, out int height) != 1)
{
throw new ImageFormatException("WebP image header is corrupted.");
}
Expand Down
56 changes: 26 additions & 30 deletions src/ImageProcessor.Web.Plugins.AzureBlobCache/AzureBlobCache.cs
Expand Up @@ -97,7 +97,7 @@ public AzureBlobCache(string requestPath, string fullPath, string querystring)
if (cloudCachedBlobClient == null)
{
// Retrieve storage accounts from connection string.
CloudStorageAccount cloudCachedStorageAccount = CloudStorageAccount.Parse(this.Settings["CachedStorageAccount"]);
var cloudCachedStorageAccount = CloudStorageAccount.Parse(this.Settings["CachedStorageAccount"]);

// Create the blob clients.
cloudCachedBlobClient = cloudCachedStorageAccount.CreateCloudBlobClient();
Expand All @@ -118,7 +118,7 @@ public AzureBlobCache(string requestPath, string fullPath, string querystring)
// Repeat for source if it exists
if (!string.IsNullOrWhiteSpace(sourceAccount))
{
CloudStorageAccount cloudSourceStorageAccount = CloudStorageAccount.Parse(this.Settings["SourceStorageAccount"]);
var cloudSourceStorageAccount = CloudStorageAccount.Parse(this.Settings["SourceStorageAccount"]);
CloudBlobClient cloudSourceBlobClient = cloudSourceStorageAccount.CreateCloudBlobClient();
cloudSourceBlobContainer = cloudSourceBlobClient.GetContainerReference(this.Settings["SourceBlobContainer"]);
}
Expand All @@ -130,15 +130,14 @@ public AzureBlobCache(string requestPath, string fullPath, string querystring)

if (this.Settings.ContainsKey("CachedCDNTimeout"))
{
int t;
int.TryParse(this.Settings["CachedCDNTimeout"], out t);
int.TryParse(this.Settings["CachedCDNTimeout"], out int t);
this.timeout = t;
}

// This setting was added to facilitate streaming of the blob resource directly instead of a redirect. This is beneficial for CDN purposes
// but caution should be taken if not used with a CDN as it will add quite a bit of overhead to the site.
// See: https://github.com/JimBobSquarePants/ImageProcessor/issues/161
this.streamCachedImage = this.Settings.ContainsKey("StreamCachedImage") && this.Settings["StreamCachedImage"].ToLower() == "true";
this.streamCachedImage = this.Settings.ContainsKey("StreamCachedImage") && string.Equals(this.Settings["StreamCachedImage"], "true", StringComparison.OrdinalIgnoreCase);
}

/// <summary>
Expand All @@ -152,11 +151,11 @@ public override async Task<bool> IsNewOrUpdatedAsync()
// TODO: Before this check is performed it should be throttled. For example, only perform this check
// if the last time it was checked is greater than 5 seconds. This would be much better for perf
// if there is a high throughput of image requests.
string cachedFileName = await this.CreateCachedFileNameAsync();
string cachedFileName = await this.CreateCachedFileNameAsync().ConfigureAwait(false);
this.CachedPath = CachedImageHelper.GetCachedPath(cloudCachedBlobContainer.Uri.ToString(), cachedFileName, true, this.FolderDepth);

// Do we insert the cache container? This seems to break some setups.
bool useCachedContainerInUrl = this.Settings.ContainsKey("UseCachedContainerInUrl") && this.Settings["UseCachedContainerInUrl"].ToLower() != "false";
bool useCachedContainerInUrl = this.Settings.ContainsKey("UseCachedContainerInUrl") && !string.Equals(this.Settings["UseCachedContainerInUrl"], "false", StringComparison.OrdinalIgnoreCase);

this.cachedRewritePath = CachedImageHelper.GetCachedPath(useCachedContainerInUrl ? Path.Combine(this.cachedCdnRoot, cloudCachedBlobContainer.Name) : this.cachedCdnRoot, cachedFileName, true, this.FolderDepth);

Expand All @@ -183,10 +182,10 @@ public override async Task<bool> IsNewOrUpdatedAsync()
string blobPath = this.CachedPath.Substring(cloudCachedBlobContainer.Uri.ToString().Length + 1);
CloudBlockBlob blockBlob = cloudCachedBlobContainer.GetBlockBlobReference(blobPath);

if (await blockBlob.ExistsAsync())
if (await blockBlob.ExistsAsync().ConfigureAwait(false))
{
// Pull the latest info.
await blockBlob.FetchAttributesAsync();
await blockBlob.FetchAttributesAsync().ConfigureAwait(false);

if (blockBlob.Properties.LastModified.HasValue)
{
Expand All @@ -211,7 +210,7 @@ public override async Task<bool> IsNewOrUpdatedAsync()
{
// Check to see if the cached image is set to expire
// or a new file with the same name has replaced our current image
if (this.IsExpired(cachedImage.CreationTimeUtc) || await this.IsUpdatedAsync(cachedImage.CreationTimeUtc))
if (this.IsExpired(cachedImage.CreationTimeUtc) || await this.IsUpdatedAsync(cachedImage.CreationTimeUtc).ConfigureAwait(false))
{
CacheIndexer.Remove(this.CachedPath);
isUpdated = true;
Expand All @@ -238,14 +237,14 @@ public override async Task AddImageToCacheAsync(Stream stream, string contentTyp
string blobPath = this.CachedPath.Substring(cloudCachedBlobContainer.Uri.ToString().Length + 1);
CloudBlockBlob blockBlob = cloudCachedBlobContainer.GetBlockBlobReference(blobPath);

await blockBlob.UploadFromStreamAsync(stream);
await blockBlob.UploadFromStreamAsync(stream).ConfigureAwait(false);

blockBlob.Properties.ContentType = contentType;
blockBlob.Properties.CacheControl = $"public, max-age={this.BrowserMaxDays * 86400}";
await blockBlob.SetPropertiesAsync();
await blockBlob.SetPropertiesAsync().ConfigureAwait(false);

blockBlob.Metadata.Add("ImageProcessedBy", "ImageProcessor.Web/" + AssemblyVersion);
await blockBlob.SetMetadataAsync();
await blockBlob.SetMetadataAsync().ConfigureAwait(false);
}

/// <summary>
Expand All @@ -268,28 +267,27 @@ public override Task TrimCacheAsync()
if (this.FolderDepth > 0)
{
Uri uri = new Uri(this.CachedPath);
var uri = new Uri(this.CachedPath);
string path = uri.GetLeftPart(UriPartial.Path).Substring(cloudCachedBlobContainer.Uri.ToString().Length + 1);
parent = path.Substring(0, 2);
}
BlobContinuationToken continuationToken = null;
List<IListBlobItem> results = new List<IListBlobItem>();
var results = new List<IListBlobItem>();
// Loop through the all the files in a non blocking fashion.
do
{
BlobResultSegment response = await cloudCachedBlobContainer.ListBlobsSegmentedAsync(parent, true, BlobListingDetails.Metadata, 5000, continuationToken, null, null, token);
BlobResultSegment response = await cloudCachedBlobContainer.ListBlobsSegmentedAsync(parent, true, BlobListingDetails.Metadata, 5000, continuationToken, null, null, token).ConfigureAwait(false);
continuationToken = response.ContinuationToken;
results.AddRange(response.Results);
}
while (token.IsCancellationRequested == false && continuationToken != null);
while (!token.IsCancellationRequested && continuationToken != null);
// Now leap through and delete.
foreach (
CloudBlockBlob blob in
results.Where((blobItem, type) => blobItem is CloudBlockBlob)
.Cast<CloudBlockBlob>()
results.OfType<CloudBlockBlob>()
.OrderBy(b => b.Properties.LastModified?.UtcDateTime ?? new DateTime()))
{
if (token.IsCancellationRequested || (blob.Properties.LastModified.HasValue && !this.IsExpired(blob.Properties.LastModified.Value.UtcDateTime)))
Expand All @@ -299,7 +297,7 @@ public override Task TrimCacheAsync()
// Remove from the cache and delete each CachedImage.
CacheIndexer.Remove(blob.Name);
await blob.DeleteAsync(token);
await blob.DeleteAsync(token).ConfigureAwait(false);
}
});

Expand All @@ -314,7 +312,7 @@ public override Task TrimCacheAsync()
/// </param>
public override void RewritePath(HttpContext context)
{
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(this.cachedRewritePath);
var request = (HttpWebRequest)WebRequest.Create(this.cachedRewritePath);

if (this.streamCachedImage)
{
Expand Down Expand Up @@ -459,7 +457,7 @@ protected virtual async Task<bool> IsUpdatedAsync(DateTime creationDate)

try
{
if (new Uri(this.RequestPath).IsFile)
if ((Uri.IsWellFormedUriString(this.RequestPath, UriKind.Absolute)) && (new Uri(this.RequestPath).IsFile))
{
if (File.Exists(this.RequestPath))
{
Expand All @@ -474,10 +472,10 @@ protected virtual async Task<bool> IsUpdatedAsync(DateTime creationDate)
blobPath = blobPath.Replace(container, string.Empty).TrimStart('/');
CloudBlockBlob blockBlob = cloudSourceBlobContainer.GetBlockBlobReference(blobPath);

if (await blockBlob.ExistsAsync())
if (await blockBlob.ExistsAsync().ConfigureAwait(false))
{
// Pull the latest info.
await blockBlob.FetchAttributesAsync();
await blockBlob.FetchAttributesAsync().ConfigureAwait(false);

if (blockBlob.Properties.LastModified.HasValue)
{
Expand All @@ -488,10 +486,10 @@ protected virtual async Task<bool> IsUpdatedAsync(DateTime creationDate)
else
{
// Try and get the headers for the file, this should allow cache busting for remote files.
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(this.RequestPath);
var request = (HttpWebRequest)WebRequest.Create(this.RequestPath);
request.Method = "HEAD";

using (HttpWebResponse response = (HttpWebResponse)await request.GetResponseAsync())
using (var response = (HttpWebResponse)await request.GetResponseAsync().ConfigureAwait(false))
{
isUpdated = response.LastModified.ToUniversalTime() > creationDate;
}
Expand All @@ -514,17 +512,15 @@ protected virtual async Task<bool> IsUpdatedAsync(DateTime creationDate)
/// <param name="request">The current request</param>
private static void TrySetIfModifiedSinceDate(HttpContext context, HttpWebRequest request)
{
DateTime ifModifiedDate;

string ifModifiedFromRequest = context.Request.Headers["If-Modified-Since"];

if (DateTime.TryParse(ifModifiedFromRequest, out ifModifiedDate))
if (DateTime.TryParse(ifModifiedFromRequest, out DateTime ifModifiedDate))
{
request.IfModifiedSince = ifModifiedDate;
}
else
{
if (ifModifiedFromRequest.ToLower().Contains("utc"))
if (ifModifiedFromRequest.IndexOf("utc", StringComparison.OrdinalIgnoreCase) >= 0)
{
ifModifiedFromRequest = ifModifiedFromRequest.ToLower().Replace("utc", string.Empty);

Expand Down
Expand Up @@ -53,7 +53,6 @@
</ItemGroup>
<ItemGroup>
<None Include="Resources\Unmanaged\README.txt" />
<EmbeddedResource Include="Resources\Unmanaged\x86\png.cmd" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="Resources\Unmanaged\x64\gifsicle.exe" />
Expand Down

0 comments on commit 8602d4e

Please sign in to comment.