/// <summary>
        ///   Creates an image file having a max length of <paramref name="maxLength" /> and JPEG quality of
        ///   <paramref
        ///     name="jpegQuality" />
        ///   from <paramref name="sourceFilePath" />. The file is saved to the location <paramref name="newFilePath" />.
        ///   The width and height of the generated image is returned as a <see cref="Size" /> instance. The WPF classes
        ///   are used to create the image, which are faster than the GDI classes. The caller must verify application is running in Full Trust.
        /// </summary>
        /// <param name="sourceFilePath">The full path of the source image.</param>
        /// <param name="newFilePath">The full path where the image will be saved.</param>
        /// <param name="maxLength">The maximum length of one side of the image.</param>
        /// <param name="jpegQuality">The JPEG quality.</param>
        /// <returns>
        ///   Returns a <see cref="Size" /> instance containing the width and height of the generated image.
        /// </returns>
        /// <exception cref="UnsupportedImageTypeException">
        ///   Thrown when Gallery Server cannot process the image, most likely because it is corrupt or an unsupported image type.
        /// </exception>
        private Size GenerateImageUsingWpf(string sourceFilePath, string newFilePath, int maxLength, int jpegQuality)
        {
            try
            {
                // Technique adapted from http://weblogs.asp.net/bleroy/archive/2009/12/10/resizing-images-from-the-server-using-wpf-wic-instead-of-gdi.aspx
                var photoBytes = File.ReadAllBytes(sourceFilePath);
                using (var photoStream = new MemoryStream(photoBytes))
                {
                    var photo = ReadBitmapFrame(photoStream);

                    var newSize = CalculateWidthAndHeight(new Size(photo.PixelWidth, photo.PixelHeight), maxLength, false);

                    var bmpFrame     = FastResize(photo, newSize.Width, newSize.Height);
                    var resizedBytes = GenerateJpegByteArray(bmpFrame, jpegQuality);

                    ImageHelper.SaveImageToDisk(resizedBytes, newFilePath);

                    var rotatedSize = ExecuteAutoRotation(newFilePath, jpegQuality);

                    return(rotatedSize.IsEmpty ? newSize : rotatedSize);
                }
            }
            catch (FileFormatException ex)
            {
                throw new UnsupportedImageTypeException(GalleryObject, ex);
            }
            catch (NotSupportedException ex)
            {
                throw new UnsupportedImageTypeException(GalleryObject, ex);
            }
        }
        /// <summary>
        /// Add the <paramref name="metaValues" /> and any meta properties from the in-memory object back to the <paramref name="filePath" />.
        /// </summary>
        /// <param name="filePath">The full path to the file.</param>
        /// <param name="metaValues">The property items. If null, no action is taken.</param>
        private void AddMetaValuesBackToRotatedImage(string filePath, System.Drawing.Imaging.PropertyItem[] metaValues)
        {
            if (metaValues == null)
            {
                return;
            }

            // Step 1: Create a copy of the file and add the PropertyItem metadata to it.
            string tmpImagePath;

            using (var targetImage = new System.Drawing.Bitmap(filePath))
            {
                foreach (var propertyItem in metaValues)
                {
                    // Don't copy width, height or orientation meta items.
                    var metasToNotCopy = new[]
                    {
                        RawMetadataItemName.ImageWidth,
                        RawMetadataItemName.ImageHeight,
                        RawMetadataItemName.ExifPixXDim,
                        RawMetadataItemName.ExifPixYDim,
                        RawMetadataItemName.Orientation
                    };

                    if (Array.IndexOf(metasToNotCopy, (RawMetadataItemName)propertyItem.Id) >= 0)
                    {
                        continue;
                    }

                    targetImage.SetPropertyItem(propertyItem);
                }

                // Save image to temporary location. We can't overwrite the original path because the Bitmap has a lock on it.
                tmpImagePath = Path.Combine(AppSetting.Instance.TempUploadDirectory, String.Concat(Guid.NewGuid().ToString(), ".jpg"));
                ImageHelper.SaveImageToDisk(targetImage, tmpImagePath, System.Drawing.Imaging.ImageFormat.Jpeg, GallerySettings.OriginalImageJpegQuality);
            }

            // Step 2: Now that the original file is freed up, delete it and move the temp file into its place.
            HelperFunctions.MoveFileSafely(tmpImagePath, filePath);

            // Step 3: Write all possible in-memory meta properties to the file. This will write as many user-edited items as possible.
            foreach (var metaItem in GalleryObject.MetadataItems)
            {
                metaItem.PersistToFile = GalleryObject.MetaDefinitions.Find(metaItem.MetadataItemName).IsPersistable;
                metaItem.HasChanges    = true;
            }
        }
        private Tuple <MediaAssetRotateFlip, Size> RotateFlipUsingGdi(string filePath, int jpegQuality)
        {
            var actualRotation = GalleryObject.CalculateNeededRotation();

            if (actualRotation <= MediaAssetRotateFlip.Rotate0FlipNone)
            {
                return(new Tuple <MediaAssetRotateFlip, Size>(actualRotation, Size.Empty));
            }

            string tmpImagePath;
            Tuple <MediaAssetRotateFlip, Size> rotateInfo;

            // Get reference to the bitmap from which the optimized image will be generated.
            using (var originalBitmap = new System.Drawing.Bitmap(filePath))
            {
                var imgFormat = originalBitmap.RawFormat; // Need to grab the format before we rotate or else we lose it (it changes to MemoryBmp)

                try
                {
                    originalBitmap.RotateFlip(GetRotateFlipType(actualRotation));
                }
                catch (System.Runtime.InteropServices.ExternalException)
                {
                    throw new UnsupportedImageTypeException();
                }

                // If present, remove the orientation meta property.
                if (Array.IndexOf(originalBitmap.PropertyIdList, ((int)RawMetadataItemName.Orientation)) >= 0)
                {
                    originalBitmap.RemovePropertyItem((int)RawMetadataItemName.Orientation);
                }

                // Save image to temporary location. We can't overwrite the original path because the Bitmap has a lock on it.
                tmpImagePath = Path.Combine(AppSetting.Instance.TempUploadDirectory, String.Concat(Guid.NewGuid().ToString(), ".jpg"));
                ImageHelper.SaveImageToDisk(originalBitmap, tmpImagePath, imgFormat, jpegQuality);

                rotateInfo = new Tuple <MediaAssetRotateFlip, Size>(actualRotation, new Size(originalBitmap.Width, originalBitmap.Height));
            }


            // Now that the original file is freed up, delete it and move the temp file into its place.
            HelperFunctions.MoveFileSafely(tmpImagePath, filePath);

            return(rotateInfo);
        }