Browse Source

Change format for assets.

pull/579/head
Sebastian 5 years ago
parent
commit
e37a91b616
  1. 18
      backend/src/Squidex.Infrastructure/Assets/ImageFormat.cs
  2. 2
      backend/src/Squidex.Infrastructure/Assets/ImageInfo.cs
  3. 53
      backend/src/Squidex.Infrastructure/Assets/ImageSharp/ImageSharpAssetThumbnailGenerator.cs
  4. 10
      backend/src/Squidex.Infrastructure/Assets/ResizeOptions.cs
  5. 6
      backend/src/Squidex/Areas/Api/Controllers/Assets/Models/AssetContentQueryDto.cs
  6. 61
      backend/tests/Squidex.Infrastructure.Tests/Assets/ImageSharpAssetThumbnailGeneratorTests.cs
  7. BIN
      backend/tests/Squidex.Infrastructure.Tests/Assets/Images/logo.gif
  8. 0
      backend/tests/Squidex.Infrastructure.Tests/Assets/Images/logo.jpeg
  9. BIN
      backend/tests/Squidex.Infrastructure.Tests/Assets/Images/logo.tga
  10. 8
      backend/tests/Squidex.Infrastructure.Tests/Squidex.Infrastructure.Tests.csproj

18
backend/src/Squidex.Infrastructure/Assets/ImageFormat.cs

@ -0,0 +1,18 @@
// ==========================================================================
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex UG (haftungsbeschraenkt)
// All rights reserved. Licensed under the MIT license.
// ==========================================================================
namespace Squidex.Infrastructure.Assets
{
public enum ImageFormat
{
Auto,
PNG,
JPEG,
TGA,
GIF
}
}

2
backend/src/Squidex.Infrastructure/Assets/ImageInfo.cs

@ -9,6 +9,8 @@ namespace Squidex.Infrastructure.Assets
{
public sealed class ImageInfo
{
public string? Format { get; set; }
public int PixelWidth { get; }
public int PixelHeight { get; }

53
backend/src/Squidex.Infrastructure/Assets/ImageSharp/ImageSharpAssetThumbnailGenerator.cs

@ -10,7 +10,11 @@ using System.IO;
using System.Threading;
using System.Threading.Tasks;
using SixLabors.ImageSharp;
using SixLabors.ImageSharp.Formats;
using SixLabors.ImageSharp.Formats.Gif;
using SixLabors.ImageSharp.Formats.Jpeg;
using SixLabors.ImageSharp.Formats.Png;
using SixLabors.ImageSharp.Formats.Tga;
using SixLabors.ImageSharp.Metadata.Profiles.Exif;
using SixLabors.ImageSharp.Processing;
using ISResizeMode = SixLabors.ImageSharp.Processing.ResizeMode;
@ -44,17 +48,7 @@ namespace Squidex.Infrastructure.Assets.ImageSharp
{
using (var image = Image.Load(source, out var format))
{
var encoder = Configuration.Default.ImageFormatsManager.FindEncoder(format);
if (encoder == null)
{
throw new NotSupportedException();
}
if (options.Quality.HasValue && (encoder is JpegEncoder || !options.KeepFormat))
{
encoder = new JpegEncoder { Quality = options.Quality.Value };
}
var encoder = GetEncoder(options, format);
image.Mutate(x => x.AutoOrient());
@ -99,6 +93,39 @@ namespace Squidex.Infrastructure.Assets.ImageSharp
}
}
private static IImageEncoder GetEncoder(ResizeOptions options, SixLabors.ImageSharp.Formats.IImageFormat? format)
{
var encoder = Configuration.Default.ImageFormatsManager.FindEncoder(format);
if (encoder == null)
{
throw new NotSupportedException();
}
if (options.Quality.HasValue && (encoder is JpegEncoder || !options.KeepFormat) && options.Format == ImageFormat.Auto)
{
encoder = new JpegEncoder { Quality = options.Quality.Value };
}
else if (options.Format == ImageFormat.JPEG)
{
encoder = new JpegEncoder();
}
else if (options.Format == ImageFormat.PNG)
{
encoder = new PngEncoder();
}
else if (options.Format == ImageFormat.TGA)
{
encoder = new TgaEncoder();
}
else if (options.Format == ImageFormat.GIF)
{
encoder = new GifEncoder();
}
return encoder;
}
public Task<ImageInfo?> GetImageInfoAsync(Stream source)
{
Guard.NotNull(source, nameof(source));
@ -107,11 +134,13 @@ namespace Squidex.Infrastructure.Assets.ImageSharp
try
{
var image = Image.Identify(source);
var image = Image.Identify(source, out var format);
if (image != null)
{
result = GetImageInfo(image);
result.Format = format.Name;
}
}
catch

10
backend/src/Squidex.Infrastructure/Assets/ResizeOptions.cs

@ -11,6 +11,8 @@ namespace Squidex.Infrastructure.Assets
{
public sealed class ResizeOptions
{
public ImageFormat Format { get; set; }
public ResizeMode Mode { get; set; }
public int? Width { get; set; }
@ -27,7 +29,7 @@ namespace Squidex.Infrastructure.Assets
public bool IsValid
{
get { return Width > 0 || Height > 0 || Quality > 0; }
get { return Width > 0 || Height > 0 || Quality > 0 || Format != ImageFormat.Auto; }
}
public override string ToString()
@ -58,6 +60,12 @@ namespace Squidex.Infrastructure.Assets
sb.Append(FocusY);
}
if (Format != ImageFormat.Auto)
{
sb.Append("_format_");
sb.Append(Format.ToString());
}
return sb.ToString();
}
}

6
backend/src/Squidex/Areas/Api/Controllers/Assets/Models/AssetContentQueryDto.cs

@ -87,6 +87,12 @@ namespace Squidex.Areas.Api.Controllers.Assets.Models
[FromQuery(Name = "force")]
public bool ForceResize { get; set; }
/// <summary>
/// True to force a new resize even if it already stored.
/// </summary>
[FromQuery(Name = "format")]
public ImageFormat Format { get; set; }
public ResizeOptions ToResizeOptions(IAssetEntity asset)
{
Guard.NotNull(asset, nameof(asset));

61
backend/tests/Squidex.Infrastructure.Tests/Assets/ImageSharpAssetThumbnailGeneratorTests.cs

@ -6,7 +6,9 @@
// ==========================================================================
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using Squidex.Infrastructure.Assets.ImageSharp;
using Xunit;
@ -18,10 +20,43 @@ namespace Squidex.Infrastructure.Assets
private readonly ImageSharpAssetThumbnailGenerator sut = new ImageSharpAssetThumbnailGenerator();
private readonly MemoryStream target = new MemoryStream();
public static IEnumerable<object[]> GetConversions()
{
var allFormats = Enum.GetValues(typeof(ImageFormat)).OfType<ImageFormat>().Where(x => x != ImageFormat.Auto);
foreach (var source in allFormats)
{
foreach (var target in allFormats)
{
if (!Equals(target, source))
{
yield return new object[] { target, source };
}
}
}
}
[Theory]
[MemberData(nameof(GetConversions))]
public async Task Should_convert_between_formats(ImageFormat sourceFormat, ImageFormat targetFormat)
{
var source = GetImage(sourceFormat);
var options = new ResizeOptions { Format = targetFormat };
await sut.CreateThumbnailAsync(source, target, options);
target.Position = 0;
var imageInfo = await sut.GetImageInfoAsync(target);
Assert.Equal(targetFormat.ToString(), imageInfo?.Format);
}
[Fact]
public async Task Should_return_same_image_if_no_size_and_quality_is_passed_for_thumbnail()
{
var source = GetPng();
var source = GetImage(ImageFormat.PNG);
await sut.CreateThumbnailAsync(source, target, new ResizeOptions());
@ -31,7 +66,7 @@ namespace Squidex.Infrastructure.Assets
[Fact]
public async Task Should_resize_image_to_target()
{
var source = GetPng();
var source = GetImage(ImageFormat.PNG);
var options = new ResizeOptions { Width = 1000, Height = 1000, Mode = ResizeMode.BoxPad };
@ -43,7 +78,7 @@ namespace Squidex.Infrastructure.Assets
[Fact]
public async Task Should_change_jpeg_quality_and_write_to_target()
{
var source = GetJpeg();
var source = GetImage(ImageFormat.JPEG);
var options = new ResizeOptions { Quality = 10 };
@ -55,7 +90,7 @@ namespace Squidex.Infrastructure.Assets
[Fact]
public async Task Should_change_png_quality_and_write_to_target()
{
var source = GetPng();
var source = GetImage(ImageFormat.PNG);
var options = new ResizeOptions { Quality = 10 };
@ -73,18 +108,20 @@ namespace Squidex.Infrastructure.Assets
Assert.Equal(135, imageInfo.PixelHeight);
Assert.Equal(600, imageInfo.PixelWidth);
Assert.False(imageInfo.IsRotatedOrSwapped);
}
[Fact]
public async Task Should_return_image_information_if_image_is_valid()
{
var source = GetPng();
var source = GetImage(ImageFormat.PNG);
var imageInfo = await sut.GetImageInfoAsync(source);
Assert.Equal(600, imageInfo!.PixelHeight);
Assert.Equal(600, imageInfo!.PixelWidth);
Assert.False(imageInfo.IsRotatedOrSwapped);
}
@ -97,6 +134,7 @@ namespace Squidex.Infrastructure.Assets
Assert.Equal(600, imageInfo!.PixelHeight);
Assert.Equal(135, imageInfo!.PixelWidth);
Assert.True(imageInfo.IsRotatedOrSwapped);
}
@ -110,19 +148,18 @@ namespace Squidex.Infrastructure.Assets
Assert.Null(imageInfo);
}
private Stream GetPng()
private Stream GetImage(ImageFormat format)
{
return GetType().Assembly.GetManifestResourceStream("Squidex.Infrastructure.Assets.Images.logo.png")!;
}
var name = $"Squidex.Infrastructure.Assets.Images.logo.{format.ToString().ToLowerInvariant()}";
private Stream GetJpeg()
{
return GetType().Assembly.GetManifestResourceStream("Squidex.Infrastructure.Assets.Images.logo.jpg")!;
return GetType().Assembly.GetManifestResourceStream(name)!;
}
private Stream GetRotatedJpeg()
{
return GetType().Assembly.GetManifestResourceStream("Squidex.Infrastructure.Assets.Images.logo-wide-rotated.jpg")!;
var name = "Squidex.Infrastructure.Assets.Images.logo-wide-rotated.jpg";
return GetType().Assembly.GetManifestResourceStream(name)!;
}
}
}

BIN
backend/tests/Squidex.Infrastructure.Tests/Assets/Images/logo.gif

Binary file not shown.

After

Width:  |  Height:  |  Size: 314 KiB

0
backend/tests/Squidex.Infrastructure.Tests/Assets/Images/logo.jpg → backend/tests/Squidex.Infrastructure.Tests/Assets/Images/logo.jpeg

Before

Width:  |  Height:  |  Size: 47 KiB

After

Width:  |  Height:  |  Size: 47 KiB

BIN
backend/tests/Squidex.Infrastructure.Tests/Assets/Images/logo.tga

Binary file not shown.

8
backend/tests/Squidex.Infrastructure.Tests/Squidex.Infrastructure.Tests.csproj

@ -8,8 +8,10 @@
</PropertyGroup>
<ItemGroup>
<None Remove="Assets\Images\logo-wide-rotated.jpg" />
<None Remove="Assets\Images\logo.jpg" />
<None Remove="Assets\Images\logo.gif" />
<None Remove="Assets\Images\logo.jpeg" />
<None Remove="Assets\Images\logo.png" />
<None Remove="Assets\Images\logo.tga" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\Squidex.Infrastructure.Amazon\Squidex.Infrastructure.Amazon.csproj" />
@ -47,8 +49,10 @@
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="Assets\Images\logo-wide-rotated.jpg" />
<EmbeddedResource Include="Assets\Images\logo.jpg" />
<EmbeddedResource Include="Assets\Images\logo.gif" />
<EmbeddedResource Include="Assets\Images\logo.jpeg" />
<EmbeddedResource Include="Assets\Images\logo.png" />
<EmbeddedResource Include="Assets\Images\logo.tga" />
</ItemGroup>
<ItemGroup>
<Compile Update="Translations\SampleResources.Designer.cs">

Loading…
Cancel
Save