Simplified image handling

This commit is contained in:
MarcinZiabek
2023-05-09 01:11:49 +02:00
parent bdb61aa545
commit 1829ed7180
8 changed files with 56 additions and 90 deletions
@@ -235,7 +235,6 @@ namespace QuestPDF.Drawing
if (x is QuestPDF.Elements.Image image) if (x is QuestPDF.Elements.Image image)
{ {
image.TargetDpi ??= settings.RasterDpi; image.TargetDpi ??= settings.RasterDpi;
image.ResizeStrategy ??= settings.ImageResizeStrategy;
image.CompressionQuality ??= settings.ImageCompressionQuality; image.CompressionQuality ??= settings.ImageCompressionQuality;
} }
+6 -3
View File
@@ -30,8 +30,11 @@ namespace QuestPDF.Elements
if (imageData == null) if (imageData == null)
return; return;
using var image = SKImage.FromEncodedData(imageData); using var originalImage = SKImage.FromEncodedData(imageData);
Canvas.DrawImage(image, Position.Zero, availableSpace); using var compressedImage = originalImage.CompressImage(CompressionQuality.Value);
var targetImage = Helpers.Helpers.GetImageWithSmallerSize(originalImage, compressedImage);
Canvas.DrawImage(targetImage, Position.Zero, availableSpace);
} }
private static ImageSize GetTargetResolution(Size availableSize, int targetDpi) private static ImageSize GetTargetResolution(Size availableSize, int targetDpi)
@@ -44,4 +47,4 @@ namespace QuestPDF.Elements
); );
} }
} }
} }
+13 -35
View File
@@ -12,7 +12,6 @@ namespace QuestPDF.Elements
internal bool UseOriginalImage { get; set; } internal bool UseOriginalImage { get; set; }
internal int? TargetDpi { get; set; } internal int? TargetDpi { get; set; }
internal ImageCompressionQuality? CompressionQuality { get; set; } internal ImageCompressionQuality? CompressionQuality { get; set; }
internal ImageResizeStrategy? ResizeStrategy { get; set; }
private const float ImageSizeSimilarityToleranceMax = 0.75f; private const float ImageSizeSimilarityToleranceMax = 0.75f;
@@ -40,56 +39,35 @@ namespace QuestPDF.Elements
private SKImage GetImageToDraw(Size availableSpace) private SKImage GetImageToDraw(Size availableSpace)
{ {
var originalImage = DocumentImage.SkImage;
if (UseOriginalImage) if (UseOriginalImage)
return DocumentImage.SkImage; return originalImage;
var request = new GetImageVersionRequest var request = new GetImageVersionRequest
{ {
Resolution = GetTargetResolution(ResizeStrategy.Value, DocumentImage.Size, availableSpace, TargetDpi.Value), Resolution = GetTargetResolution(DocumentImage.Size, availableSpace, TargetDpi.Value),
CompressionQuality = CompressionQuality.Value, CompressionQuality = CompressionQuality.Value
ResizeStrategy = ResizeStrategy.Value
}; };
return DocumentImage.GetVersionOfSize(request); var targetImage = DocumentImage.GetVersionOfSize(request);
return Helpers.Helpers.GetImageWithSmallerSize(originalImage, targetImage);
} }
private static ImageSize GetTargetResolution(ImageResizeStrategy resizeStrategy, ImageSize imageResolution, Size availableAreaSize, int targetDpi) private static ImageSize GetTargetResolution(ImageSize imageResolution, Size availableAreaSize, int targetDpi)
{ {
if (resizeStrategy == ImageResizeStrategy.Never)
return imageResolution;
var scalingFactor = targetDpi / (float)DocumentSettings.DefaultRasterDpi; var scalingFactor = targetDpi / (float)DocumentSettings.DefaultRasterDpi;
var targetResolution = new ImageSize( var targetResolution = new ImageSize(
(int)(availableAreaSize.Width * scalingFactor), (int)(availableAreaSize.Width * scalingFactor),
(int)(availableAreaSize.Height * scalingFactor)); (int)(availableAreaSize.Height * scalingFactor));
if (resizeStrategy == ImageResizeStrategy.Always)
return targetResolution;
var isSignificantlySmaller = IsImageSignificantlySmallerThanDrawingArea(imageResolution, targetResolution); var isImageResolutionSmallerThanTarget = imageResolution.Width < targetResolution.Width || imageResolution.Height < targetResolution.Height;
if (resizeStrategy == ImageResizeStrategy.ScaleOnlyToSignificantlySmallerResolution && isSignificantlySmaller)
return targetResolution;
var isSmaller = IsImageSmallerThanDrawingArea(imageResolution, targetResolution); if (isImageResolutionSmallerThanTarget)
return imageResolution;
if (resizeStrategy == ImageResizeStrategy.ScaleOnlyToSmallerResolution && isSmaller) return targetResolution;
return targetResolution;
return imageResolution;
}
private static bool IsImageSmallerThanDrawingArea(ImageSize imageResolution, ImageSize targetResolution)
{
return imageResolution.Width < targetResolution.Width || imageResolution.Height < targetResolution.Height;
}
private static bool IsImageSignificantlySmallerThanDrawingArea(ImageSize imageResolution, ImageSize targetResolution, float sizeSimilarityThreshold = ImageSizeSimilarityToleranceMax)
{
var widthRatio = targetResolution.Width / imageResolution.Width;
var heightRatio = targetResolution.Height / imageResolution.Height;
return widthRatio < sizeSimilarityThreshold && heightRatio < sizeSimilarityThreshold;
} }
} }
} }
@@ -52,12 +52,6 @@ namespace QuestPDF.Fluent
return this; return this;
} }
public ImageDescriptor WithResizeStrategy(ImageResizeStrategy strategy)
{
ImageElement.ResizeStrategy = strategy;
return this;
}
#region Aspect Ratio #region Aspect Ratio
public ImageDescriptor FitWidth() public ImageDescriptor FitWidth()
+33
View File
@@ -75,5 +75,38 @@ namespace QuestPDF.Helpers
_ => throw new ArgumentOutOfRangeException(nameof(quality), quality, null) _ => throw new ArgumentOutOfRangeException(nameof(quality), quality, null)
}; };
} }
internal static SKImage CompressImage(this SKImage image, ImageCompressionQuality compressionQuality)
{
var targetFormat = image.Info.IsOpaque
? SKEncodedImageFormat.Jpeg
: SKEncodedImageFormat.Png;
if (targetFormat == SKEncodedImageFormat.Png)
compressionQuality = ImageCompressionQuality.Best;
var data = image.Encode(targetFormat, compressionQuality.ToQualityValue());
return SKImage.FromEncodedData(data);
}
internal static SKImage ResizeAndCompressImage(this SKImage image, ImageSize targetResolution, ImageCompressionQuality compressionQuality)
{
if (image.Width == targetResolution.Width && image.Height == targetResolution.Height)
return CompressImage(image, compressionQuality);
var imageInfo = new SKImageInfo(targetResolution.Width, targetResolution.Height);
using var resultImage = SKImage.Create(imageInfo);
image.ScalePixels(resultImage.PeekPixels(), SKFilterQuality.Medium);
return CompressImage(resultImage, compressionQuality);
}
internal static SKImage GetImageWithSmallerSize(SKImage one, SKImage second)
{
return one.EncodedData.Size < second.EncodedData.Size
? one
: second;
}
} }
} }
@@ -18,17 +18,14 @@
/// The default value is 90 (very high quality). /// The default value is 90 (very high quality).
/// </summary> /// </summary>
public ImageCompressionQuality ImageCompressionQuality { get; set; } = ImageCompressionQuality.VeryHigh; public ImageCompressionQuality ImageCompressionQuality { get; set; } = ImageCompressionQuality.VeryHigh;
// TODO: add comments
public ImageResizeStrategy ImageResizeStrategy { get; set; } = ImageResizeStrategy.ScaleOnlyToSignificantlySmallerResolution;
/// <summary> /// <summary>
/// The DPI (pixels-per-inch) at which images and features without native PDF support will be rasterized. /// The DPI (pixels-per-inch) at which images and features without native PDF support will be rasterized.
/// A larger DPI would create a PDF that reflects the original intent with better fidelity, but it can make for larger PDF files too, which would use more memory while rendering, and it would be slower to be processed or sent online or to printer. /// A larger DPI would create a PDF that reflects the original intent with better fidelity, but it can make for larger PDF files too, which would use more memory while rendering, and it would be slower to be processed or sent online or to printer.
/// When generating images, this parameter also controls the resolution of the generated content. /// When generating images, this parameter also controls the resolution of the generated content.
/// Default value is 72. /// Default value is 144.
/// </summary> /// </summary>
public int RasterDpi { get; set; } = DefaultRasterDpi; public int RasterDpi { get; set; } = DefaultRasterDpi * 2;
public ContentDirection ContentDirection { get; set; } = ContentDirection.LeftToRight; public ContentDirection ContentDirection { get; set; } = ContentDirection.LeftToRight;
+1 -28
View File
@@ -11,7 +11,6 @@ namespace QuestPDF.Infrastructure
{ {
internal ImageSize Resolution { get; set; } internal ImageSize Resolution { get; set; }
internal ImageCompressionQuality CompressionQuality { get; set; } internal ImageCompressionQuality CompressionQuality { get; set; }
internal ImageResizeStrategy ResizeStrategy { get; set; }
} }
public class Image : IDisposable public class Image : IDisposable
@@ -46,37 +45,11 @@ namespace QuestPDF.Infrastructure
return cacheKey.image; return cacheKey.image;
} }
var result = ResizeAndCompressImage(SkImage, request.Resolution, request.CompressionQuality); var result = SkImage.ResizeAndCompressImage(request.Resolution, request.CompressionQuality);
ScaledImageCache.AddLast((request, result)); ScaledImageCache.AddLast((request, result));
return result; return result;
} }
private static SKImage CompressImage(SKImage image, ImageCompressionQuality compressionQuality)
{
var targetFormat = image.Info.IsOpaque
? SKEncodedImageFormat.Jpeg
: SKEncodedImageFormat.Png;
if (targetFormat == SKEncodedImageFormat.Png)
compressionQuality = ImageCompressionQuality.Best;
var data = image.Encode(targetFormat, compressionQuality.ToQualityValue());
return SKImage.FromEncodedData(data);
}
private static SKImage ResizeAndCompressImage(SKImage image, ImageSize targetResolution, ImageCompressionQuality compressionQuality)
{
if (image.Width == targetResolution.Width && image.Height == targetResolution.Height)
return CompressImage(image, compressionQuality);
var imageInfo = new SKImageInfo(targetResolution.Width, targetResolution.Height);
using var resultImage = SKImage.Create(imageInfo);
image.ScalePixels(resultImage.PeekPixels(), SKFilterQuality.Medium);
return CompressImage(resultImage, compressionQuality);
}
#endregion #endregion
#region public constructors #region public constructors
@@ -1,11 +0,0 @@
namespace QuestPDF.Infrastructure
{
public enum ImageResizeStrategy
{
// TODO: add comments
Always,
ScaleOnlyToSmallerResolution,
ScaleOnlyToSignificantlySmallerResolution,
Never
}
}