/// <summary>
        /// Gets a resized image for the image at the given path
        /// </summary>
        /// <param name="imagePath"></param>
        /// <param name="width"></param>
        /// <returns></returns>
        /// <remarks>
        /// If there is no media, image property or image file is found then this will return not found.
        /// </remarks>
        public IActionResult GetResized(string imagePath, int width)
        {
            var ext = Path.GetExtension(imagePath);

            // we need to check if it is an image by extension
            if (_imageUrlGenerator.IsSupportedImageFormat(ext) == false)
            {
                return(NotFound());
            }

            //redirect to ImageProcessor thumbnail with rnd generated from last modified time of original media file
            DateTimeOffset?imageLastModified = null;

            try
            {
                imageLastModified = _mediaFileManager.FileSystem.GetLastModified(imagePath);
            }
            catch (Exception)
            {
                // if we get an exception here it's probably because the image path being requested is an image that doesn't exist
                // in the local media file system. This can happen if someone is storing an absolute path to an image online, which
                // is perfectly legal but in that case the media file system isn't going to resolve it.
                // so ignore and we won't set a last modified date.
            }

            var rnd      = imageLastModified.HasValue ? $"&rnd={imageLastModified:yyyyMMddHHmmss}" : null;
            var imageUrl = _imageUrlGenerator.GetImageUrl(new ImageUrlGenerationOptions(imagePath)
            {
                Width            = width,
                ImageCropMode    = ImageCropMode.Max,
                CacheBusterValue = rnd
            });

            return(new RedirectResult(imageUrl, false));
        }
Example #2
0
        /// <summary>
        /// Gets a resized image for the image at the given path
        /// </summary>
        /// <param name="imagePath"></param>
        /// <param name="width"></param>
        /// <returns></returns>
        /// <remarks>
        /// If there is no media, image property or image file is found then this will return not found.
        /// </remarks>
        public IActionResult GetResized(string imagePath, int width)
        {
            // We have to use HttpUtility to encode the path here, for non-ASCII characters
            // We cannot use the WebUtility, as we only want to encode the path, and not the entire string
            var encodedImagePath = HttpUtility.UrlPathEncode(imagePath);


            var ext = Path.GetExtension(encodedImagePath);

            // check if imagePath is local to prevent open redirect
            if (!Uri.IsWellFormedUriString(encodedImagePath, UriKind.Relative))
            {
                return(Unauthorized());
            }

            // we need to check if it is an image by extension
            if (_imageUrlGenerator.IsSupportedImageFormat(ext) == false)
            {
                return(NotFound());
            }

            // redirect to ImageProcessor thumbnail with rnd generated from last modified time of original media file
            DateTimeOffset?imageLastModified = null;

            try
            {
                imageLastModified = _mediaFileManager.FileSystem.GetLastModified(imagePath);
            }
            catch (Exception)
            {
                // if we get an exception here it's probably because the image path being requested is an image that doesn't exist
                // in the local media file system. This can happen if someone is storing an absolute path to an image online, which
                // is perfectly legal but in that case the media file system isn't going to resolve it.
                // so ignore and we won't set a last modified date.
            }

            var rnd      = imageLastModified.HasValue ? $"&rnd={imageLastModified:yyyyMMddHHmmss}" : null;
            var imageUrl = _imageUrlGenerator.GetImageUrl(new ImageUrlGenerationOptions(encodedImagePath)
            {
                Width            = width,
                ImageCropMode    = ImageCropMode.Max,
                CacheBusterValue = rnd
            });

            if (Url.IsLocalUrl(imageUrl))
            {
                return(new LocalRedirectResult(imageUrl, false));
            }
            else
            {
                return(Unauthorized());
            }
        }
        /// <summary>
        /// Gets the value image url for a specific width and height.
        /// </summary>
        public string GetCropUrl(int width, int height, IImageUrlGenerator imageUrlGenerator, bool useFocalPoint = false, string cacheBusterValue = null)
        {
            var options = GetCropBaseOptions(string.Empty, null, true, useFocalPoint);

            options.Width            = width;
            options.Height           = height;
            options.CacheBusterValue = cacheBusterValue;

            return(imageUrlGenerator.GetImageUrl(options));
        }
        /// <summary>
        /// Gets the value image URL for a specific width and height.
        /// </summary>
        public string GetCropUrl(int width, int height, IImageUrlGenerator imageUrlGenerator, string cacheBusterValue = null)
        {
            var options = GetCropBaseOptions(null, null, false);

            options.Width            = width;
            options.Height           = height;
            options.CacheBusterValue = cacheBusterValue;

            return(imageUrlGenerator.GetImageUrl(options));
        }
        /// <summary>
        /// Gets the value image url for a specified crop.
        /// </summary>
        public string GetCropUrl(string alias, IImageUrlGenerator imageUrlGenerator, bool useCropDimensions = true, bool useFocalPoint = false, string cacheBusterValue = null)
        {
            var crop = GetCrop(alias);

            // could not find a crop with the specified, non-empty, alias
            if (crop == null && !string.IsNullOrWhiteSpace(alias))
            {
                return(null);
            }

            var options = GetCropBaseOptions(string.Empty, crop, string.IsNullOrWhiteSpace(alias), useFocalPoint);

            if (crop != null && useCropDimensions)
            {
                options.Width  = crop.Width;
                options.Height = crop.Height;
            }

            options.CacheBusterValue = cacheBusterValue;

            return(imageUrlGenerator.GetImageUrl(options));
        }
Example #6
0
        /// <summary>
        /// Gets a resized image for the image at the given path
        /// </summary>
        /// <param name="imagePath"></param>
        /// <param name="width"></param>
        /// <returns></returns>
        /// <remarks>
        /// If there is no media, image property or image file is found then this will return not found.
        /// </remarks>
        public HttpResponseMessage GetResized(string imagePath, int width)
        {
            var ext = Path.GetExtension(imagePath);

            // we need to check if it is an image by extension
            if (_contentSection.IsImageFile(ext) == false)
            {
                return(Request.CreateResponse(HttpStatusCode.NotFound));
            }

            //redirect to ImageProcessor thumbnail with rnd generated from last modified time of original media file
            var response = Request.CreateResponse(HttpStatusCode.Found);

            DateTimeOffset?imageLastModified = null;

            try
            {
                imageLastModified = _mediaFileSystem.GetLastModified(imagePath);
            }
            catch (Exception)
            {
                // if we get an exception here it's probably because the image path being requested is an image that doesn't exist
                // in the local media file system. This can happen if someone is storing an absolute path to an image online, which
                // is perfectly legal but in that case the media file system isn't going to resolve it.
                // so ignore and we won't set a last modified date.
            }

            var rnd      = imageLastModified.HasValue ? $"&rnd={imageLastModified:yyyyMMddHHmmss}" : null;
            var imageUrl = _imageUrlGenerator.GetImageUrl(new ImageUrlGenerationOptions(imagePath)
            {
                UpScale = false, Width = width, AnimationProcessMode = "first", ImageCropMode = "max", CacheBusterValue = rnd
            });

            response.Headers.Location = new Uri(imageUrl, UriKind.RelativeOrAbsolute);
            return(response);
        }
Example #7
0
        /// <summary>
        /// Gets the ImageProcessor Url from the image path.
        /// </summary>
        /// <param name="imageUrl">
        /// The image url.
        /// </param>
        /// <param name="imageUrlGenerator">
        /// The generator that will process all the options and the image URL to return a full image urls with all processing options appended
        /// </param>
        /// <param name="cropDataSet"></param>
        /// <param name="width">
        /// The width of the output image.
        /// </param>
        /// <param name="height">
        /// The height of the output image.
        /// </param>
        /// <param name="cropAlias">
        /// The crop alias.
        /// </param>
        /// <param name="quality">
        /// Quality percentage of the output image.
        /// </param>
        /// <param name="imageCropMode">
        /// The image crop mode.
        /// </param>
        /// <param name="imageCropAnchor">
        /// The image crop anchor.
        /// </param>
        /// <param name="preferFocalPoint">
        /// Use focal point to generate an output image using the focal point instead of the predefined crop if there is one
        /// </param>
        /// <param name="useCropDimensions">
        /// Use crop dimensions to have the output image sized according to the predefined crop sizes, this will override the width and height parameters
        /// </param>
        /// <param name="cacheBusterValue">
        /// Add a serialized date of the last edit of the item to ensure client cache refresh when updated
        /// </param>
        /// <param name="furtherOptions">
        /// These are any query string parameters (formatted as query strings) that ImageProcessor supports. For example:
        /// <example>
        /// <![CDATA[
        /// furtherOptions: "&bgcolor=fff"
        /// ]]>
        /// </example>
        /// </param>
        /// <param name="ratioMode">
        /// Use a dimension as a ratio
        /// </param>
        /// <param name="upScale">
        /// If the image should be upscaled to requested dimensions
        /// </param>
        /// <returns>
        /// The <see cref="string"/>.
        /// </returns>
        public static string GetCropUrl(
            this string imageUrl,
            IImageUrlGenerator imageUrlGenerator,
            ImageCropperValue cropDataSet,
            int?width                       = null,
            int?height                      = null,
            string cropAlias                = null,
            int?quality                     = null,
            ImageCropMode?imageCropMode     = null,
            ImageCropAnchor?imageCropAnchor = null,
            bool preferFocalPoint           = false,
            bool useCropDimensions          = false,
            string cacheBusterValue         = null,
            string furtherOptions           = null,
            ImageCropRatioMode?ratioMode    = null,
            bool upScale                    = true,
            string animationProcessMode     = null)
        {
            if (string.IsNullOrEmpty(imageUrl))
            {
                return(string.Empty);
            }

            ImageUrlGenerationOptions options;

            if (cropDataSet != null && (imageCropMode == ImageCropMode.Crop || imageCropMode == null))
            {
                var crop = cropDataSet.GetCrop(cropAlias);

                // if a crop was specified, but not found, return null
                if (crop == null && !string.IsNullOrWhiteSpace(cropAlias))
                {
                    return(null);
                }

                options = cropDataSet.GetCropBaseOptions(imageUrl, crop, string.IsNullOrWhiteSpace(cropAlias), preferFocalPoint);

                if (crop != null & useCropDimensions)
                {
                    width  = crop.Width;
                    height = crop.Height;
                }

                // If a predefined crop has been specified & there are no coordinates & no ratio mode, but a width parameter has been passed we can get the crop ratio for the height
                if (crop != null && string.IsNullOrEmpty(cropAlias) == false && crop.Coordinates == null && ratioMode == null && width != null && height == null)
                {
                    options.HeightRatio = (decimal)crop.Height / crop.Width;
                }

                // If a predefined crop has been specified & there are no coordinates & no ratio mode, but a height parameter has been passed we can get the crop ratio for the width
                if (crop != null && string.IsNullOrEmpty(cropAlias) == false && crop.Coordinates == null && ratioMode == null && width == null && height != null)
                {
                    options.WidthRatio = (decimal)crop.Width / crop.Height;
                }
            }
            else
            {
                options = new ImageUrlGenerationOptions(imageUrl)
                {
                    ImageCropMode   = (imageCropMode ?? ImageCropMode.Pad).ToString().ToLowerInvariant(),
                    ImageCropAnchor = imageCropAnchor?.ToString().ToLowerInvariant()
                };
            }

            options.Quality = quality;
            options.Width   = ratioMode != null && ratioMode.Value == ImageCropRatioMode.Width ? null : width;
            options.Height  = ratioMode != null && ratioMode.Value == ImageCropRatioMode.Height ? null : height;
            options.AnimationProcessMode = animationProcessMode;

            if (ratioMode == ImageCropRatioMode.Width && height != null)
            {
                // if only height specified then assume a square
                if (width == null)
                {
                    width = height;
                }
                options.WidthRatio = (decimal)width / (decimal)height;
            }

            if (ratioMode == ImageCropRatioMode.Height && width != null)
            {
                // if only width specified then assume a square
                if (height == null)
                {
                    height = width;
                }
                options.HeightRatio = (decimal)height / (decimal)width;
            }

            options.UpScale          = upScale;
            options.FurtherOptions   = furtherOptions;
            options.CacheBusterValue = cacheBusterValue;

            return(imageUrlGenerator.GetImageUrl(options));
        }
Example #8
0
        /// <summary>
        /// Used by the RTE (and grid RTE) for drag/drop/persisting images
        /// </summary>
        /// <param name="html"></param>
        /// <param name="mediaParentFolder"></param>
        /// <param name="userId"></param>
        /// <returns></returns>
        internal string FindAndPersistPastedTempImages(string html, Guid mediaParentFolder, int userId, IImageUrlGenerator imageUrlGenerator)
        {
            // Find all img's that has data-tmpimg attribute
            // Use HTML Agility Pack - https://html-agility-pack.net
            var htmlDoc = new HtmlDocument();

            htmlDoc.LoadHtml(html);

            var tmpImages = htmlDoc.DocumentNode.SelectNodes($"//img[@{TemporaryImageDataAttribute}]");

            if (tmpImages == null || tmpImages.Count == 0)
            {
                return(html);
            }

            // An array to contain a list of URLs that
            // we have already processed to avoid dupes
            var uploadedImages = new Dictionary <string, GuidUdi>();

            foreach (var img in tmpImages)
            {
                // The data attribute contains the path to the tmp img to persist as a media item
                var tmpImgPath = img.GetAttributeValue(TemporaryImageDataAttribute, string.Empty);

                if (string.IsNullOrEmpty(tmpImgPath))
                {
                    continue;
                }

                var absoluteTempImagePath = IOHelper.MapPath(tmpImgPath);
                var fileName     = Path.GetFileName(absoluteTempImagePath);
                var safeFileName = fileName.ToSafeFileName();

                var     mediaItemName = safeFileName.ToFriendlyName();
                IMedia  mediaFile;
                GuidUdi udi;

                if (uploadedImages.ContainsKey(tmpImgPath) == false)
                {
                    if (mediaParentFolder == Guid.Empty)
                    {
                        mediaFile = _mediaService.CreateMedia(mediaItemName, Constants.System.Root, Constants.Conventions.MediaTypes.Image, userId);
                    }
                    else
                    {
                        mediaFile = _mediaService.CreateMedia(mediaItemName, mediaParentFolder, Constants.Conventions.MediaTypes.Image, userId);
                    }

                    var fileInfo = new FileInfo(absoluteTempImagePath);

                    var fileStream = fileInfo.OpenReadWithRetry();
                    if (fileStream == null)
                    {
                        throw new InvalidOperationException("Could not acquire file stream");
                    }
                    using (fileStream)
                    {
                        mediaFile.SetValue(_contentTypeBaseServiceProvider, Constants.Conventions.Media.File, safeFileName, fileStream);
                    }

                    _mediaService.Save(mediaFile, userId);

                    udi = mediaFile.GetUdi();
                }
                else
                {
                    // Already been uploaded & we have it's UDI
                    udi = uploadedImages[tmpImgPath];
                }

                // Add the UDI to the img element as new data attribute
                img.SetAttributeValue("data-udi", udi.ToString());

                // Get the new persisted image URL
                var mediaTyped = _umbracoContextAccessor?.UmbracoContext?.Media.GetById(udi.Guid);
                if (mediaTyped == null)
                {
                    throw new PanicException($"Could not find media by id {udi.Guid} or there was no UmbracoContext available.");
                }

                var location = mediaTyped.Url();

                // Find the width & height attributes as we need to set the imageprocessor QueryString
                var width  = img.GetAttributeValue("width", int.MinValue);
                var height = img.GetAttributeValue("height", int.MinValue);

                if (width != int.MinValue && height != int.MinValue)
                {
                    location = imageUrlGenerator.GetImageUrl(new ImageUrlGenerationOptions(location)
                    {
                        ImageCropMode = "max", Width = width, Height = height
                    });
                }

                img.SetAttributeValue("src", location);

                // Remove the data attribute (so we do not re-process this)
                img.Attributes.Remove(TemporaryImageDataAttribute);

                // Add to the dictionary to avoid dupes
                if (uploadedImages.ContainsKey(tmpImgPath) == false)
                {
                    uploadedImages.Add(tmpImgPath, udi);

                    // Delete folder & image now its saved in media
                    // The folder should contain one image - as a unique guid folder created
                    // for each image uploaded from TinyMceController
                    var folderName = Path.GetDirectoryName(absoluteTempImagePath);
                    try
                    {
                        Directory.Delete(folderName, true);
                    }
                    catch (Exception ex)
                    {
                        _logger.Error <string>(typeof(HtmlImageSourceParser), ex, "Could not delete temp file or folder {FileName}", absoluteTempImagePath);
                    }
                }
            }

            return(htmlDoc.DocumentNode.OuterHtml);
        }
Example #9
0
    /// <summary>
    ///     Gets the underlying image processing service URL from the image path.
    /// </summary>
    /// <param name="imageUrl">The image URL.</param>
    /// <param name="imageUrlGenerator">
    ///     The generator that will process all the options and the image URL to return a full
    ///     image URLs with all processing options appended.
    /// </param>
    /// <param name="cropDataSet">The crop data set.</param>
    /// <param name="width">The width of the output image.</param>
    /// <param name="height">The height of the output image.</param>
    /// <param name="cropAlias">The crop alias.</param>
    /// <param name="quality">Quality percentage of the output image.</param>
    /// <param name="imageCropMode">The image crop mode.</param>
    /// <param name="imageCropAnchor">The image crop anchor.</param>
    /// <param name="preferFocalPoint">
    ///     Use focal point to generate an output image using the focal point instead of the
    ///     predefined crop if there is one.
    /// </param>
    /// <param name="useCropDimensions">
    ///     Use crop dimensions to have the output image sized according to the predefined crop
    ///     sizes, this will override the width and height parameters.
    /// </param>
    /// <param name="cacheBusterValue">
    ///     Add a serialized date of the last edit of the item to ensure client cache refresh when
    ///     updated.
    /// </param>
    /// <param name="furtherOptions">
    ///     These are any query string parameters (formatted as query strings) that the underlying image processing service
    ///     supports. For example:
    ///     <example><![CDATA[
    /// furtherOptions: "bgcolor=fff"
    /// ]]></example>
    /// </param>
    /// <returns>
    ///     The URL of the cropped image.
    /// </returns>
    public static string?GetCropUrl(
        this string imageUrl,
        IImageUrlGenerator imageUrlGenerator,
        ImageCropperValue?cropDataSet,
        int?width                       = null,
        int?height                      = null,
        string?cropAlias                = null,
        int?quality                     = null,
        ImageCropMode?imageCropMode     = null,
        ImageCropAnchor?imageCropAnchor = null,
        bool preferFocalPoint           = false,
        bool useCropDimensions          = false,
        string?cacheBusterValue         = null,
        string?furtherOptions           = null)
    {
        if (string.IsNullOrWhiteSpace(imageUrl))
        {
            return(null);
        }

        ImageUrlGenerationOptions options;

        if (cropDataSet != null && (imageCropMode == ImageCropMode.Crop || imageCropMode == null))
        {
            ImageCropperValue.ImageCropperCrop?crop = cropDataSet.GetCrop(cropAlias);

            // If a crop was specified, but not found, return null
            if (crop == null && !string.IsNullOrWhiteSpace(cropAlias))
            {
                return(null);
            }

            options = cropDataSet.GetCropBaseOptions(imageUrl, crop, preferFocalPoint || string.IsNullOrWhiteSpace(cropAlias));

            if (crop != null && useCropDimensions)
            {
                width  = crop.Width;
                height = crop.Height;
            }

            // Calculate missing dimension if a predefined crop has been specified, but has no coordinates
            if (crop != null && string.IsNullOrEmpty(cropAlias) == false && crop.Coordinates == null)
            {
                if (width != null && height == null)
                {
                    height = (int)MathF.Round(width.Value * ((float)crop.Height / crop.Width));
                }
                else if (width == null && height != null)
                {
                    width = (int)MathF.Round(height.Value * ((float)crop.Width / crop.Height));
                }
            }
        }
        else
        {
            options = new ImageUrlGenerationOptions(imageUrl)
            {
                ImageCropMode   = imageCropMode ?? ImageCropMode.Pad, // Not sure why we default to Pad
                ImageCropAnchor = imageCropAnchor,
            };
        }

        options.Quality          = quality;
        options.Width            = width;
        options.Height           = height;
        options.FurtherOptions   = furtherOptions;
        options.CacheBusterValue = cacheBusterValue;

        return(imageUrlGenerator.GetImageUrl(options));
    }
Example #10
0
    /// <summary>
    ///     Tries to lookup the user's Gravatar to see if the endpoint can be reached, if so it returns the valid URL
    /// </summary>
    /// <param name="user"></param>
    /// <param name="cache"></param>
    /// <param name="mediaFileManager"></param>
    /// <param name="imageUrlGenerator"></param>
    /// <returns>
    ///     A list of 5 different sized avatar URLs
    /// </returns>
    public static string[] GetUserAvatarUrls(this IUser user, IAppCache cache, MediaFileManager mediaFileManager, IImageUrlGenerator imageUrlGenerator)
    {
        // If FIPS is required, never check the Gravatar service as it only supports MD5 hashing.
        // Unfortunately, if the FIPS setting is enabled on Windows, using MD5 will throw an exception
        // and the website will not run.
        // Also, check if the user has explicitly removed all avatars including a Gravatar, this will be possible and the value will be "none"
        if (user.Avatar == "none" || CryptoConfig.AllowOnlyFipsAlgorithms)
        {
            return(new string[0]);
        }

        if (user.Avatar.IsNullOrWhiteSpace())
        {
            var gravatarHash = user.Email?.GenerateHash <MD5>();
            var gravatarUrl  = "https://www.gravatar.com/avatar/" + gravatarHash + "?d=404";

            // try Gravatar
            var gravatarAccess = cache.GetCacheItem("UserAvatar" + user.Id, () =>
            {
                // Test if we can reach this URL, will fail when there's network or firewall errors
                var request = (HttpWebRequest)WebRequest.Create(gravatarUrl);

                // Require response within 10 seconds
                request.Timeout = 10000;
                try
                {
                    using ((HttpWebResponse)request.GetResponse())
                    {
                    }
                }
                catch (Exception)
                {
                    // There was an HTTP or other error, return an null instead
                    return(false);
                }

                return(true);
            });

            if (gravatarAccess)
            {
                return(new[]
                {
                    gravatarUrl + "&s=30", gravatarUrl + "&s=60", gravatarUrl + "&s=90", gravatarUrl + "&s=150",
                    gravatarUrl + "&s=300",
                });
            }

            return(new string[0]);
        }

        // use the custom avatar
        var avatarUrl = mediaFileManager.FileSystem.GetUrl(user.Avatar);

        return(new[]
        {
            imageUrlGenerator.GetImageUrl(new ImageUrlGenerationOptions(avatarUrl)
            {
                ImageCropMode = ImageCropMode.Crop, Width = 30, Height = 30,
            }),
            imageUrlGenerator.GetImageUrl(new ImageUrlGenerationOptions(avatarUrl)
            {
                ImageCropMode = ImageCropMode.Crop, Width = 60, Height = 60,
            }),
            imageUrlGenerator.GetImageUrl(new ImageUrlGenerationOptions(avatarUrl)
            {
                ImageCropMode = ImageCropMode.Crop, Width = 90, Height = 90,
            }),
            imageUrlGenerator.GetImageUrl(new ImageUrlGenerationOptions(avatarUrl)
            {
                ImageCropMode = ImageCropMode.Crop, Width = 150, Height = 150,
            }),
            imageUrlGenerator.GetImageUrl(new ImageUrlGenerationOptions(avatarUrl)
            {
                ImageCropMode = ImageCropMode.Crop, Width = 300, Height = 300,
            }),
        }.WhereNotNull().ToArray());
    }