Exemple #1
0
        /// <summary>
        /// Function to resize the image to a new width, height and/or depth.
        /// </summary>
        /// <param name="baseImage">The image to resize.</param>
        /// <param name="newWidth">The new width for the image.</param>
        /// <param name="newHeight">The new height for the image (for <see cref="ImageType.Image2D"/> and <see cref="ImageType.ImageCube"/> images).</param>
        /// <param name="newDepth">The new depth for the image (for <see cref="ImageType.Image3D"/> images).</param>
        /// <param name="filter">[Optional] The type of filtering to apply to the scaled image to help smooth larger and smaller images.</param>
        /// <returns>A <see cref="IGorgonImage"/> containing the resized image.</returns>
        /// <exception cref="ArgumentNullException">Thrown when the <paramref name="baseImage"/> parameter is <b>null</b>.</exception>
        /// <exception cref="ArgumentOutOfRangeException">Thrown if the <paramref name="newWidth"/>, <paramref name="newHeight"/>, or <paramref name="newDepth"/> parameters are less than 1.</exception>
        /// <exception cref="GorgonException">Thrown if there was an error during resizing regarding image pixel format conversion due to the type of <paramref name="filter"/> applied.</exception>
        /// <remarks>
        /// <para>
        /// This method will change the size of an existing image and return a larger or smaller version of itself as a new <see cref="IGorgonImage"/>.
        /// </para>
        /// </remarks>
        public static IGorgonImage Resize(this IGorgonImage baseImage, int newWidth, int newHeight, int newDepth, ImageFilter filter = ImageFilter.Point)
        {
            if (baseImage == null)
            {
                throw new ArgumentNullException(nameof(baseImage));
            }

            if (newWidth < 1)
            {
                throw new ArgumentOutOfRangeException(Resources.GORIMG_ERR_IMAGE_WIDTH_TOO_SMALL, nameof(newWidth));
            }

            if ((newHeight < 1) && ((baseImage.ImageType == ImageType.Image2D) || (baseImage.ImageType == ImageType.ImageCube)))
            {
                throw new ArgumentOutOfRangeException(Resources.GORIMG_ERR_IMAGE_HEIGHT_TOO_SMALL, nameof(newHeight));
            }

            if ((newDepth < 1) && (baseImage.ImageType == ImageType.Image3D))
            {
                throw new ArgumentOutOfRangeException(Resources.GORIMG_ERR_IMAGE_DEPTH_TOO_SMALL, nameof(newDepth));
            }

            // Only use the appropriate dimensions.
            switch (baseImage.ImageType)
            {
            case ImageType.Image1D:
                newHeight = baseImage.Height;
                break;

            case ImageType.Image2D:
            case ImageType.ImageCube:
                newDepth = baseImage.Depth;
                break;
            }

            // If we haven't actually changed the size, then skip out.
            if ((newWidth == baseImage.Width) && (newHeight == baseImage.Height) && (newDepth == baseImage.Depth))
            {
                return(baseImage);
            }

            var wic = new WicUtilities();

            IGorgonImage newImage = null;

            try
            {
                int calcMipLevels = GorgonImage.CalculateMaxMipCount(newWidth, newHeight, newDepth).Min(baseImage.MipCount);
                newImage = wic.Resize(baseImage, 0, 0, newWidth, newHeight, newDepth, calcMipLevels, filter, ResizeMode.Scale);

                newImage.CopyTo(baseImage);

                return(baseImage);
            }
            finally
            {
                newImage?.Dispose();
                wic.Dispose();
            }
        }
Exemple #2
0
        /// <summary>
        /// Function to crop the image to the rectangle passed to the parameters.
        /// </summary>
        /// <param name="baseImage">The image to resize.</param>
        /// <param name="cropRect">The rectangle that will be used to crop the image.</param>
        /// <param name="newDepth">The new depth for the image (for <see cref="ImageType.Image3D"/> images).</param>
        /// <returns>A <see cref="IGorgonImage"/> containing the resized image.</returns>
        /// <exception cref="ArgumentNullException">Thrown when the <paramref name="baseImage"/> parameter is <b>null</b>.</exception>
        /// <exception cref="ArgumentOutOfRangeException">Thrown if the <paramref name="newDepth"/> parameter is less than 1.</exception>
        /// <remarks>
        /// <para>
        /// This method will crop the existing image a smaller version of itself as a new <see cref="IGorgonImage"/>. If the sizes are the same, or the <paramref name="cropRect"/> is larger than the size
        /// of the <paramref name="baseImage"/>, then no changes will be made.
        /// </para>
        /// </remarks>
        public static IGorgonImage Crop(this IGorgonImage baseImage, DX.Rectangle cropRect, int newDepth)
        {
            if (baseImage == null)
            {
                throw new ArgumentNullException(nameof(baseImage));
            }

            if ((newDepth < 1) && (baseImage.ImageType == ImageType.Image3D))
            {
                throw new ArgumentOutOfRangeException(Resources.GORIMG_ERR_IMAGE_DEPTH_TOO_SMALL, nameof(newDepth));
            }

            // Only use the appropriate dimensions.
            switch (baseImage.ImageType)
            {
            case ImageType.Image1D:
                cropRect.Height = baseImage.Height;
                break;

            case ImageType.Image2D:
            case ImageType.ImageCube:
                newDepth = baseImage.Depth;
                break;
            }

            // If the intersection of the crop rectangle and the source buffer are the same (and the depth is the same), then we don't need to crop.
            var bufferRect = new DX.Rectangle(0, 0, baseImage.Width, baseImage.Height);
            var clipRect   = DX.Rectangle.Intersect(cropRect, bufferRect);

            if ((bufferRect.Equals(ref clipRect)) && (newDepth == baseImage.Depth))
            {
                return(baseImage);
            }

            var wic = new WicUtilities();

            IGorgonImage newImage = null;

            try
            {
                int calcMipLevels = GorgonImage.CalculateMaxMipCount(cropRect.Width, cropRect.Height, newDepth).Min(baseImage.MipCount);
                newImage = wic.Resize(baseImage, cropRect.X, cropRect.Y, cropRect.Width, cropRect.Height, newDepth, calcMipLevels, ImageFilter.Point, ResizeMode.Crop);

                // Send the data over to the new image.
                newImage.CopyTo(baseImage);

                return(baseImage);
            }
            finally
            {
                newImage?.Dispose();
                wic.Dispose();
            }
        }
Exemple #3
0
        /// <summary>
        /// Function to expand an image width, height, and/or depth.
        /// </summary>
        /// <param name="baseImage">The image to expand.</param>
        /// <param name="newWidth">The new width of the image.</param>
        /// <param name="newHeight">The new height of the image.</param>
        /// <param name="newDepth">The new depth of the image.</param>
        /// <param name="anchor">[Optional] The anchor point for placing the image data after the image is expanded.</param>
        /// <returns>The expanded image.</returns>
        /// <remarks>
        /// <para>
        /// This will expand the size of an image, but not stretch the actual image data. This will leave a padding around the original image area filled with transparent pixels.
        /// </para>
        /// <para>
        /// The image data can be repositioned in the new image by specifying an <paramref name="anchor"/> point.
        /// </para>
        /// <para>
        /// If the new size of the image is smaller than that of the <paramref name="baseImage"/>, then the new size is constrained to the old size. Cropping is not supported by this method.
        /// </para>
        /// <para>
        /// If a user wishes to resize the image, then call the <see cref="Resize"/> method, of if they wish to crop an image, use the <see cref="Crop"/> method.
        /// </para>
        /// </remarks>
        public static IGorgonImage Expand(this IGorgonImage baseImage, int newWidth, int newHeight, int newDepth, ImageExpandAnchor anchor = ImageExpandAnchor.UpperLeft)
        {
            IGorgonImage workingImage = null;
            WicUtilities wic          = null;

            try
            {
                // Constrain to the correct sizes.
                newWidth  = newWidth.Max(baseImage.Width);
                newHeight = newHeight.Max(baseImage.Height);
                newDepth  = newDepth.Max(baseImage.Depth);

                // Only use the appropriate dimensions.
                switch (baseImage.ImageType)
                {
                case ImageType.Image1D:
                    newHeight = baseImage.Height;
                    break;

                case ImageType.Image2D:
                case ImageType.ImageCube:
                    newDepth = baseImage.Depth;
                    break;
                }

                // We don't shink with this method, use the Crop method for that.
                if ((newWidth <= baseImage.Width) && (newHeight <= baseImage.Height) && (newDepth <= baseImage.Depth))
                {
                    return(baseImage);
                }

                wic = new WicUtilities();

                workingImage = new GorgonImage(new GorgonImageInfo(baseImage)
                {
                    Width  = newWidth,
                    Height = newHeight,
                    Depth  = newDepth
                });

                DX.Point position = DX.Point.Zero;

                switch (anchor)
                {
                case ImageExpandAnchor.UpperMiddle:
                    position = new DX.Point((newWidth / 2) - (baseImage.Width / 2), 0);
                    break;

                case ImageExpandAnchor.UpperRight:
                    position = new DX.Point(newWidth - baseImage.Width, 0);
                    break;

                case ImageExpandAnchor.MiddleLeft:
                    position = new DX.Point(0, (newHeight / 2) - (baseImage.Height / 2));
                    break;

                case ImageExpandAnchor.Center:
                    position = new DX.Point((newWidth / 2) - (baseImage.Width / 2), (newHeight / 2) - (baseImage.Height / 2));
                    break;

                case ImageExpandAnchor.MiddleRight:
                    position = new DX.Point(newWidth - baseImage.Width, (newHeight / 2) - (baseImage.Height / 2));
                    break;

                case ImageExpandAnchor.BottomLeft:
                    position = new DX.Point(0, newHeight - baseImage.Height);
                    break;

                case ImageExpandAnchor.BottomMiddle:
                    position = new DX.Point((newWidth / 2) - (baseImage.Width / 2), newHeight - baseImage.Height);
                    break;

                case ImageExpandAnchor.BottomRight:
                    position = new DX.Point(newWidth - baseImage.Width, newHeight - baseImage.Height);
                    break;
                }

                int calcMipLevels = GorgonImage.CalculateMaxMipCount(newWidth, newHeight, newDepth).Min(baseImage.MipCount);
                workingImage = wic.Resize(baseImage, position.X, position.Y, newWidth, newHeight, newDepth, calcMipLevels, ImageFilter.Point, ResizeMode.Expand);

                // Send the data over to the new image.
                workingImage.CopyTo(baseImage);

                return(baseImage);
            }
            finally
            {
                workingImage?.Dispose();
                wic?.Dispose();
            }
        }