diff --git a/src/Orchard.Web/Modules/Orchard.MediaProcessing/Orchard.MediaProcessing.csproj b/src/Orchard.Web/Modules/Orchard.MediaProcessing/Orchard.MediaProcessing.csproj index eba93aabd..c70eb9caa 100644 --- a/src/Orchard.Web/Modules/Orchard.MediaProcessing/Orchard.MediaProcessing.csproj +++ b/src/Orchard.Web/Modules/Orchard.MediaProcessing/Orchard.MediaProcessing.csproj @@ -112,9 +112,7 @@ - - - + diff --git a/src/Orchard.Web/Modules/Orchard.MediaProcessing/Providers/Filters/ConstrainFilter.cs b/src/Orchard.Web/Modules/Orchard.MediaProcessing/Providers/Filters/ConstrainFilter.cs deleted file mode 100644 index 5a8d5b6ac..000000000 --- a/src/Orchard.Web/Modules/Orchard.MediaProcessing/Providers/Filters/ConstrainFilter.cs +++ /dev/null @@ -1,97 +0,0 @@ -using System; -using System.Web.Mvc; -using ImageResizer; -using Orchard.DisplayManagement; -using Orchard.Forms.Services; -using Orchard.Localization; -using Orchard.MediaProcessing.Descriptors.Filter; -using Orchard.MediaProcessing.Services; - -namespace Orchard.MediaProcessing.Providers.Filters { - public class ConstrainFilter : IImageFilterProvider { - public ConstrainFilter() { - T = NullLocalizer.Instance; - } - - public Localizer T { get; set; } - - public void Describe(DescribeFilterContext describe) { - describe.For("Transform", T("Transform"), T("Transform")) - .Element("Constrain", T("Constrain"), T("Constrains the dimensions of an image either by with of by height"), - ApplyFilter, - DisplayFilter, - "ContrainImageFilter" - ); - } - - public void ApplyFilter(FilterContext context) { - var value = (int)context.State.Value; - var axis = (string)context.State.Axis; - - - - var settings = new ResizeSettings { - Mode = FitMode.Max - }; - - switch (axis) { - case "width": - settings.Width = value; - break; - case "height": - settings.Height = value; - break; - } - - - context.Media = result; - } - - public LocalizedString DisplayFilter(FilterContext context) { - var value = (int)context.State.Value; - var axis = (string)context.State.Axis; - - return axis == "height" - ? T("Constrain to {0}px high", value) - : T("Constrain to {0}px wide", value); - } - } - - public class ConstrainFilterFilterForms : IFormProvider { - protected dynamic Shape { get; set; } - public Localizer T { get; set; } - - public ConstrainFilterFilterForms( - IShapeFactory shapeFactory) { - Shape = shapeFactory; - T = NullLocalizer.Instance; - } - - public void Describe(DescribeContext context) { - Func form = - shape => { - var f = Shape.Form( - Id: "ContrainImageFilter", - _Axis: Shape.SelectList( - Id: "axis", Name: "Axis", - Title: T("Axis"), - Size: 1, - Multiple: false - ), - _Height: Shape.Textbox( - Id: "value", Name: "Value", - Title: T("Value"), - Description: T("The value in pixel the selected axis should be constrained to. Mandatory."), - Classes: new[] {"text-small"}) - ); - - f._Axis.Add(new SelectListItem { Value = "height", Text = T("Height").Text }); - f._Axis.Add(new SelectListItem { Value = "width", Text = T("Width").Text }); - - return f; - }; - - context.Form("ContrainImageFilter", form); - } - } -} \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.MediaProcessing/Providers/Filters/CropFilter.cs b/src/Orchard.Web/Modules/Orchard.MediaProcessing/Providers/Filters/CropFilter.cs deleted file mode 100644 index c0fbb6c3d..000000000 --- a/src/Orchard.Web/Modules/Orchard.MediaProcessing/Providers/Filters/CropFilter.cs +++ /dev/null @@ -1,89 +0,0 @@ -using System; -using System.Drawing; -using Orchard.DisplayManagement; -using Orchard.Forms.Services; -using Orchard.Localization; -using Orchard.MediaProcessing.Descriptors.Filter; -using Orchard.MediaProcessing.Services; - -namespace Orchard.MediaProcessing.Providers.Filters { - public class CropFilter : IImageFilterProvider { - public CropFilter() { - T = NullLocalizer.Instance; - } - - public Localizer T { get; set; } - - public void Describe(DescribeFilterContext describe) { - describe.For("Transform", T("Transform"), T("Transform")) - .Element("Crop", T("Crop"), T("Crops to a fixed height and width"), - ApplyFilter, - DisplayFilter, - "CropFilter" - ); - } - - public void ApplyFilter(FilterContext context) { - var newHeight = int.Parse(context.State.Height); - newHeight = newHeight > 0 ? newHeight : context.Media.Height; - var heightFactor = (float) context.Media.Height/newHeight; - - var newWidth = int.Parse(context.State.Width); - newWidth = newWidth > 0 ? newWidth : context.Media.Width; - var widthFactor = context.Media.Width/newWidth; - - if (widthFactor != heightFactor) { - if (widthFactor > heightFactor) { - newHeight = Convert.ToInt32(context.Media.Height/widthFactor); - } - else { - newWidth = Convert.ToInt32(context.Media.Width/heightFactor); - } - } - - var newImage = new Bitmap(newWidth, newHeight); - using (var graphics = Graphics.FromImage(newImage)) { - graphics.DrawImage(context.Media, 0, 0, new Rectangle(0, 0, newWidth, newHeight), GraphicsUnit.Pixel); - } - - context.Media = newImage; - } - - public LocalizedString DisplayFilter(FilterContext context) { - return T("Crop to {0}px high x {1}px wide", context.State.Height, context.State.Width); - } - } - - public class CropFilterForms : IFormProvider { - protected dynamic Shape { get; set; } - public Localizer T { get; set; } - - public CropFilterForms( - IShapeFactory shapeFactory) { - Shape = shapeFactory; - T = NullLocalizer.Instance; - } - - public void Describe(DescribeContext context) { - Func form = - shape => { - var f = Shape.Form( - Id: "ImageCropFilter", - _Height: Shape.Textbox( - Id: "height", Name: "Height", - Title: T("Height"), - Description: T("The height in pixels, 0 to allow any value."), - Classes: new[] {"text-small"}), - _Width: Shape.Textbox( - Id: "width", Name: "Width", - Title: T("Width"), - Description: T("The width in pixels, 0 to allow any value."), - Classes: new[] {"text-small"})); - - return f; - }; - - context.Form("CropFilter", form); - } - } -} \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.MediaProcessing/Providers/Filters/FormatFilter.cs b/src/Orchard.Web/Modules/Orchard.MediaProcessing/Providers/Filters/FormatFilter.cs new file mode 100644 index 000000000..46fa9412e --- /dev/null +++ b/src/Orchard.Web/Modules/Orchard.MediaProcessing/Providers/Filters/FormatFilter.cs @@ -0,0 +1,92 @@ +using System; +using System.IO; +using System.Web.Mvc; +using ImageResizer; +using Orchard.DisplayManagement; +using Orchard.Forms.Services; +using Orchard.Localization; +using Orchard.MediaProcessing.Descriptors.Filter; +using Orchard.MediaProcessing.Services; + +namespace Orchard.MediaProcessing.Providers.Filters { + public class FormatFilter : IImageFilterProvider { + public FormatFilter() { + T = NullLocalizer.Instance; + } + + public Localizer T { get; set; } + + public void Describe(DescribeFilterContext describe) { + describe.For("Transform", T("Transform"), T("Transform")) + .Element("Format", T("Format"), T("Change the format of the image."), + ApplyFilter, + DisplayFilter, + "FormatFilter" + ); + } + + public void ApplyFilter(FilterContext context) { + string format = context.State.Format; + int quality = context.State.Quality; + + var settings = new ResizeSettings { + Quality = quality, + Format = format + }; + + var result = new MemoryStream(); + if (context.Media.CanSeek) { + context.Media.Seek(0, SeekOrigin.Begin); + } + + ImageBuilder.Current.Build(context.Media, result, settings); + + context.FilePath = Path.ChangeExtension(context.FilePath, format); + context.Media = result; + } + + public LocalizedString DisplayFilter(FilterContext context) { + return T("Format the image to {0}", (string)context.State.Format); + } + } + + public class FormatFilterForms : IFormProvider { + protected dynamic Shape { get; set; } + public Localizer T { get; set; } + + public FormatFilterForms( + IShapeFactory shapeFactory) { + Shape = shapeFactory; + T = NullLocalizer.Instance; + } + + public void Describe(DescribeContext context) { + Func form = + shape => { + var f = Shape.Form( + Id: "FormatFilter", + _Format: Shape.SelectList( + Id: "format", Name: "Format", + Title: T("Format"), + Description: T("The target format of the image."), + Size: 1, + Multiple: false), + _Quality: Shape.Textbox( + Id: "quality", Name: "Quality", + Title: T("Quality"), + Value: 90, + Description: T("JPeg compression quality, from 0 to 100."), + Classes: new[] { "text-small" }) + ); + + f._Format.Add(new SelectListItem { Value = "jpg", Text = T("Jpeg").Text }); + f._Format.Add(new SelectListItem { Value = "gif", Text = T("Gif").Text }); + f._Format.Add(new SelectListItem { Value = "png", Text = T("Png").Text }); + + return f; + }; + + context.Form("FormatFilter", form); + } + } +} \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.MediaProcessing/Providers/Filters/ImageFormatFilter.cs b/src/Orchard.Web/Modules/Orchard.MediaProcessing/Providers/Filters/ImageFormatFilter.cs deleted file mode 100644 index f52b5795d..000000000 --- a/src/Orchard.Web/Modules/Orchard.MediaProcessing/Providers/Filters/ImageFormatFilter.cs +++ /dev/null @@ -1,92 +0,0 @@ -using System; -using System.Drawing.Imaging; -using System.IO; -using System.Web.Mvc; -using Orchard.DisplayManagement; -using Orchard.Forms.Services; -using Orchard.Localization; -using Orchard.MediaProcessing.Descriptors.Filter; -using Orchard.MediaProcessing.Services; - -namespace Orchard.MediaProcessing.Providers.Filters { - public class ImageFormatFilter : IImageFilterProvider { - public ImageFormatFilter() { - T = NullLocalizer.Instance; - } - - public Localizer T { get; set; } - - public void Describe(DescribeFilterContext describe) { - describe.For("Transform", T("Transform"), T("Transform")) - .Element("ImageFormat", T("ImageFormat"), T("Changes the image file format"), - ApplyFilter, - DisplayFilter, - "ImageFormatFilter" - ); - } - - public void ApplyFilter(FilterContext context) { - context.Format = ImageFormatConverter.ToImageFormat((ImageFormats)Enum.Parse(typeof (ImageFormats), (string)context.State.ImageFormat)); - context.FilePath = Path.ChangeExtension(context.FilePath, context.Format.ToString().ToLower()); - } - - public LocalizedString DisplayFilter(FilterContext context) { - return T("Convert to {0}", context.State.ImageFormat.ToString()); - } - } - - public class ImageFormatFilterForms : IFormProvider { - protected dynamic Shape { get; set; } - public Localizer T { get; set; } - - public ImageFormatFilterForms( - IShapeFactory shapeFactory) { - Shape = shapeFactory; - T = NullLocalizer.Instance; - } - - public void Describe(DescribeContext context) { - Func form = - shape => { - var f = Shape.Form( - Id: "ImageFormatFilter", - _ImageFormat: Shape.SelectList( - Id: "imageformat", - Name: "ImageFormat" - )); - - foreach (var item in Enum.GetValues(typeof (ImageFormats))) { - var name = Enum.GetName(typeof (ImageFormats), item); - f._ImageFormat.Add(new SelectListItem {Value = item.ToString(), Text = name}); - } - - return f; - }; - - context.Form("ImageFormatFilter", form); - } - } - - public enum ImageFormats { - Bmp, - Gif, - Jpeg, - Png - } - - public class ImageFormatConverter { - public static ImageFormat ToImageFormat(ImageFormats format) { - switch (format) { - case ImageFormats.Bmp: - return ImageFormat.Bmp; - case ImageFormats.Gif: - return ImageFormat.Gif; - case ImageFormats.Jpeg: - return ImageFormat.Jpeg; - case ImageFormats.Png: - return ImageFormat.Png; - } - return ImageFormat.Jpeg; - } - } -} \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.MediaProcessing/Providers/Filters/ResizeFilter.cs b/src/Orchard.Web/Modules/Orchard.MediaProcessing/Providers/Filters/ResizeFilter.cs index 29e7cfd56..a097ea98b 100644 --- a/src/Orchard.Web/Modules/Orchard.MediaProcessing/Providers/Filters/ResizeFilter.cs +++ b/src/Orchard.Web/Modules/Orchard.MediaProcessing/Providers/Filters/ResizeFilter.cs @@ -1,7 +1,7 @@ using System; using System.Drawing; -using System.Drawing.Drawing2D; using System.IO; +using System.Web.Mvc; using ImageResizer; using Orchard.DisplayManagement; using Orchard.Forms.Services; @@ -29,6 +29,9 @@ namespace Orchard.MediaProcessing.Providers.Filters { public void ApplyFilter(FilterContext context) { int witdh = context.State.Width; int height = context.State.Height; + string mode = context.State.Mode; + string alignment = context.State.Alignment; + string padcolor = context.State.PadColor; var settings = new ResizeSettings { Mode = FitMode.Max, @@ -36,13 +39,45 @@ namespace Orchard.MediaProcessing.Providers.Filters { Width = witdh }; + switch (mode) { + case "max": settings.Mode = FitMode.Max; break; + case "pad": settings.Mode = FitMode.Pad; break; + case "crop": settings.Mode = FitMode.Crop; break; + case "stretch": settings.Mode = FitMode.Stretch; break; + } + + switch (alignment) { + case "topleft": settings.Anchor = ContentAlignment.TopLeft; break; + case "topcenter": settings.Anchor = ContentAlignment.TopCenter; break; + case "topright": settings.Anchor = ContentAlignment.TopRight; break; + case "middleleft": settings.Anchor = ContentAlignment.MiddleLeft; break; + case "middlecenter": settings.Anchor = ContentAlignment.MiddleCenter; break; + case "middleright": settings.Anchor = ContentAlignment.MiddleRight; break; + case "bottomleft": settings.Anchor = ContentAlignment.BottomLeft; break; + case "bottomcenter": settings.Anchor = ContentAlignment.BottomCenter; break; + case "bottomright": settings.Anchor = ContentAlignment.BottomRight; break; + } + + if (!String.IsNullOrWhiteSpace(padcolor)) { + if (padcolor.StartsWith("#")) { + ColorTranslator.FromHtml(padcolor); + } + else { + settings.PaddingColor = Color.FromName(padcolor); + } + + } + var result = new MemoryStream(); + if (context.Media.CanSeek) { + context.Media.Seek(0, SeekOrigin.Begin); + } ImageBuilder.Current.Build(context.Media, result, settings); context.Media = result; } public LocalizedString DisplayFilter(FilterContext context) { - return T("Resize to {0}px high x {1}px wide", context.State.Height, context.State.Width); + return T((string)context.State.Mode + " to {0}px high x {1}px wide", context.State.Height, context.State.Width); } } @@ -64,14 +99,50 @@ namespace Orchard.MediaProcessing.Providers.Filters { _Width: Shape.Textbox( Id: "width", Name: "Width", Title: T("Width"), - Description: T("The width in pixels, 0 to allow any value."), + Value: 0, + Description: T("The width in pixels."), Classes: new[] {"text-small"}), _Height: Shape.Textbox( Id: "height", Name: "Height", Title: T("Height"), - Description: T("The height in pixels, 0 to allow any value."), + Value: 0, + Description: T("The height in pixels."), + Classes: new[] {"text-small"}), + _Mode: Shape.SelectList( + Id: "mode", Name: "Mode", + Title: T("Mode"), + Description: T("How the image should be resized.
Max: adjusts to the max given width or left, keeping image ratio.
Pad: adds a padding so that the target image is exactly of width and height.
Crop: removes part of the image to fit with given height and width.
Stretch: stretches the image to fit within height and width."), + Size: 1, + Multiple: false), + _Alignment: Shape.SelectList( + Id: "alignment", Name: "Alignment", + Title: T("Alignment"), + Description: T("Select the alignment for Crop and Pad modes."), + Size: 1, + Multiple: false), + _PadColor: Shape.Textbox( + Id: "padcolor", Name: "PadColor", + Title: T("Pad Color"), + Value: "#ffffff", + Description: T("The background color to use to pad the image. Named color or hex value."), Classes: new[] {"text-small"}) - ); + ); + + f._Mode.Add(new SelectListItem { Value = "max", Text = T("Max").Text }); + f._Mode.Add(new SelectListItem { Value = "pad", Text = T("Pad").Text }); + f._Mode.Add(new SelectListItem { Value = "crop", Text = T("Crop").Text }); + f._Mode.Add(new SelectListItem { Value = "stretch", Text = T("Stretch").Text }); + + f._Alignment.Add(new SelectListItem { Value = "topleft", Text = T("Top Left").Text }); + f._Alignment.Add(new SelectListItem { Value = "topcenter", Text = T("Top Center").Text }); + f._Alignment.Add(new SelectListItem { Value = "topright", Text = T("Top Right").Text }); + f._Alignment.Add(new SelectListItem { Value = "middleleft", Text = T("Middle Left").Text }); + f._Alignment.Add(new SelectListItem { Value = "middlecenter", Text = T("Middle Center").Text }); + f._Alignment.Add(new SelectListItem { Value = "middleright", Text = T("Middle Right").Text }); + f._Alignment.Add(new SelectListItem { Value = "bottomleft", Text = T("Bottom Left").Text }); + f._Alignment.Add(new SelectListItem { Value = "bottomcenter", Text = T("Bottom Center").Text }); + f._Alignment.Add(new SelectListItem { Value = "bottomright", Text = T("Bottom Right").Text }); + return f; }; diff --git a/src/Orchard.Web/Modules/Orchard.MediaProcessing/Services/ImageProcessingFileNameProvider.cs b/src/Orchard.Web/Modules/Orchard.MediaProcessing/Services/ImageProcessingFileNameProvider.cs index 1895eaee2..39c32c7a9 100644 --- a/src/Orchard.Web/Modules/Orchard.MediaProcessing/Services/ImageProcessingFileNameProvider.cs +++ b/src/Orchard.Web/Modules/Orchard.MediaProcessing/Services/ImageProcessingFileNameProvider.cs @@ -1,8 +1,6 @@ using System.Collections.Generic; -using System.IO; using System.Linq; using Orchard.Caching; -using Orchard.Data; using Orchard.MediaProcessing.Models; namespace Orchard.MediaProcessing.Services { diff --git a/src/Orchard.Web/Modules/Orchard.MediaProcessing/Shapes/MediaShapes.cs b/src/Orchard.Web/Modules/Orchard.MediaProcessing/Shapes/MediaShapes.cs index a2d17fb07..b4de7c50d 100644 --- a/src/Orchard.Web/Modules/Orchard.MediaProcessing/Shapes/MediaShapes.cs +++ b/src/Orchard.Web/Modules/Orchard.MediaProcessing/Shapes/MediaShapes.cs @@ -35,7 +35,8 @@ namespace Orchard.MediaProcessing.Shapes { [Shape] public void ImageUrl(dynamic Display, TextWriter Output, string Profile, string Path) { var filePath = _fileNameProvider.Value.GetFileName(Profile, Path); - if (string.IsNullOrEmpty(filePath) || _storageProvider.Value.GetFile(filePath) == null) { + // todo: regenerate the file if the profile is newer, by getting IStorageFile. + if (string.IsNullOrEmpty(filePath) || !_storageProvider.Value.FileExists(filePath)) { try { var profilePart = _profileService.Value.GetImageProfileByName(Profile); if (profilePart == null) @@ -58,10 +59,12 @@ namespace Orchard.MediaProcessing.Shapes { var newFile = _storageProvider.Value.OpenOrCreate(filterContext.FilePath); using (var imageStream = newFile.OpenWrite()) { using (var sw = new BinaryWriter(imageStream)) { - filterContext.Media.Seek(0, SeekOrigin.Begin); + if (filterContext.Media.CanSeek) { + filterContext.Media.Seek(0, SeekOrigin.Begin); + } using (var sr = new BinaryReader(filterContext.Media)) { int count; - var buffer = new byte[1024]; + var buffer = new byte[8192]; while ((count = sr.Read(buffer, 0, buffer.Length)) != 0) { sw.Write(buffer, 0, count); } diff --git a/src/Orchard/FileSystems/Media/FileSystemStorageProvider.cs b/src/Orchard/FileSystems/Media/FileSystemStorageProvider.cs index 2bba24dce..9364e734c 100644 --- a/src/Orchard/FileSystems/Media/FileSystemStorageProvider.cs +++ b/src/Orchard/FileSystems/Media/FileSystemStorageProvider.cs @@ -70,7 +70,7 @@ namespace Orchard.FileSystems.Media { /// The relative path within the storage provider. /// True if the file exists; False otherwise. public bool FileExists(string path) { - return new FileInfo(MapStorage(path)).Exists; + return File.Exists(MapStorage(path)); } ///