ImageEffectsHelper.cs 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126
  1. using ImageMagick;
  2. using PicView.Core.FileHandling;
  3. namespace PicView.Core.ImageEffects;
  4. public static class ImageEffectsHelper
  5. {
  6. public static async Task<MagickImage?> GetRadialBlur(string file)
  7. {
  8. var magick = new MagickImage();
  9. await magick.ReadAsync(file).ConfigureAwait(false);
  10. ApplyRadialBlur(magick);
  11. return magick;
  12. }
  13. private static void ApplyRadialBlur(MagickImage magick)
  14. {
  15. magick.AdaptiveBlur(10);
  16. var morphology = new MorphologySettings
  17. {
  18. Kernel = Kernel.DoG,
  19. Method = MorphologyMethod.Convolve
  20. };
  21. magick.Morphology(morphology);
  22. }
  23. public static async Task<MagickImage?> ApplyEffects(FileInfo fileInfo, ImageEffectConfig config, CancellationToken cancellationToken)
  24. {
  25. try
  26. {
  27. return await Task.Run(async () =>
  28. {
  29. var magick = await LoadImage(fileInfo, cancellationToken);
  30. ApplyImageEffects(magick, config, cancellationToken);
  31. return magick;
  32. }, cancellationToken).ConfigureAwait(false);
  33. }
  34. catch (OperationCanceledException)
  35. {
  36. // Operation was canceled
  37. }
  38. catch (Exception e)
  39. {
  40. #if DEBUG
  41. Console.WriteLine(e);
  42. #endif
  43. }
  44. return null;
  45. }
  46. private static async Task<MagickImage> LoadImage(FileInfo fileInfo, CancellationToken cancellationToken)
  47. {
  48. await using var filestream = FileHelper.GetOptimizedFileStream(fileInfo);
  49. var magick = new MagickImage();
  50. if (fileInfo.Length >= 2147483648)
  51. {
  52. // ReSharper disable once MethodHasAsyncOverloadWithCancellation
  53. magick.Read(filestream);
  54. }
  55. else
  56. {
  57. await magick.ReadAsync(filestream, cancellationToken).ConfigureAwait(false);
  58. }
  59. return magick;
  60. }
  61. private static void ApplyImageEffects(MagickImage magick, ImageEffectConfig config, CancellationToken cancellationToken)
  62. {
  63. magick.BrightnessContrast(config.Brightness, config.Contrast);
  64. magick.BackgroundColor = MagickColors.Transparent;
  65. magick.Settings.BackgroundColor = MagickColors.Transparent;
  66. magick.Settings.FillColor = MagickColors.Transparent;
  67. if (config.Negative) ApplyNegative(magick);
  68. if (config.BlackAndWhite) ApplyBlackAndWhite(magick);
  69. if (config.OldMovie) ApplyOldMovieEffect(magick);
  70. if (config.SketchStrokeWidth != 0) ApplyPencilSketch(magick, config.SketchStrokeWidth);
  71. if (config.PosterizeLevel != 0) ApplyPosterize(magick, config.PosterizeLevel);
  72. if (config.BlurLevel != 0) ApplyBlur(magick, config.BlurLevel);
  73. if (config.Solarize.ToUInt32() != 0) ApplySolarize(magick, config.Solarize);
  74. cancellationToken.ThrowIfCancellationRequested();
  75. }
  76. private static void ApplyNegative(MagickImage magick) => magick.Negate();
  77. private static void ApplyBlackAndWhite(MagickImage magick) => magick.Grayscale();
  78. private static void ApplyOldMovieEffect(MagickImage magick)
  79. {
  80. magick.SepiaTone(new Percentage(80));
  81. magick.AddNoise(NoiseType.MultiplicativeGaussian);
  82. AddVerticalBands(magick);
  83. }
  84. private static void AddVerticalBands(MagickImage magick)
  85. {
  86. var random = new Random();
  87. for (var i = 0; i < magick.Width; i += random.Next(1, 50))
  88. {
  89. using var band = new MagickImage(new MagickColor("#3E382A"), (uint)random.Next(1, 3), magick.Height);
  90. band.Evaluate(Channels.Alpha, EvaluateOperator.Set, 0.2);
  91. magick.Composite(band, i, 0, CompositeOperator.Over);
  92. }
  93. }
  94. private static void ApplyPencilSketch(MagickImage magick, double sketchStrokeWidth)
  95. {
  96. magick.Charcoal(sketchStrokeWidth, 3);
  97. }
  98. private static void ApplyPosterize(MagickImage magick, int posterizeLevel)
  99. {
  100. magick.Posterize(posterizeLevel);
  101. }
  102. private static void ApplyBlur(MagickImage magick, double blurLevel)
  103. {
  104. magick.Blur(0, blurLevel);
  105. }
  106. private static void ApplySolarize(MagickImage magick, Percentage solarize)
  107. {
  108. magick.Solarize(solarize);
  109. }
  110. }