diff --git a/src/Umbraco.Core/IO/ResizedImage.cs b/src/Umbraco.Core/IO/ResizedImage.cs new file mode 100644 index 0000000000..bd96dcfb26 --- /dev/null +++ b/src/Umbraco.Core/IO/ResizedImage.cs @@ -0,0 +1,20 @@ +namespace Umbraco.Core.IO +{ + internal class ResizedImage + { + public ResizedImage() + { + } + + public ResizedImage(int width, int height, string fileName) + { + Width = width; + Height = height; + FileName = fileName; + } + + public int Width { get; set; } + public int Height { get; set; } + public string FileName { get; set; } + } +} \ No newline at end of file diff --git a/src/Umbraco.Core/IO/UmbracoMediaFile.cs b/src/Umbraco.Core/IO/UmbracoMediaFile.cs new file mode 100644 index 0000000000..e657d9507a --- /dev/null +++ b/src/Umbraco.Core/IO/UmbracoMediaFile.cs @@ -0,0 +1,253 @@ +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Drawing.Drawing2D; +using System.Drawing.Imaging; +using System.IO; +using System.Linq; +using System.Threading.Tasks; +using System.Web; +using Umbraco.Core.Configuration; + +namespace Umbraco.Core.IO +{ + public class UmbracoMediaFile + { + private readonly MediaFileSystem _fs; + + #region Constructors + + public UmbracoMediaFile() + { + _fs = FileSystemProviderManager.Current.GetFileSystemProvider(); + } + + public UmbracoMediaFile(string path) + { + _fs = FileSystemProviderManager.Current.GetFileSystemProvider(); + + Path = path; + + Initialize(); + } + + #endregion + + #region Static Methods + + //MB: Do we really need all these overloads? looking through the code, only one of them is actually used + + public static UmbracoMediaFile Save(HttpPostedFile file, string path) + { + return Save(file.InputStream, path); + } + + public static UmbracoMediaFile Save(HttpPostedFileBase file, string path) + { + return Save(file.InputStream, path); + } + + public static UmbracoMediaFile Save(Stream inputStream, string path) + { + var fs = FileSystemProviderManager.Current.GetFileSystemProvider(); + fs.AddFile(path, inputStream); + + return new UmbracoMediaFile(path); + } + + public static UmbracoMediaFile Save(byte[] file, string relativePath) + { + return Save(new MemoryStream(file), relativePath); + } + + public static UmbracoMediaFile Save(HttpPostedFile file) + { + var tempDir = System.IO.Path.Combine("uploads", Guid.NewGuid().ToString()); + return Save(file, tempDir); + } + + //filebase overload... + public static UmbracoMediaFile Save(HttpPostedFileBase file) + { + var tempDir = System.IO.Path.Combine("uploads", Guid.NewGuid().ToString()); + return Save(file, tempDir); + } + + #endregion + + private long? _length; + private Size? _size; + + /// + /// Initialized values that don't require opening the file. + /// + private void Initialize() + { + Filename = _fs.GetFileName(Path); + Extension = _fs.GetExtension(Path) != null + ? _fs.GetExtension(Path).Substring(1).ToLowerInvariant() + : ""; + Url = _fs.GetUrl(Path); + } + + public string Filename { get; private set; } + + public string Extension { get; private set; } + + public string Path { get; private set; } + + public string Url { get; private set; } + + /// + /// Get the length of the file in bytes + /// + /// + /// We are lazy loading this, don't go opening the file on ctor like we were doing. + /// + public long Length + { + get + { + if (_length == null) + { + _length = _fs.GetSize(Path); + } + return _length.Value; + } + } + + public bool SupportsResizing + { + get + { + return ("," + UmbracoSettings.ImageFileTypes + ",").Contains(string.Format(",{0},", Extension)); + } + } + + public string GetFriendlyName() + { + return Filename.SplitPascalCasing().ToFirstUpperInvariant(); + } + + public Size GetDimensions() + { + if (_size == null) + { + EnsureFileSupportsResizing(); + + var fs = _fs.OpenFile(Path); + var image = Image.FromStream(fs); + var fileWidth = image.Width; + var fileHeight = image.Height; + fs.Close(); + image.Dispose(); + + _size = new Size(fileWidth, fileHeight); + } + return _size.Value; + } + + public string Resize(int width, int height) + { + EnsureFileSupportsResizing(); + + var fileNameThumb = DoResize(width, height, 0, string.Empty); + + return _fs.GetUrl(fileNameThumb); + } + + public string Resize(int maxWidthHeight, string fileNameAddition) + { + EnsureFileSupportsResizing(); + + var fileNameThumb = DoResize(GetDimensions().Width, GetDimensions().Height, maxWidthHeight, fileNameAddition); + + return _fs.GetUrl(fileNameThumb); + } + + private string DoResize(int width, int height, int maxWidthHeight, string fileNameAddition) + { + using (var fs = _fs.OpenFile(Path)) + { + using (var image = Image.FromStream(fs)) + { + var fileNameThumb = string.IsNullOrWhiteSpace(fileNameAddition) + ? string.Format("{0}_UMBRACOSYSTHUMBNAIL.jpg", Path.Substring(0, Path.LastIndexOf(".", StringComparison.Ordinal))) + : string.Format("{0}_{1}.jpg", Path.Substring(0, Path.LastIndexOf(".", StringComparison.Ordinal)), fileNameAddition); + + var thumbnail = GenerateThumbnail(image, maxWidthHeight, width, height, fileNameThumb, maxWidthHeight == 0); + + return thumbnail.FileName; + } + } + } + + private void EnsureFileSupportsResizing() + { + if (SupportsResizing == false) + throw new InvalidOperationException(string.Format("The file {0} is not an image, so can't get dimensions", Filename)); + } + + private ResizedImage GenerateThumbnail(Image image, int maxWidthHeight, int fileWidth, int fileHeight, string thumbnailFileName, bool useFixedDimensions) + { + // Generate thumbnail + float f = 1; + if (useFixedDimensions == false) + { + var fx = (float)image.Size.Width / (float)maxWidthHeight; + var fy = (float)image.Size.Height / (float)maxWidthHeight; + + // must fit in thumbnail size + f = Math.Max(fx, fy); + } + + var widthTh = (int)Math.Round((float)fileWidth / f); + var heightTh = (int)Math.Round((float)fileHeight / f); + + // fixes for empty width or height + if (widthTh == 0) + widthTh = 1; + if (heightTh == 0) + heightTh = 1; + + // Create new image with best quality settings + using (var bp = new Bitmap(widthTh, heightTh)) + { + using (var g = Graphics.FromImage(bp)) + { + g.SmoothingMode = SmoothingMode.HighQuality; + g.InterpolationMode = InterpolationMode.HighQualityBicubic; + g.PixelOffsetMode = PixelOffsetMode.HighQuality; + g.CompositingQuality = CompositingQuality.HighQuality; + + // Copy the old image to the new and resized + var rect = new Rectangle(0, 0, widthTh, heightTh); + g.DrawImage(image, rect, 0, 0, image.Width, image.Height, GraphicsUnit.Pixel); + + // Copy metadata + var imageEncoders = ImageCodecInfo.GetImageEncoders(); + + var codec = Extension.ToLower() == "png" || Extension.ToLower() == "gif" + ? imageEncoders.Single(t => t.MimeType.Equals("image/png")) + : imageEncoders.Single(t => t.MimeType.Equals("image/jpeg")); + + // Set compresion ratio to 90% + var ep = new EncoderParameters(); + ep.Param[0] = new EncoderParameter(Encoder.Quality, 90L); + + // Save the new image using the dimensions of the image + var newFileName = thumbnailFileName.Replace("UMBRACOSYSTHUMBNAIL", string.Format("{0}x{1}", widthTh, heightTh)); + using (var ms = new MemoryStream()) + { + bp.Save(ms, codec, ep); + ms.Seek(0, 0); + + _fs.AddFile(newFileName, ms); + } + + return new ResizedImage(widthTh, heightTh, newFileName); + } + } + } + } +} diff --git a/src/Umbraco.Core/Umbraco.Core.csproj b/src/Umbraco.Core/Umbraco.Core.csproj index 5600a8da26..137a2bfbe5 100644 --- a/src/Umbraco.Core/Umbraco.Core.csproj +++ b/src/Umbraco.Core/Umbraco.Core.csproj @@ -173,6 +173,8 @@ + + diff --git a/src/umbraco.cms/businesslogic/Files/IFile.cs b/src/umbraco.cms/businesslogic/Files/IFile.cs index ccf858fb02..5f018b688f 100644 --- a/src/umbraco.cms/businesslogic/Files/IFile.cs +++ b/src/umbraco.cms/businesslogic/Files/IFile.cs @@ -5,6 +5,7 @@ using System.Text; namespace umbraco.cms.businesslogic.Files { + [Obsolete("This is no longer used ane will be removed from the codebase in the future")] public interface IFile { string Filename { get; } diff --git a/src/umbraco.cms/businesslogic/Files/NotAnImageException.cs b/src/umbraco.cms/businesslogic/Files/NotAnImageException.cs index 2d0ff67635..7ea71e2426 100644 --- a/src/umbraco.cms/businesslogic/Files/NotAnImageException.cs +++ b/src/umbraco.cms/businesslogic/Files/NotAnImageException.cs @@ -5,6 +5,7 @@ using System.Text; namespace umbraco.cms.businesslogic.Files { + [Obsolete("This is no longer used ane will be removed from the codebase in the future")] public class NotAnImageException : Exception { public NotAnImageException() diff --git a/src/umbraco.cms/businesslogic/Files/UmbracoFile.cs b/src/umbraco.cms/businesslogic/Files/UmbracoFile.cs index a37adad5b7..5822e8c72c 100644 --- a/src/umbraco.cms/businesslogic/Files/UmbracoFile.cs +++ b/src/umbraco.cms/businesslogic/Files/UmbracoFile.cs @@ -10,24 +10,26 @@ using Umbraco.Core.IO; namespace umbraco.cms.businesslogic.Files { + [Obsolete("Use Umbraco.Core.IO.UmbracoMediaFile instead")] public class UmbracoFile : IFile { - private readonly MediaFileSystem _fs; - + private readonly UmbracoMediaFile _mediaFile; + #region Constructors public UmbracoFile() { - _fs = FileSystemProviderManager.Current.GetFileSystemProvider(); + _mediaFile = new UmbracoMediaFile(); } public UmbracoFile(string path) { - _fs = FileSystemProviderManager.Current.GetFileSystemProvider(); + _mediaFile = new UmbracoMediaFile(path); + } - Path = path; - - Initialize(); + internal UmbracoFile(UmbracoMediaFile mediaFile) + { + _mediaFile = mediaFile; } #endregion @@ -38,57 +40,46 @@ namespace umbraco.cms.businesslogic.Files public static UmbracoFile Save(HttpPostedFile file, string path) { - return Save(file.InputStream, path); + return new UmbracoFile(UmbracoMediaFile.Save(file.InputStream, path)); } public static UmbracoFile Save(HttpPostedFileBase file, string path) { - return Save(file.InputStream, path); + return new UmbracoFile(UmbracoMediaFile.Save(file.InputStream, path)); } public static UmbracoFile Save(Stream inputStream, string path) { - var fs = FileSystemProviderManager.Current.GetFileSystemProvider(); - fs.AddFile(path, inputStream); - - return new UmbracoFile(path); + return new UmbracoFile(UmbracoMediaFile.Save(inputStream, path)); } public static UmbracoFile Save(byte[] file, string relativePath) { - return Save(new MemoryStream(file), relativePath); + return new UmbracoFile(UmbracoMediaFile.Save(new MemoryStream(file), relativePath)); } public static UmbracoFile Save(HttpPostedFile file) { - var tempDir = System.IO.Path.Combine("uploads", Guid.NewGuid().ToString()); - return Save(file, tempDir); + return new UmbracoFile(UmbracoMediaFile.Save(file)); } //filebase overload... public static UmbracoFile Save(HttpPostedFileBase file) { - var tempDir = System.IO.Path.Combine("uploads", Guid.NewGuid().ToString()); - return Save(file, tempDir); + return new UmbracoFile(UmbracoMediaFile.Save(file)); } #endregion - - private void Initialize() + + public string Filename { - Filename = _fs.GetFileName(Path); - Length = _fs.GetSize(Path); - Extension = _fs.GetExtension(Path) != null - ? _fs.GetExtension(Path).Substring(1).ToLowerInvariant() - : ""; - Url = _fs.GetUrl(Path); + get { return _mediaFile.Filename; } } - #region IFile Members - - public string Filename { get; private set; } - - public string Extension { get; private set; } + public string Extension + { + get { return _mediaFile.Extension; } + } [Obsolete("LocalName is obsolete, please use Url instead", false)] public string LocalName @@ -96,160 +87,47 @@ namespace umbraco.cms.businesslogic.Files get { return Url; } } - public string Path { get; private set; } + public string Path + { + get { return _mediaFile.Path; } + } - public string Url { get; private set; } + public string Url + { + get { return _mediaFile.Url; } + } - public long Length { get; private set; } + public long Length + { + get { return _mediaFile.Length; } + } public bool SupportsResizing { - get - { - return ("," + UmbracoSettings.ImageFileTypes + ",").Contains(string.Format(",{0},", Extension)); - } + get { return _mediaFile.SupportsResizing; } } public string GetFriendlyName() { - return Filename.SplitPascalCasing().ToFirstUpperInvariant(); + return _mediaFile.GetFriendlyName(); } public System.Tuple GetDimensions() { - EnsureFileSupportsResizing(); - - var fs = _fs.OpenFile(Path); - var image = Image.FromStream(fs); - var fileWidth = image.Width; - var fileHeight = image.Height; - fs.Close(); - image.Dispose(); - - return new System.Tuple(fileWidth, fileHeight); + var size = _mediaFile.GetDimensions(); + return new System.Tuple(size.Width, size.Height); } public string Resize(int width, int height) { - EnsureFileSupportsResizing(); - - var fileNameThumb = DoResize(width, height, 0, string.Empty); - - return _fs.GetUrl(fileNameThumb); + return _mediaFile.Resize(width, height); } public string Resize(int maxWidthHeight, string fileNameAddition) { - EnsureFileSupportsResizing(); - - var fileNameThumb = DoResize(GetDimensions().Item1, GetDimensions().Item2, maxWidthHeight, fileNameAddition); - - return _fs.GetUrl(fileNameThumb); + return _mediaFile.Resize(maxWidthHeight, fileNameAddition); } - private string DoResize(int width, int height, int maxWidthHeight, string fileNameAddition) - { - using (var fs = _fs.OpenFile(Path)) - { - using (var image = Image.FromStream(fs)) - { - var fileNameThumb = string.IsNullOrWhiteSpace(fileNameAddition) - ? string.Format("{0}_UMBRACOSYSTHUMBNAIL.jpg", Path.Substring(0, Path.LastIndexOf(".", StringComparison.Ordinal))) - : string.Format("{0}_{1}.jpg", Path.Substring(0, Path.LastIndexOf(".", StringComparison.Ordinal)), fileNameAddition); - - var thumbnail = GenerateThumbnail(image, maxWidthHeight, width, height, fileNameThumb, maxWidthHeight == 0); - - return thumbnail.FileName; - } - } - } - - #endregion - - private void EnsureFileSupportsResizing() - { - if (SupportsResizing == false) - throw new NotAnImageException(string.Format("The file {0} is not an image, so can't get dimensions", Filename)); - } - - private ResizedImage GenerateThumbnail(Image image, int maxWidthHeight, int fileWidth, int fileHeight, string thumbnailFileName, bool useFixedDimensions) - { - // Generate thumbnail - float f = 1; - if (useFixedDimensions == false) - { - var fx = (float)image.Size.Width / (float)maxWidthHeight; - var fy = (float)image.Size.Height / (float)maxWidthHeight; - - // must fit in thumbnail size - f = Math.Max(fx, fy); - } - - var widthTh = (int)Math.Round((float)fileWidth / f); - var heightTh = (int)Math.Round((float)fileHeight / f); - - // fixes for empty width or height - if (widthTh == 0) - widthTh = 1; - if (heightTh == 0) - heightTh = 1; - - // Create new image with best quality settings - using (var bp = new Bitmap(widthTh, heightTh)) - { - using (var g = Graphics.FromImage(bp)) - { - g.SmoothingMode = SmoothingMode.HighQuality; - g.InterpolationMode = InterpolationMode.HighQualityBicubic; - g.PixelOffsetMode = PixelOffsetMode.HighQuality; - g.CompositingQuality = CompositingQuality.HighQuality; - - // Copy the old image to the new and resized - var rect = new Rectangle(0, 0, widthTh, heightTh); - g.DrawImage(image, rect, 0, 0, image.Width, image.Height, GraphicsUnit.Pixel); - - // Copy metadata - var imageEncoders = ImageCodecInfo.GetImageEncoders(); - - var codec = Extension.ToLower() == "png" || Extension.ToLower() == "gif" - ? imageEncoders.Single(t => t.MimeType.Equals("image/png")) - : imageEncoders.Single(t => t.MimeType.Equals("image/jpeg")); - - // Set compresion ratio to 90% - var ep = new EncoderParameters(); - ep.Param[0] = new EncoderParameter(Encoder.Quality, 90L); - - // Save the new image using the dimensions of the image - var newFileName = thumbnailFileName.Replace("UMBRACOSYSTHUMBNAIL", string.Format("{0}x{1}", widthTh, heightTh)); - using (var ms = new MemoryStream()) - { - bp.Save(ms, codec, ep); - ms.Seek(0, 0); - - _fs.AddFile(newFileName, ms); - } - - return new ResizedImage(widthTh, heightTh, newFileName); - } - } - } } - internal class ResizedImage - { - public ResizedImage() - { - } - - public ResizedImage(int width, int height, string fileName) - { - Width = width; - Height = height; - FileName = fileName; - } - - public int Width { get; set; } - public int Height { get; set; } - public string FileName { get; set; } - } } diff --git a/src/umbraco.cms/businesslogic/datatype/FileHandlerData.cs b/src/umbraco.cms/businesslogic/datatype/FileHandlerData.cs index 4a8786a8fd..53a7d14f24 100644 --- a/src/umbraco.cms/businesslogic/datatype/FileHandlerData.cs +++ b/src/umbraco.cms/businesslogic/datatype/FileHandlerData.cs @@ -169,12 +169,12 @@ namespace umbraco.cms.businesslogic.datatype object propertyValue) { XmlNode propertyNode = uploadFieldConfigNode.SelectSingleNode(propertyAlias); - if (propertyNode != null && !String.IsNullOrEmpty(propertyNode.FirstChild.Value)) + if (propertyNode != null && !string.IsNullOrEmpty(propertyNode.FirstChild.Value)) { - if (content.getProperty(propertyNode.FirstChild.Value) != null) + var prop = content.getProperty(propertyNode.FirstChild.Value); + if (prop != null) { - content.getProperty(propertyNode.FirstChild.Value) - .Value = propertyValue; + prop.Value = propertyValue; } } }