Reputation: 545
There is a requirement to optimize images uploaded to a azure blob storage. I'm writing an azure function app (blob trigger) which will take the uploaded image and compress it using a image compressor library and then save the resulting image into another blob.
I've created a custom library to compress images by referencing the ImageOptimizerWebJob library. The compression logic runs appropriate image compressor exe file (pingo.exe, cjpeg.exe, jpegtran.exe or gifsicle.exe) to compress the given image.
public CompressionResult CompressFile(string fileName, bool lossy)
{
string targetFile = Path.ChangeExtension(Path.GetTempFileName(), Path.GetExtension(fileName));
ProcessStartInfo start = new ProcessStartInfo("cmd")
{
WindowStyle = ProcessWindowStyle.Hidden,
WorkingDirectory = _cwd,
Arguments = GetArguments(fileName, targetFile, lossy),
UseShellExecute = false,
CreateNoWindow = true,
};
var stopwatch = Stopwatch.StartNew();
using (var process = Process.Start(start))
{
process.WaitForExit();
}
stopwatch.Stop();
return new CompressionResult(fileName, targetFile, stopwatch.Elapsed);
}
private static string GetArguments(string sourceFile, string targetFile, bool lossy)
{
if (!Uri.IsWellFormedUriString(sourceFile, UriKind.RelativeOrAbsolute) && !File.Exists(sourceFile))
return null;
string ext;
try
{
ext = Path.GetExtension(sourceFile).ToLowerInvariant();
}
catch (ArgumentException ex)
{
Console.WriteLine(ex);
return null;
}
switch (ext)
{
case ".png":
File.Copy(sourceFile, targetFile);
if (lossy)
return string.Format(CultureInfo.CurrentCulture, "/c pingo -s8 -q -palette=79 \"{0}\"", targetFile);
else
return string.Format(CultureInfo.CurrentCulture, "/c pingo -s8 -q \"{0}\"", targetFile);
case ".jpg":
case ".jpeg":
if (lossy)
{
return string.Format(CultureInfo.CurrentCulture, "/c cjpeg -quality 80,60 -dct float -smooth 5 -outfile \"{1}\" \"{0}\"", sourceFile, targetFile);
}
return string.Format(CultureInfo.CurrentCulture, "/c jpegtran -copy none -optimize -progressive -outfile \"{1}\" \"{0}\"", sourceFile, targetFile);
case ".gif":
return string.Format(CultureInfo.CurrentCulture, "/c gifsicle -O3 --batch --colors=256 \"{0}\" --output=\"{1}\"", sourceFile, targetFile);
}
return null;
}
My azure function uses this library to do the job. But the challenge here is, the input and output file location are azure blobs not local desktop paths.
The input and output blob data are coming from the Run() method
public static void Run([BlobTrigger("test/{name}", Connection = "")]Stream myBlob,
[Blob("test-output/{name}", FileAccess.ReadWrite)]CloudBlockBlob output,
string name,
TraceWriter log)
But I cannot directly use the input and output blob paths for the image compressor. I could not figure out a way to get the output image as a memory stream (to upload to output blob)
Appreciate your suggestions to resolve this.
Upvotes: 0
Views: 1763
Reputation: 81543
You will either need to use a file system of some description or if the exe provides StdIn/Out you can do this all in a MemoryStream
and save it (play with it) how you like
Here is an example for jpegoptim.exe
which does support StdIn/Out
var startInfo = new ProcessStartInfo
{
WindowStyle = ProcessWindowStyle.Hidden,
FileName = @"jpegoptim.exe",
Arguments = @"-s --stdin --stdout",
RedirectStandardOutput = true,
RedirectStandardError = true,
RedirectStandardInput = true,
UseShellExecute = false,
CreateNoWindow = true
};
using (var process = Process.Start(startInfo))
{
inputStream.CopyTo(process.StandardInput.BaseStream);
process.StandardInput.Close();
using (var file = new FileStream(dest, FileMode.Create, FileAccess.Write))
{
process.StandardOutput.BaseStream.CopyTo(file);
}
if (process.ExitCode != 0)
{
var message = process.StandardError.ReadToEnd();
throw new InvalidOperationException($"Failed to optimise image : {message}");
}
}
Upvotes: 0