/// <summary> /// Save the image (of any format) to a jpeg file with 100 quality /// Note that this is still going to introduce some errors if the input is a bitmap. /// </summary> /// <remarks>Will throw if the destination is locked and the user tells us to give up. </remarks> public static void SaveAsTopQualityJpeg(Image image, string destinationPath) { var jpgEncoder = ImageCodecInfo.GetImageDecoders().First(codec => codec.FormatID == ImageFormat.Jpeg.Guid); var encoder = Encoder.Quality; //nb: there are cases (notably http://jira.palaso.org/issues/browse/WS-34711, after cropping a jpeg) where we get out of memory if we are not operating on a copy // Use a temporary file pathname in the destination folder. This is needed to ensure proper permissions are granted // to the resulting file later after FileUtils.ReplaceFileWithUserInteractionIfNeeded is called. That method may call // RobustFile.Replace which replaces both the file content and the file metadata (permissions). The result of that if we use // the user's temp directory is described in http://issues.bloomlibrary.org/youtrack/issue/BL-3954. using (var temp = TempFile.InFolderOf(destinationPath)) using (var safetyImage = new Bitmap(image)) { using (var parameters = new EncoderParameters(1)) { //0 = max compression, 100 = least parameters.Param[0] = new EncoderParameter(encoder, 100L); RobustImageIO.SaveImage(safetyImage, temp.Path, jpgEncoder, parameters); } SIL.IO.FileUtils.ReplaceFileWithUserInteractionIfNeeded(temp.Path, destinationPath, null); } }