/ src / modules / previewpane / BgcodeThumbnailProvider / BgcodeThumbnailProvider.cs
BgcodeThumbnailProvider.cs
  1  // Copyright (c) Microsoft Corporation
  2  // The Microsoft Corporation licenses this file to you under the MIT license.
  3  // See the LICENSE file in the project root for more information.
  4  using System.Drawing.Drawing2D;
  5  using System.Drawing.Imaging;
  6  
  7  using Microsoft.PowerToys.FilePreviewCommon;
  8  
  9  namespace Microsoft.PowerToys.ThumbnailHandler.Bgcode
 10  {
 11      /// <summary>
 12      /// Binary G-code Thumbnail Provider.
 13      /// </summary>
 14      public class BgcodeThumbnailProvider
 15      {
 16          public BgcodeThumbnailProvider(string filePath)
 17          {
 18              FilePath = filePath;
 19              Stream = new FileStream(filePath, FileMode.Open, FileAccess.Read);
 20          }
 21  
 22          /// <summary>
 23          /// Gets the file path to the file creating thumbnail for.
 24          /// </summary>
 25          public string FilePath { get; private set; }
 26  
 27          /// <summary>
 28          /// Gets the stream object to access file.
 29          /// </summary>
 30          public Stream Stream { get; private set; }
 31  
 32          /// <summary>
 33          ///  The maximum dimension (width or height) thumbnail we will generate.
 34          /// </summary>
 35          private const uint MaxThumbnailSize = 10000;
 36  
 37          /// <summary>
 38          /// Reads the Binary G-code content searching for thumbnails and returns the largest.
 39          /// </summary>
 40          /// <param name="reader">The BinaryReader instance for the Binary G-code content.</param>
 41          /// <param name="cx">The maximum thumbnail size, in pixels.</param>
 42          /// <returns>A thumbnail extracted from the Binary G-code content.</returns>
 43          public static Bitmap GetThumbnail(BinaryReader reader, uint cx)
 44          {
 45              if (cx > MaxThumbnailSize || reader == null || reader.BaseStream.Length == 0)
 46              {
 47                  return null;
 48              }
 49  
 50              Bitmap thumbnail = null;
 51  
 52              try
 53              {
 54                  var bgcodeThumbnail = BgcodeHelper.GetBestThumbnail(reader);
 55  
 56                  thumbnail = bgcodeThumbnail?.GetBitmap();
 57              }
 58              catch (Exception)
 59              {
 60                  // TODO: add logger
 61              }
 62  
 63              if (thumbnail != null && (
 64                  ((thumbnail.Width != cx || thumbnail.Height > cx) && (thumbnail.Height != cx || thumbnail.Width > cx)) ||
 65                  thumbnail.PixelFormat != PixelFormat.Format32bppArgb))
 66              {
 67                  // We are not the appropriate size for caller.  Resize now while
 68                  // respecting the aspect ratio.
 69                  float scale = Math.Min((float)cx / thumbnail.Width, (float)cx / thumbnail.Height);
 70                  int scaleWidth = (int)(thumbnail.Width * scale);
 71                  int scaleHeight = (int)(thumbnail.Height * scale);
 72                  thumbnail = ResizeImage(thumbnail, scaleWidth, scaleHeight);
 73              }
 74  
 75              return thumbnail;
 76          }
 77  
 78          /// <summary>
 79          /// Resize the image with high quality to the specified width and height.
 80          /// </summary>
 81          /// <param name="image">The image to resize.</param>
 82          /// <param name="width">The width to resize to.</param>
 83          /// <param name="height">The height to resize to.</param>
 84          /// <returns>The resized image.</returns>
 85          public static Bitmap ResizeImage(Image image, int width, int height)
 86          {
 87              if (width <= 0 ||
 88                  height <= 0 ||
 89                  width > MaxThumbnailSize ||
 90                  height > MaxThumbnailSize ||
 91                  image == null)
 92              {
 93                  return null;
 94              }
 95  
 96              Bitmap destImage = new Bitmap(width, height, PixelFormat.Format32bppArgb);
 97  
 98              destImage.SetResolution(image.HorizontalResolution, image.VerticalResolution);
 99  
100              using (var graphics = Graphics.FromImage(destImage))
101              {
102                  graphics.CompositingMode = CompositingMode.SourceCopy;
103                  graphics.CompositingQuality = CompositingQuality.HighQuality;
104                  graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
105                  graphics.SmoothingMode = SmoothingMode.HighQuality;
106                  graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;
107  
108                  graphics.DrawImage(image, 0, 0, width, height);
109              }
110  
111              image.Dispose();
112  
113              return destImage;
114          }
115  
116          /// <summary>
117          /// Generate thumbnail bitmap for provided Bgcode file/stream.
118          /// </summary>
119          /// <param name="cx">Maximum thumbnail size, in pixels.</param>
120          /// <returns>Generated bitmap</returns>
121          public Bitmap GetThumbnail(uint cx)
122          {
123              if (cx == 0 || cx > MaxThumbnailSize)
124              {
125                  return null;
126              }
127  
128              if (global::PowerToys.GPOWrapper.GPOWrapper.GetConfiguredBgcodeThumbnailsEnabledValue() == global::PowerToys.GPOWrapper.GpoRuleConfigured.Disabled)
129              {
130                  // GPO is disabling this utility.
131                  return null;
132              }
133  
134              using (var reader = new BinaryReader(this.Stream))
135              {
136                  Bitmap thumbnail = GetThumbnail(reader, cx);
137                  if (thumbnail != null && thumbnail.Size.Width > 0 && thumbnail.Size.Height > 0)
138                  {
139                      return thumbnail;
140                  }
141              }
142  
143              return null;
144          }
145      }
146  }