Skip to content

Commit

Permalink
Cleanup + fixes
Browse files Browse the repository at this point in the history
Adjustments.Opacity now respects passed rectangle.
  • Loading branch information
JimBobSquarePants committed Aug 30, 2018
1 parent c0fd48e commit 4af8de4
Show file tree
Hide file tree
Showing 185 changed files with 1,752 additions and 3,243 deletions.
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
54 changes: 25 additions & 29 deletions src/ImageProcessor.Web.Plugins.AzureBlobCache/AzureBlobCache.cs
Original file line number Diff line number Diff line change
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 @@ CloudBlockBlob blob in

// 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 @@ CloudBlockBlob blob in
/// </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 @@ -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
5 changes: 1 addition & 4 deletions src/ImageProcessor.Web/Caching/AsyncKeyLock.cs
Original file line number Diff line number Diff line change
Expand Up @@ -78,10 +78,7 @@ private sealed class Releaser : IDisposable
/// Initializes a new instance of the <see cref="Releaser"/> class.
/// </summary>
/// <param name="key">The key identifying the doorman that limits the number of threads.</param>
public Releaser(string key)
{
this.key = key;
}
public Releaser(string key) => this.key = key;

/// <inheritdoc />
public void Dispose()
Expand Down
10 changes: 3 additions & 7 deletions src/ImageProcessor.Web/Caching/CacheIndexer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,7 @@ public static class CacheIndexer
public static CachedImage Get(string cachedPath)
{
string key = Path.GetFileNameWithoutExtension(cachedPath);
CachedImage cachedImage = (CachedImage)MemCache.GetItem(key);
return cachedImage;
return (CachedImage)MemCache.GetItem(key);
}

/// <summary>
Expand Down Expand Up @@ -73,7 +72,7 @@ public static bool Remove(string cachedPath)
{ expiration = new TimeSpan(0, 1, 0); }

// Add the CachedImage with a sliding expiration of `expiry` minutes.
CacheItemPolicy policy = new CacheItemPolicy { SlidingExpiration = expiration };
var policy = new CacheItemPolicy { SlidingExpiration = expiration };

if (new Uri(cachedImage.Path).IsFile)
{
Expand Down Expand Up @@ -120,9 +119,6 @@ public static bool Remove(string cachedPath)
/// <returns>
/// The value of the item to add or get.
/// </returns>
public static CachedImage Add(CachedImage cachedImage, int expiry)
{
return Add(cachedImage, new TimeSpan(0, expiry, 0));
}
public static CachedImage Add(CachedImage cachedImage, int expiry) => Add(cachedImage, new TimeSpan(0, expiry, 0));
}
}
Loading

0 comments on commit 4af8de4

Please sign in to comment.