// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.IO;
using System.Runtime.InteropServices.ComTypes;
using System.Windows;
using System.Windows.Media;
using System.Windows.Media.Media3D;
using Common.Utilities;
using HelixToolkit.Wpf;
using Microsoft.PowerToys.Settings.UI.Library;
using Bitmap = System.Drawing.Bitmap;
using Color = System.Windows.Media.Color;
using ColorConverter = System.Windows.Media.ColorConverter;
namespace Microsoft.PowerToys.ThumbnailHandler.Stl
{
///
/// Stl Thumbnail Provider.
///
public class StlThumbnailProvider
{
public StlThumbnailProvider(string filePath)
{
FilePath = filePath;
Stream = new FileStream(filePath, FileMode.Open, FileAccess.Read);
}
///
/// Gets the file path to the file creating thumbnail for.
///
public string FilePath { get; private set; }
///
/// Gets the stream object to access file.
///
public Stream Stream { get; private set; }
///
/// The maximum dimension (width or height) thumbnail we will generate.
///
private const uint MaxThumbnailSize = 10000;
///
/// Loads the Stl model into a Viewport3D and renders a bitmap of it.
///
/// The Stream instance for the Stl content.
/// The maximum thumbnail size, in pixels.
/// A thumbnail rendered from the Stl model.
public static Bitmap GetThumbnail(Stream stream, uint cx)
{
if (cx > MaxThumbnailSize || stream == null || stream.Length == 0)
{
return null;
}
Bitmap thumbnail = null;
var stlReader = new StLReader
{
DefaultMaterial = new DiffuseMaterial(new SolidColorBrush(DefaultMaterialColor)),
};
var model = stlReader.Read(stream);
if (model.Bounds == Rect3D.Empty)
{
return null;
}
var viewport = new System.Windows.Controls.Viewport3D();
viewport.Measure(new System.Windows.Size(cx, cx));
viewport.Arrange(new Rect(0, 0, cx, cx));
var modelVisual = new ModelVisual3D()
{
Transform = new RotateTransform3D(new AxisAngleRotation3D(new Vector3D(0, 0, 1), 180)),
};
viewport.Children.Add(modelVisual);
viewport.Children.Add(new DefaultLights());
var perspectiveCamera = new PerspectiveCamera
{
Position = new Point3D(1, 2, 1),
LookDirection = new Vector3D(-1, -2, -1),
UpDirection = new Vector3D(0, 0, 1),
FieldOfView = 20,
NearPlaneDistance = 0.1,
FarPlaneDistance = double.PositiveInfinity,
};
viewport.Camera = perspectiveCamera;
modelVisual.Content = model;
perspectiveCamera.ZoomExtents(viewport);
var bitmapExporter = new BitmapExporter
{
Background = new SolidColorBrush(Colors.Transparent),
OversamplingMultiplier = 1,
};
var bitmapStream = new MemoryStream();
bitmapExporter.Export(viewport, bitmapStream);
bitmapStream.Position = 0;
thumbnail = new Bitmap(bitmapStream);
return thumbnail;
}
///
/// Generate thumbnail bitmap for provided Gcode file/stream.
///
/// Maximum thumbnail size, in pixels.
/// Generated bitmap
public Bitmap GetThumbnail(uint cx)
{
if (cx == 0 || cx > MaxThumbnailSize)
{
return null;
}
if (global::PowerToys.GPOWrapper.GPOWrapper.GetConfiguredStlThumbnailsEnabledValue() == global::PowerToys.GPOWrapper.GpoRuleConfigured.Disabled)
{
// GPO is disabling this utility.
return null;
}
using (var memStream = new MemoryStream())
{
this.Stream.CopyTo(memStream);
memStream.Position = 0;
using (Bitmap thumbnail = GetThumbnail(memStream, cx))
{
if (thumbnail != null && thumbnail.Size.Width > 0 && thumbnail.Size.Height > 0)
{
return (Bitmap)thumbnail.Clone();
}
}
}
return null;
}
///
/// Gets a value indicating what color to use.
///
public static Color DefaultMaterialColor
{
get
{
try
{
var moduleSettings = new SettingsUtils();
var colorString = moduleSettings.GetSettings(PowerPreviewSettings.ModuleName).Properties.StlThumbnailColor.Value;
return (Color)ColorConverter.ConvertFromString(colorString);
}
catch (FileNotFoundException)
{
// Couldn't read the settings.
// Assume default color value.
return Color.FromRgb(255, 201, 36);
}
}
}
}
}