简体   繁体   中英

Azure blobs: Image optimization

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.

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM