/// <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); }