diff --git a/README.md b/README.md
index 1cde6c5..5945b99 100644
--- a/README.md
+++ b/README.md
@@ -28,7 +28,7 @@ Install via Nuget
```csharp
using (var png = new TinyPngClient("yourSecretApiKey"))
{
- await (await png.Compress("cat.jpg")).SaveImageToDisk("compressedCat.jpg");
+ await png.Compress("cat.jpg");
}
```
@@ -39,31 +39,36 @@ using (var png = new TinyPngClient("yourSecretApiKey"))
using (var png = new TinyPngClient("yourSecretApiKey"))
{
//compress an image
- var compressResult = await png.Compress("pathToFile or byte array or stream");
+ var result = await png.Compress("pathToFile or byte array or stream");
+
+ //this gives you the information about your image as stored by TinyPNG
+ //they don't give you the actual bits as you may want to chain this with a resize
+ //operation without caring for the originally sied image. For that, we need to:
+ var compressedImage = await result.Download();
//get the image data as a byte array
- var bytes = await compressResult.GetImageByteData();
+ var bytes = await compressedImage.GetImageByteData();
//get a stream instead
- var stream = await compressResult.GetImageStreamData()
+ var stream = await compressedImage.GetImageStreamData()
//or just save to disk
- await compressResult.SaveImageToDisk("pathToSaveImage");
+ await compressedImage.SaveImageToDisk("pathToSaveImage");
}
```
-Further details about the result of the compression are also available on the `Input` and `Output` properties. Some examples:
+Further details about the result of the compression are also available on the `Input` and `Output` properties of a `Compress` operation. Some examples:
```csharp
//old size
- compressResult.Input.Size;
+ result.Input.Size;
//new size
- compressResult.Output.Size;
+ result.Output.Size;
//URL of the compressed Image
- compressResult.Output.Url;
+ result.Output.Url;
```
@@ -72,9 +77,9 @@ Further details about the result of the compression are also available on the `I
```csharp
using (var png = new TinyPngClient("yourSecretApiKey"))
{
- var compressResult = await png.Compress("pathToFile or byte array or stream");
+ var result = await png.Compress("pathToFile or byte array or stream");
- var resizedImage = await png.Resize(compressResult, width, height, ResizeType);
+ var resizedImage = await png.Resize(result, width, height, ResizeType);
await resizedImage.SaveImageToDisk("pathToSaveImage");
}
@@ -90,12 +95,12 @@ depending on the type of resize you want to do.
```csharp
using (var png = new TinyPngClient("yourSecretApiKey"))
{
- var compressResult = await png.Compress("pathToFile or byte array or stream");
+ var result = await png.Compress("pathToFile or byte array or stream");
- await png.Resize(compressResult, new ScaleWidthResizeOperation(width));
- await png.Resize(compressResult, new ScaleHeightResizeOperation(width));
- await png.Resize(compressResult, new FitResizeOperation(width, height));
- await png.Resize(compressResult, new CoverResizeOperation(width, height));
+ await png.Resize(result, new ScaleWidthResizeOperation(width));
+ await png.Resize(result, new ScaleHeightResizeOperation(width));
+ await png.Resize(result, new FitResizeOperation(width, height));
+ await png.Resize(result, new CoverResizeOperation(width, height));
}
```
@@ -104,7 +109,8 @@ The same `Byte[]`, `Stream` and `File` path API's are available from the result
## Amazon S3 Storage
-The result of any compress operation can be stored directly on to Amazon S3 storage. There are two ways to configure this.
+The result of any compress operation can be stored directly on to Amazon S3 storage. I'd strongly recommend referring to [TinyPNG.com's documentation](https://tinypng.com/developers/reference) with regard to how to configure
+the appropriate S3 access.
If you're going to be storing images for most requests onto S3, then you can pass in an `AmazonS3Configuration` object to the constructor.
diff --git a/TinyPNG.v2.ncrunchsolution b/TinyPNG.v2.ncrunchsolution
new file mode 100644
index 0000000..b98737f
--- /dev/null
+++ b/TinyPNG.v2.ncrunchsolution
@@ -0,0 +1,14 @@
+
+ 1
+ false
+ false
+ true
+ UseDynamicAnalysis
+ UseStaticAnalysis
+ UseStaticAnalysis
+ UseStaticAnalysis
+ UseDynamicAnalysis
+
+
+
+
\ No newline at end of file
diff --git a/src/TinyPNG/Extensions.cs b/src/TinyPNG/Extensions.cs
index a82c458..c178d60 100644
--- a/src/TinyPNG/Extensions.cs
+++ b/src/TinyPNG/Extensions.cs
@@ -6,13 +6,12 @@ namespace TinyPng
{
public static class Extensions
{
-
///
/// Get the image data as a byte array
///
/// The result from compress
/// Byte array of the image data
- public async static Task GetImageByteData(this TinyPngResponse result)
+ public async static Task GetImageByteData(this TinyPngImageResponse result)
{
return await result.HttpResponseMessage.Content.ReadAsByteArrayAsync();
}
@@ -22,7 +21,7 @@ public async static Task GetImageByteData(this TinyPngResponse result)
///
/// The result from compress
/// Stream of compressed image data
- public async static Task GetImageStreamData(this TinyPngResponse result)
+ public async static Task GetImageStreamData(this TinyPngImageResponse result)
{
return await result.HttpResponseMessage.Content.ReadAsStreamAsync();
}
@@ -33,7 +32,7 @@ public async static Task GetImageStreamData(this TinyPngResponse result)
/// The result from compress
/// The path to store the file
///
- public async static Task SaveImageToDisk(this TinyPngResponse result, string filePath)
+ public async static Task SaveImageToDisk(this TinyPngImageResponse result, string filePath)
{
var byteData = await result.GetImageByteData();
File.WriteAllBytes(filePath, byteData);
diff --git a/src/TinyPNG/Responses/TinyPngCompressResponse.cs b/src/TinyPNG/Responses/TinyPngCompressResponse.cs
index fdda53b..d2ff429 100644
--- a/src/TinyPNG/Responses/TinyPngCompressResponse.cs
+++ b/src/TinyPNG/Responses/TinyPngCompressResponse.cs
@@ -10,6 +10,7 @@ public class TinyPngCompressResponse : TinyPngResponse
public TinyPngApiInput Input { get; private set; }
public TinyPngApiOutput Output { get; private set; }
public TinyPngApiResult ApiResult { get; private set; }
+
private readonly JsonSerializerSettings jsonSettings;
public TinyPngCompressResponse(HttpResponseMessage msg) : base(msg)
diff --git a/src/TinyPNG/Responses/TinyPngImageResponse.cs b/src/TinyPNG/Responses/TinyPngImageResponse.cs
new file mode 100644
index 0000000..af5ebef
--- /dev/null
+++ b/src/TinyPNG/Responses/TinyPngImageResponse.cs
@@ -0,0 +1,14 @@
+using System.Net.Http;
+
+namespace TinyPng.Responses
+{
+ ///
+ /// This is a response which contains actual image data
+ ///
+ public class TinyPngImageResponse : TinyPngResponse
+ {
+ public TinyPngImageResponse(HttpResponseMessage msg) : base(msg)
+ {
+ }
+ }
+}
diff --git a/src/TinyPNG/Responses/TinyPngResizeResponse.cs b/src/TinyPNG/Responses/TinyPngResizeResponse.cs
index 34a2542..b8ad868 100644
--- a/src/TinyPNG/Responses/TinyPngResizeResponse.cs
+++ b/src/TinyPNG/Responses/TinyPngResizeResponse.cs
@@ -2,7 +2,7 @@
namespace TinyPng.Responses
{
- public class TinyPngResizeResponse : TinyPngResponse
+ public class TinyPngResizeResponse : TinyPngImageResponse
{
public TinyPngResizeResponse(HttpResponseMessage msg) : base(msg)
{
diff --git a/src/TinyPNG/Responses/TinyPngResponse.cs b/src/TinyPNG/Responses/TinyPngResponse.cs
index e886c3e..4e4fa86 100644
--- a/src/TinyPNG/Responses/TinyPngResponse.cs
+++ b/src/TinyPNG/Responses/TinyPngResponse.cs
@@ -6,17 +6,11 @@ namespace TinyPng.Responses
{
public class TinyPngResponse
{
- public HttpResponseMessage HttpResponseMessage { get; private set; }
+ public HttpResponseMessage HttpResponseMessage { get; }
private int compressionCount;
- public int CompressionCount
- {
- get
- {
- return compressionCount;
- }
- }
+ public int CompressionCount => compressionCount;
protected TinyPngResponse(HttpResponseMessage msg)
{
diff --git a/src/TinyPNG/TinyPng.cs b/src/TinyPNG/TinyPng.cs
index b90dc92..8f81252 100644
--- a/src/TinyPNG/TinyPng.cs
+++ b/src/TinyPNG/TinyPng.cs
@@ -14,7 +14,8 @@ public class TinyPngClient : IDisposable
{
private readonly string _apiKey;
private const string ApiEndpoint = "https://api.tinify.com/shrink";
- private HttpClient httpClient = new HttpClient();
+
+ public HttpClient httpClient = new HttpClient();
private readonly JsonSerializerSettings jsonSettings;
///
@@ -125,6 +126,22 @@ public async Task Compress(Stream data)
var errorMsg = JsonConvert.DeserializeObject(await response.Content.ReadAsStringAsync());
throw new TinyPngApiException((int)response.StatusCode, response.ReasonPhrase, errorMsg.Error, errorMsg.Message);
}
+ public async Task Download(TinyPngCompressResponse result)
+ {
+ if (result == null)
+ throw new ArgumentNullException(nameof(result));
+
+ var msg = new HttpRequestMessage(HttpMethod.Get, result.Output.Url);
+
+ var response = await httpClient.SendAsync(msg);
+ if (response.IsSuccessStatusCode)
+ {
+ return new TinyPngImageResponse(response);
+ }
+
+ var errorMsg = JsonConvert.DeserializeObject(await response.Content.ReadAsStringAsync());
+ throw new TinyPngApiException((int)response.StatusCode, response.ReasonPhrase, errorMsg.Error, errorMsg.Message);
+ }
///
@@ -142,7 +159,6 @@ public async Task Resize(TinyPngCompressResponse result,
var requestBody = JsonConvert.SerializeObject(new { resize = resizeOperation }, jsonSettings);
-
var msg = new HttpRequestMessage(HttpMethod.Post, result.Output.Url);
msg.Content = new StringContent(requestBody, System.Text.Encoding.UTF8, "application/json");
@@ -217,8 +233,9 @@ public async Task SaveCompressedImageToAmazonS3(TinyPngCompressResponse res
/// Stores a previously compressed image directly into Amazon S3 storage
///
/// The previously compressed image
- /// The path and bucket to store in: bucket/file.png format
- /// Optional: To override the previosly configured region
+ /// The path to storage the image as
+ /// Optional: To override the previously configured bucket
+ /// Optional: To override the previously configured region
///
public async Task SaveCompressedImageToAmazonS3(TinyPngCompressResponse result, string path, string bucketOverride = "", string regionOverride = "")
{
diff --git a/src/TinyPNG/project.json b/src/TinyPNG/project.json
index c526b68..a8a1af3 100644
--- a/src/TinyPNG/project.json
+++ b/src/TinyPNG/project.json
@@ -6,7 +6,7 @@
"copyright": "Copyright 2016 Chad Tolkien",
"packOptions": {
"iconUrl": "https://raw.githubusercontent.com/ctolkien/TinyPNG/master/icon.png",
- "releaseNotes": "Support for .NET Core 1.0",
+ "releaseNotes": "Major refactor of the API",
"summary": "This is a .NET wrapper around the TinyPng.com image compression service.",
"description": "This is a .NET wrapper around the TinyPng.com image compression service. Supports .Net Core and full .Net Framework. Non-blocking async turtles all the way down. Byte[], Stream and File API's available.",
"repository": {
@@ -49,5 +49,5 @@
}
}
},
- "version": "1.3.0-*"
+ "version": "2.0.0-*"
}
diff --git a/tests/TinyPng.Tests/FakeResponseHandler.cs b/tests/TinyPng.Tests/FakeResponseHandler.cs
new file mode 100644
index 0000000..98ddec2
--- /dev/null
+++ b/tests/TinyPng.Tests/FakeResponseHandler.cs
@@ -0,0 +1,41 @@
+using System;
+using System.Collections.Generic;
+using System.Net;
+using System.Net.Http;
+using System.Threading.Tasks;
+
+namespace TinyPng.Tests
+{
+ public class FakeResponseHandler : DelegatingHandler
+ {
+ private readonly Dictionary _FakeGetResponses = new Dictionary();
+ private readonly Dictionary _FakePostResponses = new Dictionary();
+
+
+ public void AddFakeGetResponse(Uri uri, HttpResponseMessage responseMessage)
+ {
+ _FakeGetResponses.Add(uri, responseMessage);
+ }
+ public void AddFakePostResponse(Uri uri, HttpResponseMessage responseMessage)
+ {
+ _FakePostResponses.Add(uri, responseMessage);
+ }
+
+ protected async override Task SendAsync(HttpRequestMessage request, System.Threading.CancellationToken cancellationToken)
+ {
+ if (request.Method == HttpMethod.Get && _FakeGetResponses.ContainsKey(request.RequestUri))
+ {
+ return _FakeGetResponses[request.RequestUri];
+ }
+ if (request.Method == HttpMethod.Post &&_FakePostResponses.ContainsKey(request.RequestUri))
+ {
+ return _FakePostResponses[request.RequestUri];
+ }
+ else
+ {
+ return new HttpResponseMessage(HttpStatusCode.NotFound) { RequestMessage = request };
+ }
+
+ }
+ }
+}
diff --git a/tests/TinyPng.Tests/Resources/cat.jpg b/tests/TinyPng.Tests/Resources/cat.jpg
index 8dea0c5..b35300f 100644
Binary files a/tests/TinyPng.Tests/Resources/cat.jpg and b/tests/TinyPng.Tests/Resources/cat.jpg differ
diff --git a/tests/TinyPng.Tests/Resources/compressedcat.jpg b/tests/TinyPng.Tests/Resources/compressedcat.jpg
new file mode 100644
index 0000000..ee75612
Binary files /dev/null and b/tests/TinyPng.Tests/Resources/compressedcat.jpg differ
diff --git a/tests/TinyPng.Tests/Resources/resizedcat.jpg b/tests/TinyPng.Tests/Resources/resizedcat.jpg
new file mode 100644
index 0000000..64d603c
Binary files /dev/null and b/tests/TinyPng.Tests/Resources/resizedcat.jpg differ
diff --git a/tests/TinyPng.Tests/TinyPngTests.cs b/tests/TinyPng.Tests/TinyPngTests.cs
index 464fef5..8ac0054 100644
--- a/tests/TinyPng.Tests/TinyPngTests.cs
+++ b/tests/TinyPng.Tests/TinyPngTests.cs
@@ -1,48 +1,148 @@
-using System;
+using Newtonsoft.Json;
+using System;
+using System.IO;
+using System.Net.Http;
using System.Threading.Tasks;
using Xunit;
namespace TinyPng.Tests
{
+ static class Extensions
+ {
+ public static FakeResponseHandler Compress(this FakeResponseHandler fakeResponse)
+ {
+
+ var content = new TinyPngApiResult();
+ content.Input = new TinyPngApiInput
+ {
+ Size = 18031,
+ Type = "image/jpeg"
+ };
+ content.Output = new TinyPngApiOutput
+ {
+ Width = 400,
+ Height = 400,
+ Size = 16646,
+ Type = "image/jpeg",
+ Ratio = 0.9232f,
+ Url = "https://api.tinify.com/output"
+ };
+
+ var compressResponseMessage = new HttpResponseMessage
+ {
+ StatusCode = System.Net.HttpStatusCode.Created,
+ Content = new StringContent(JsonConvert.SerializeObject(content)),
+ };
+ compressResponseMessage.Headers.Location = new Uri("https://api.tinify.com/output");
+ compressResponseMessage.Headers.Add("Compression-Count", "99");
+
+ fakeResponse.AddFakePostResponse(new Uri("https://api.tinify.com/shrink"), compressResponseMessage);
+ return fakeResponse;
+ }
+ public static FakeResponseHandler Download(this FakeResponseHandler fakeResponse)
+ {
+ var compressedCatStream = File.OpenRead(TinyPngTests.CompressedCat);
+ var outputResponseMessage = new HttpResponseMessage
+ {
+ Content = new StreamContent(compressedCatStream),
+ StatusCode = System.Net.HttpStatusCode.OK
+ };
+
+ fakeResponse.AddFakeGetResponse(new Uri("https://api.tinify.com/output"), outputResponseMessage);
+ return fakeResponse;
+ }
+
+ public static FakeResponseHandler Resize(this FakeResponseHandler fakeResponse)
+ {
+ var resizedCatStream = File.OpenRead(TinyPngTests.ResizedCat);
+ var resizeMessage = new HttpResponseMessage
+ {
+ StatusCode = System.Net.HttpStatusCode.OK,
+ Content = new StreamContent(resizedCatStream)
+ };
+ resizeMessage.Headers.Add("Image-Width", "150");
+ resizeMessage.Headers.Add("Image-Height", "150");
+
+ fakeResponse.AddFakePostResponse(new Uri("https://api.tinify.com/output"), resizeMessage);
+ return fakeResponse;
+ }
+
+ public static FakeResponseHandler S3(this FakeResponseHandler fakeResponse)
+ {
+ var amazonMessage = new HttpResponseMessage
+ {
+ StatusCode = System.Net.HttpStatusCode.OK
+ };
+ amazonMessage.Headers.Add("Location", "https://s3-ap-southeast-2.amazonaws.com/tinypng-test-bucket/path.jpg");
+
+ fakeResponse.AddFakePostResponse(new Uri("https://api.tinify.com/output"), amazonMessage);
+ return fakeResponse;
+ }
+ }
+
public class TinyPngTests
{
const string apiKey = "lolwat";
- const string Cat = "Resources/cat.jpg";
+ internal const string Cat = "Resources/cat.jpg";
+ internal const string CompressedCat = "Resources/compressedcat.jpg";
+ internal const string ResizedCat = "Resources/resizedcat.jpg";
- [Fact(Skip = "Integration")]
+ [Fact]
public async Task Compression()
{
var pngx = new TinyPngClient(apiKey);
+ pngx.httpClient = new HttpClient(new FakeResponseHandler().Compress());
var result = await pngx.Compress(Cat);
Assert.Equal("image/jpeg", result.Input.Type);
+ Assert.Equal(400, result.Output.Width);
+ Assert.Equal(400, result.Output.Height);
+
+ }
- Assert.Equal(300, result.Output.Width);
+ [Fact]
+ public async Task CompressionAndDownload()
+ {
+ var pngx = new TinyPngClient(apiKey);
+ pngx.httpClient = new HttpClient(new FakeResponseHandler()
+ .Compress()
+ .Download());
- Assert.Equal(182, (await result.GetImageByteData()).Length);
+ var result = await pngx.Compress(Cat);
+
+ var downloadResult = await pngx.Download(result);
+
+ Assert.Equal(16646, (await downloadResult.GetImageByteData()).Length);
}
- [Fact(Skip = "Integration")]
+ [Fact]
public async Task Resizing()
{
var pngx = new TinyPngClient(apiKey);
+ pngx.httpClient = new HttpClient(new FakeResponseHandler()
+ .Compress()
+ .Resize());
var result = await pngx.Compress(Cat);
- var resized = await pngx.Resize(result, new ScaleHeightResizeOperation(100));
+ var resized = await pngx.Resize(result, new ScaleHeightResizeOperation(150));
- Assert.Equal(7111, (await resized.GetImageByteData()).Length);
+ var resizedImageByteData = await resized.GetImageByteData();
- }
+ Assert.Equal(5970, resizedImageByteData.Length);
+ }
- [Fact(Skip = "Integration")]
+ [Fact]
public async Task CompressAndStoreToS3ShouldThrowIfS3HasNotBeenConfigured()
{
var pngx = new TinyPngClient(apiKey);
+ pngx.httpClient = new HttpClient(new FakeResponseHandler()
+ .Compress()
+ .S3());
var result = await pngx.Compress(Cat);
@@ -53,10 +153,13 @@ public async Task CompressAndStoreToS3ShouldThrowIfS3HasNotBeenConfigured()
private const string ApiKey = "lolwat";
private const string ApiAccessKey = "lolwat";
- [Fact(Skip = "Integration")]
+ [Fact]
public async Task CompressAndStoreToS3()
{
var pngx = new TinyPngClient(apiKey);
+ pngx.httpClient = new HttpClient(new FakeResponseHandler()
+ .Compress()
+ .S3());
var result = await pngx.Compress(Cat);