/// <summary> /// Runs the process to optimize the image. /// </summary> /// <param name="stream"> </param> /// <param name="algorithm"> /// Default is auto depend on file extension, others is force algorithm /// </param> /// <param name="qualityPercent"> /// Quality of image after compress, 0 is default it mean auto quality by image type /// </param> /// <param name="timeout"> TimeoutMillisecond of process in millisecond </param> /// <returns> The Task containing processing information. </returns> /// <exception cref="ArgumentException"> stream is invalid image format </exception> private static ImageCompressResult Process(MemoryStream stream, CompressAlgorithm algorithm, int qualityPercent = 0, int timeout = 0) { bool isValidImage = ImageCompressorHelper.TryGetCompressImageType(stream, out var imageType); if (!isValidImage || imageType == CompressImageType.Invalid) { throw new ArgumentException($"{nameof(stream)} is invalid image format", nameof(stream)); } // Create a source temporary file with the correct extension. var filePath = FileHelper.CreateTempFile(stream, imageType.AsString(EnumFormat.Description), out _); ImageCompressResult imageCompressResult = Process(filePath, algorithm, qualityPercent, timeout); if (imageCompressResult != null) { // update file type, because in process not update it imageCompressResult.FileType = imageType; } // Cleanup temp file FileHelper.SafeDelete(filePath); return(imageCompressResult); }
/// <summary> /// Runs the process to optimize the image. /// </summary> /// <param name="inputPath"> </param> /// <param name="outputPath"> </param> /// <param name="qualityPercent"></param> /// <param name="timeout"> </param> /// <returns></returns> /// <exception cref="ArgumentException"> input path is invalid image format </exception> public static ImageCompressResult Compress(string inputPath, string outputPath, int qualityPercent = 0, int timeout = ImageCompressorConstants.TimeoutMillisecond) { using (MemoryStream stream = new MemoryStream()) { using (FileStream file = new FileStream(inputPath, FileMode.Open, FileAccess.Read)) { // Copy file to stream file.Position = 0; file.CopyTo(stream); // Do compress ImageCompressResult imageCompressResult = Compress(stream, qualityPercent, timeout); // Save to file imageCompressResult?.ResultFileStream.Save(outputPath); return(imageCompressResult); } } }
/// <summary> /// Runs the process to optimize the image. /// </summary> /// <param name="stream"> The source image stream. </param> /// <param name="qualityPercent"> /// Quality of image after compress, 0 is default it mean auto quality by image type /// </param> /// <param name="timeout"> TimeoutMillisecond of process in millisecond </param> /// <returns> The Task containing processing information. </returns> /// <exception cref="ArgumentException"> stream is invalid image format </exception> public static ImageCompressResult Compress(MemoryStream stream, int qualityPercent = 0, int timeout = ImageCompressorConstants.TimeoutMillisecond) { // Create new stopwatch. Stopwatch stopwatch = new Stopwatch(); bool isValidImage = ImageCompressorHelper.TryGetCompressImageType(stream, out var imageType); if (!isValidImage || imageType == CompressImageType.Invalid) { throw new ArgumentException($"{nameof(stream)} is invalid image format", nameof(stream)); } // Handle default value qualityPercent = ImageCompressorHelper.GetQualityPercent(qualityPercent, imageType); ImageCompressResult imageCompressResult = null; // Begin timing. stopwatch.Start(); bool isCanOptimize = false; switch (imageType) { case CompressImageType.Png: { while (qualityPercent > 0) { imageCompressResult = Process(stream, CompressAlgorithm.PngPrimary, qualityPercent, timeout); if (imageCompressResult == null || (imageCompressResult.PercentSaving > 0 && imageCompressResult.PercentSaving < 100)) { isCanOptimize = true; break; } qualityPercent -= 10; } // if quality percent < 0 then try compress by png secondary algorithm (this // algorithm not related to quality percent) if (!isCanOptimize) { imageCompressResult = Process(stream, CompressAlgorithm.PngSecondary, qualityPercent, timeout); } break; } case CompressImageType.Jpeg: { while (qualityPercent > 0) { imageCompressResult = Process(stream, CompressAlgorithm.Jpeg, qualityPercent, timeout); if (imageCompressResult == null || (imageCompressResult.PercentSaving > 0 && imageCompressResult.PercentSaving < 100)) { isCanOptimize = true; break; } qualityPercent -= 10; } break; } case CompressImageType.Gif: { while (qualityPercent > 0) { imageCompressResult = Process(stream, CompressAlgorithm.Gif, qualityPercent, timeout); if (imageCompressResult == null || (imageCompressResult.PercentSaving > 0 && imageCompressResult.PercentSaving < 100)) { isCanOptimize = true; break; } qualityPercent -= 10; } break; } } // Stop timing. stopwatch.Stop(); // if cannot at all, return null if (imageCompressResult == null) { return(null); } if (imageCompressResult.PercentSaving > 0 && imageCompressResult.PercentSaving < 100) { // update total millisecond took only imageCompressResult.TotalMillisecondsTook = stopwatch.ElapsedMilliseconds; } else { // update total millisecond took imageCompressResult.TotalMillisecondsTook = stopwatch.ElapsedMilliseconds; // Cannot optimize Use origin for destination => update file size and stream imageCompressResult.CompressedFileSize = imageCompressResult.OriginalFileSize; // Copy origin steam to result imageCompressResult.ResultFileStream.SetLength(0); stream.Position = 0; stream.CopyTo(imageCompressResult.ResultFileStream); } imageCompressResult.QualityPercent = isCanOptimize ? qualityPercent : 100; return(imageCompressResult); }
/// <summary> /// Runs the process to optimize the image. /// </summary> /// <param name="filePath"> The source file. </param> /// <param name="algorithm"> /// Default is auto depend on file extension, others is force algorithm /// </param> /// <param name="qualityPercent"> /// Quality of image after compress, 0 is default it mean auto quality by image type /// </param> /// <param name="timeout"> TimeoutMillisecond of process in millisecond </param> /// <returns> The Task containing processing information. </returns> /// <exception cref="ArgumentException"> /// file path is invalid, argument of command is invalid /// </exception> /// <exception cref="NotSupportedException"> /// Some security policies don't allow execution of programs in this way /// </exception> private static ImageCompressResult Process(string filePath, CompressAlgorithm algorithm, int qualityPercent = 0, int timeout = 0) { ImageCompressorHelper.CheckFilePath(filePath); long fileSizeBeforeCompress = new FileInfo(filePath).Length; ImageCompressResult imageCompressResult = null; var processInfo = new ProcessStartInfo("cmd") { WorkingDirectory = ImageCompressorBootstrapper.Instance.WorkingPath, Arguments = GetArguments(filePath, out var fileTempPath, algorithm, qualityPercent), UseShellExecute = false, CreateNoWindow = true, WindowStyle = ProcessWindowStyle.Hidden, RedirectStandardOutput = false, RedirectStandardError = false, }; if (IsProcessRunAsUser) { System.Security.SecureString runAsPassword = new System.Security.SecureString(); foreach (char c in ProcessRunAsPassword) { runAsPassword.AppendChar(c); } processInfo.UserName = ProcessRunAsUserName; processInfo.Password = runAsPassword; } if (string.IsNullOrWhiteSpace(processInfo.Arguments)) { throw new ArgumentException($"Command {nameof(processInfo.Arguments)} is empty", $"{nameof(processInfo.Arguments)}"); } int elapsedTime = 0; bool eventHandled = false; try { Process process = new Process { StartInfo = processInfo, EnableRaisingEvents = true }; process.Exited += (sender, args) => { // Done compress imageCompressResult = new ImageCompressResult(filePath, fileSizeBeforeCompress); process.Dispose(); eventHandled = true; // Remove temp file if have FileHelper.SafeDelete(fileTempPath); }; process.Start(); } catch (System.ComponentModel.Win32Exception ex) { throw new NotSupportedException("Some security policies don't allow execution of programs in this way", ex); } // Wait for Exited event, but not more than config timeout time. const int sleepAmount = 100; while (!eventHandled) { elapsedTime += sleepAmount; if (elapsedTime > timeout && timeout > 0) { break; } Thread.Sleep(sleepAmount); } // update compress result stream if (imageCompressResult != null) { FileHelper.WriteToStream(filePath, imageCompressResult.ResultFileStream); } return(imageCompressResult); }