From 3a4f249416f52a0a2d9e273e6d134d65f0d8d519 Mon Sep 17 00:00:00 2001 From: Lars Brubaker Date: Mon, 19 Mar 2018 18:29:32 -0700 Subject: [PATCH] Removing ImageAsset adding ImageObject3D added image editor using image editor for public property editor added ring object --- DesignTools/ImageAsset.cs | 91 ------- DesignTools/Primitives/ImageObject3D.cs | 184 +++++++++++++++ DesignTools/Primitives/RingObject3D.cs | 4 +- DesignTools/PublicPropertyEditor.cs | 162 +------------ MatterControl.csproj | 3 +- .../View3D/Actions/ImageEditor.cs | 222 ++++++++++++++++++ 6 files changed, 414 insertions(+), 252 deletions(-) delete mode 100644 DesignTools/ImageAsset.cs create mode 100644 DesignTools/Primitives/ImageObject3D.cs create mode 100644 PartPreviewWindow/View3D/Actions/ImageEditor.cs diff --git a/DesignTools/ImageAsset.cs b/DesignTools/ImageAsset.cs deleted file mode 100644 index ab8eb43ed..000000000 --- a/DesignTools/ImageAsset.cs +++ /dev/null @@ -1,91 +0,0 @@ -/* -Copyright (c) 2018, Lars Brubaker, John Lewin -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -1. Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. -2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR -ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -The views and conclusions contained in the software and documentation are those -of the authors and should not be interpreted as representing official policies, -either expressed or implied, of the FreeBSD Project. -*/ - -using System.IO; -using MatterHackers.Agg.Image; -using MatterHackers.Agg.ImageProcessing; -using MatterHackers.Agg.Platform; -using Newtonsoft.Json; - -namespace MatterHackers.MatterControl.DesignTools -{ - public class ImageAsset - { - private string _assetPath; - private ImageBuffer _image; - private bool _invert; - - public string AssetPath - { - get { return _assetPath; } - set - { - if (_assetPath != value) - { - _assetPath = value; - _image = null; - } - } - } - - [JsonIgnore] - public ImageBuffer Image - { - get - { - if (_image == null) - { - if (File.Exists(AssetPath)) - { - _image = AggContext.ImageIO.LoadImage(AssetPath); - if (Invert) - { - _image = InvertLightness.DoInvertLightness(_image); - } - } - } - - return _image; - } - } - - public bool Invert - { - get { return _invert; } - set - { - if (_invert != value) - { - _invert = value; - _image = null; - } - } - } - } -} \ No newline at end of file diff --git a/DesignTools/Primitives/ImageObject3D.cs b/DesignTools/Primitives/ImageObject3D.cs new file mode 100644 index 000000000..87ab313e8 --- /dev/null +++ b/DesignTools/Primitives/ImageObject3D.cs @@ -0,0 +1,184 @@ +/* +Copyright (c) 2017, Lars Brubaker, John Lewin +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +The views and conclusions contained in the software and documentation are those +of the authors and should not be interpreted as representing official policies, +either expressed or implied, of the FreeBSD Project. +*/ + +using System; +using System.IO; +using System.Threading; +using MatterHackers.Agg.Image; +using MatterHackers.Agg.ImageProcessing; +using MatterHackers.Agg.Platform; +using MatterHackers.Agg.UI; +using MatterHackers.DataConverters3D; +using MatterHackers.PolygonMesh; +using Newtonsoft.Json; + +namespace MatterHackers.MatterControl.DesignTools +{ + public class ImageObject3D : AssetObject3D, IRebuildable + { + private const double DefaultSizeMm = 60; + + private string _assetPath; + + private ImageBuffer _image; + + private bool _invert; + + public ImageObject3D() + { + base.Mesh = null; + } + + public override string AssetPath + { + get => _assetPath; + set + { + if (_assetPath != value) + { + _assetPath = value; + _image = null; + } + } + } + + [JsonIgnore] + public ImageBuffer Image + { + get + { + if (_image == null) + { + if (File.Exists(this.AssetPath)) + { + _image = this.LoadImage(); + + if (this.Invert) + { + _image = InvertLightness.DoInvertLightness(_image); + } + + base.Mesh = this.InitMesh() ?? PlatonicSolids.CreateCube(100, 100, 0.2); + } + } + + return _image; + } + } + + public bool Invert + { + get => _invert; + set + { + if (_invert != value) + { + _invert = value; + _image = null; + + this.OnInvalidate(); + } + } + } + + private ImageBuffer LoadImage() + { + // TODO: Consider non-awful alternatives + var resetEvent = new AutoResetEvent(false); + + ImageBuffer imageBuffer = null; + + this.LoadAsset(CancellationToken.None, null).ContinueWith((streamTask) => + { + Stream assetStream = null; + try + { + assetStream = streamTask.Result; + imageBuffer = AggContext.ImageIO.LoadImage(assetStream); + } + catch { } + + assetStream?.Dispose(); + + resetEvent.Set(); + }); + + // Wait up to 30 seconds for a given image asset + resetEvent.WaitOne(30 * 1000); + + return imageBuffer; + } + + public override Mesh Mesh + { + get + { + if (!string.IsNullOrWhiteSpace(this.AssetPath) + // TODO: Remove this hack needed to work around Persistable = false + && (base.Mesh == null || base.Mesh.FaceTexture.Count <= 0)) + { + // TODO: Revise fallback mesh + base.Mesh = this.InitMesh() ?? PlatonicSolids.CreateCube(100, 100, 0.2); + } + + return base.Mesh; + } + } + + public double ScaleMmPerPixels { get; private set; } + + private Mesh InitMesh() + { + if (!string.IsNullOrWhiteSpace(this.AssetPath)) + { + var imageBuffer = this.Image; + if (imageBuffer != null) + { + ScaleMmPerPixels = Math.Min(DefaultSizeMm / imageBuffer.Width, DefaultSizeMm / imageBuffer.Height); + + // Create texture mesh + double width = ScaleMmPerPixels * imageBuffer.Width; + double height = ScaleMmPerPixels * imageBuffer.Height; + + Mesh textureMesh = PlatonicSolids.CreateCube(width, height, 0.2); + MeshHelper.PlaceTextureOnFace(textureMesh.Faces[0], imageBuffer); + + return textureMesh; + } + } + + return null; + } + + public void Rebuild(UndoBuffer undoBuffer) + { + //MeshHelper.PlaceTextureOnFace(Mesh.Faces[0], ImageAsset.Image); + } + } +} \ No newline at end of file diff --git a/DesignTools/Primitives/RingObject3D.cs b/DesignTools/Primitives/RingObject3D.cs index a6e5ba4ab..6edb1acd0 100644 --- a/DesignTools/Primitives/RingObject3D.cs +++ b/DesignTools/Primitives/RingObject3D.cs @@ -65,8 +65,8 @@ namespace MatterHackers.MatterControl.DesignTools } public double OuterDiameter { get; set; } = 20; - public double InnerDiameter { get; set; } = 25; - public double Height { get; set; } = 20; + public double InnerDiameter { get; set; } = 15; + public double Height { get; set; } = 5; public int Sides { get; set; } = 30; public void Rebuild(UndoBuffer undoBuffer) diff --git a/DesignTools/PublicPropertyEditor.cs b/DesignTools/PublicPropertyEditor.cs index 524ce9685..23d7ef165 100644 --- a/DesignTools/PublicPropertyEditor.cs +++ b/DesignTools/PublicPropertyEditor.cs @@ -62,7 +62,7 @@ namespace MatterHackers.MatterControl.DesignTools typeof(double), typeof(int), typeof(char), typeof(string), typeof(bool), typeof(Vector2), typeof(Vector3), typeof(DirectionVector), typeof(DirectionAxis), - typeof(ImageAsset) + typeof(ImageObject3D) }; public const BindingFlags OwnedPropertiesOnly = BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly; @@ -458,12 +458,10 @@ namespace MatterHackers.MatterControl.DesignTools editControlsContainer.AddChild(rowContainer); } // create an image asset editor - else if (property.Value is ImageAsset imageAsset) + else if (property.Value is ImageObject3D imageObject) { - rowContainer = CreateImageEditor(rebuildable, - imageAsset, - theme, - undoBuffer); + var editor = new ImageEditor(); + rowContainer = editor.Create(imageObject, view3DWidget, theme); editControlsContainer.AddChild(rowContainer); } @@ -526,158 +524,6 @@ namespace MatterHackers.MatterControl.DesignTools } } - private GuiWidget CreateImageEditor(IRebuildable item, - ImageAsset imageAsset, - ThemeConfig theme, - UndoBuffer undoBuffer) - { - var column = new FlowLayoutWidget(FlowDirection.TopToBottom) - { - HAnchor = HAnchor.Stretch - }; - - var imageSection = new SectionWidget( - "Image".Localize(), - new FlowLayoutWidget(FlowDirection.TopToBottom), - theme).ApplyBoxStyle(margin: 0); - - column.AddChild(imageSection); - - ImageBuffer thumbnailImage = SetImage(theme, imageAsset); - - ImageWidget thumbnailWidget; - imageSection.ContentPanel.AddChild(thumbnailWidget = new ImageWidget(thumbnailImage) - { - Margin = new BorderDouble(bottom: 5), - HAnchor = HAnchor.Center - }); - - // add a search Google box - var searchRow = new FlowLayoutWidget() - { - HAnchor = HAnchor.Stretch, - VAnchor = VAnchor.Fit, - }; - imageSection.ContentPanel.AddChild(searchRow); - - MHTextEditWidget textToAddWidget = new MHTextEditWidget("", pixelWidth: 300, messageWhenEmptyAndNotSelected: "Search Google".Localize()); - textToAddWidget.HAnchor = HAnchor.Stretch; - searchRow.AddChild(textToAddWidget); - textToAddWidget.ActualTextEditWidget.EnterPressed += (object sender, KeyEventArgs keyEvent) => - { - UiThread.RunOnIdle(() => - { - textToAddWidget.Unfocus(); - string search = "http://www.google.com/search?q={0} silhouette&tbm=isch".FormatWith(textToAddWidget.Text); - ApplicationController.Instance.LaunchBrowser(search); - }); - }; - - // add in the invert checkbox and change image button - var changeImageButton = new TextButton("Change".Localize(), theme) - { - BackgroundColor = theme.MinimalShade - }; - changeImageButton.Click += (sender, e) => - { - UiThread.RunOnIdle(() => - { - // we do this using to make sure that the stream is closed before we try and insert the Picture - AggContext.FileDialogs.OpenFileDialog( - new OpenFileDialogParams( - "Select an image file|*.jpg;*.png;*.bmp;*.gif;*.pdf", - multiSelect: false, - title: "Add Image".Localize()), - (openParams) => - { - if (!File.Exists(openParams.FileName)) - { - return; - } - - imageAsset.AssetPath = openParams.FileName; - thumbnailWidget.Image = SetImage(theme, imageAsset); - - item?.Rebuild(undoBuffer); - - column.Invalidate(); - }); - }); - }; - - var row = new FlowLayoutWidget() - { - HAnchor = HAnchor.Stretch, - VAnchor = VAnchor.Fit, - }; - imageSection.ContentPanel.AddChild(row); - - // Invert checkbox - var invertCheckbox = new CheckBox(new CheckBoxViewText("Invert".Localize(), textColor: theme.Colors.PrimaryTextColor)) - { - Checked = imageAsset.Invert, - Margin = new BorderDouble(0), - }; - invertCheckbox.CheckedStateChanged += (s, e) => - { - imageAsset.Invert = invertCheckbox.Checked; - thumbnailWidget.Image = SetImage(theme, imageAsset); - item?.Rebuild(undoBuffer); - }; - row.AddChild(invertCheckbox); - - row.AddChild(new HorizontalSpacer()); - - row.AddChild(changeImageButton); - - return column; - } - - private ImageBuffer SetImage(ThemeConfig theme, ImageAsset imageAsset) - { - var image = imageAsset.Image; - // Show image load error if needed - if (image == null) - { - image = new ImageBuffer(185, 185).SetPreMultiply(); - var graphics2D = image.NewGraphics2D(); - - graphics2D.FillRectangle(0, 0, 185, 185, theme.MinimalShade); - graphics2D.Rectangle(0, 0, 185, 185, theme.SlightShade); - graphics2D.DrawString("Error Loading Image".Localize() + "...", 10, 185 / 2, baseline: Agg.Font.Baseline.BoundsCenter, color: Color.Red, pointSize: theme.DefaultFontSize, drawFromHintedCach: true); - } - - return (image.Height <= 185) ? image : ScaleThumbnailImage(185, image); - } - - private ImageBuffer ScaleThumbnailImage(int height, ImageBuffer imageBuffer) - { - if (imageBuffer.Height != height) - { - var factor = (double)height / imageBuffer.Height; - - int width = (int)(imageBuffer.Width * factor); - - var scaledImageBuffer = new ImageBuffer(width, height); - scaledImageBuffer.NewGraphics2D().Render(imageBuffer, 0, 0, width, height); - return scaledImageBuffer; - } - - return imageBuffer; - } - - private ImageBuffer ScaleThumbnailImage(int width, int height, ImageBuffer imageBuffer) - { - if (imageBuffer.Width != width) - { - var scaledImageBuffer = new ImageBuffer(width, height); - scaledImageBuffer.NewGraphics2D().Render(imageBuffer, 0, 0, scaledImageBuffer.Width, scaledImageBuffer.Height); - imageBuffer = scaledImageBuffer; - } - - return imageBuffer; - } - private GuiWidget CreateEnumEditor(IRebuildable item, PropertyInfo propertyInfo, Type propertyType, object value, string displayName, ThemeConfig theme, diff --git a/MatterControl.csproj b/MatterControl.csproj index e5a6c7e17..428fa0856 100644 --- a/MatterControl.csproj +++ b/MatterControl.csproj @@ -91,7 +91,6 @@ - @@ -107,6 +106,7 @@ + @@ -135,6 +135,7 @@ + diff --git a/PartPreviewWindow/View3D/Actions/ImageEditor.cs b/PartPreviewWindow/View3D/Actions/ImageEditor.cs new file mode 100644 index 000000000..d04bdcb29 --- /dev/null +++ b/PartPreviewWindow/View3D/Actions/ImageEditor.cs @@ -0,0 +1,222 @@ +/* +Copyright (c) 2018, Lars Brubaker, John Lewin +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +The views and conclusions contained in the software and documentation are those +of the authors and should not be interpreted as representing official policies, +either expressed or implied, of the FreeBSD Project. +*/ + +using System; +using System.Collections.Generic; +using System.IO; +using MatterHackers.Agg; +using MatterHackers.Agg.Image; +using MatterHackers.Agg.UI; +using MatterHackers.Localizations; +using MatterHackers.MatterControl.PartPreviewWindow; + +namespace MatterHackers.MatterControl.DesignTools +{ + using CustomWidgets; + using DataConverters3D; + using MatterHackers.Agg.Platform; + using MatterHackers.MatterControl.Library; + + public class ImageEditor : IObject3DEditor + { + bool IObject3DEditor.Unlocked => true; + + string IObject3DEditor.Name => "Image Editor"; + + public GuiWidget Create(IObject3D item, View3DWidget parentView3D, ThemeConfig theme) + { + var column = new FlowLayoutWidget(FlowDirection.TopToBottom) + { + HAnchor = HAnchor.MaxFitOrStretch + }; + + var imageObject = item as ImageObject3D; + + var activeImage = imageObject.Image; + + var imageSection = new SectionWidget( + "Image".Localize(), + new FlowLayoutWidget(FlowDirection.TopToBottom), + theme).ApplyBoxStyle(margin: 0); + + column.AddChild(imageSection); + + ImageBuffer thumbnailImage = SetImage(theme, imageObject); + + ImageWidget thumbnailWidget; + imageSection.ContentPanel.AddChild(thumbnailWidget = new ImageWidget(thumbnailImage) + { + Margin = new BorderDouble(bottom: 5), + HAnchor = HAnchor.Center + }); + + bool addImageSearch = false; + if(addImageSearch) + { + // add a search Google box + var searchRow = new FlowLayoutWidget() + { + HAnchor = HAnchor.Stretch, + VAnchor = VAnchor.Fit, + }; + imageSection.ContentPanel.AddChild(searchRow); + + MHTextEditWidget textToAddWidget = new MHTextEditWidget("", pixelWidth: 300, messageWhenEmptyAndNotSelected: "Search Google".Localize()); + textToAddWidget.HAnchor = HAnchor.Stretch; + searchRow.AddChild(textToAddWidget); + textToAddWidget.ActualTextEditWidget.EnterPressed += (object sender, KeyEventArgs keyEvent) => + { + UiThread.RunOnIdle(() => + { + textToAddWidget.Unfocus(); + string search = "http://www.google.com/search?q={0} silhouette&tbm=isch".FormatWith(textToAddWidget.Text); + ApplicationController.Instance.LaunchBrowser(search); + }); + }; + } + + // add in the invert checkbox and change image button + var addButton = new TextButton("Change".Localize(), theme) + { + BackgroundColor = theme.MinimalShade + }; + addButton.Click += (sender, e) => + { + UiThread.RunOnIdle(() => + { + // we do this using to make sure that the stream is closed before we try and insert the Picture + AggContext.FileDialogs.OpenFileDialog( + new OpenFileDialogParams( + "Select an image file|*.jpg;*.png;*.bmp;*.gif;*.pdf", + multiSelect: false, + title: "Add Image".Localize()), + (openParams) => + { + if (!File.Exists(openParams.FileName)) + { + return; + } + + imageObject.AssetPath = openParams.FileName; + imageObject.Mesh = null; + + thumbnailWidget.Image = SetImage(theme, imageObject); + + column.Invalidate(); + imageObject.Invalidate(); + }); + }); + }; + + var row = new FlowLayoutWidget() + { + HAnchor = HAnchor.Stretch, + VAnchor = VAnchor.Fit, + }; + imageSection.ContentPanel.AddChild(row); + + // Invert checkbox + var invertCheckbox = new CheckBox(new CheckBoxViewText("Invert".Localize(), textColor: theme.Colors.PrimaryTextColor)) + { + Checked = imageObject.Invert, + Margin = new BorderDouble(0), + }; + invertCheckbox.CheckedStateChanged += (s, e) => + { + imageObject.Invert = invertCheckbox.Checked; + }; + row.AddChild(invertCheckbox); + + row.AddChild(new HorizontalSpacer()); + + row.AddChild(addButton); + + imageObject.Invalidated += (s, e) => + { + if (activeImage != imageObject.Image) + { + thumbnailImage = SetImage(theme, imageObject); + thumbnailWidget.Image = thumbnailImage; + + activeImage = imageObject.Image; + } + }; + + return column; + } + + private ImageBuffer SetImage(ThemeConfig theme, ImageObject3D imageObject) + { + var image = imageObject.Image; + // Show image load error if needed + if (image == null) + { + image = new ImageBuffer(185, 185).SetPreMultiply(); + var graphics2D = image.NewGraphics2D(); + + graphics2D.FillRectangle(0, 0, 185, 185, theme.MinimalShade); + graphics2D.Rectangle(0, 0, 185, 185, theme.SlightShade); + graphics2D.DrawString("Error Loading Image".Localize() + "...", 10, 185 / 2, baseline: Agg.Font.Baseline.BoundsCenter, color: Color.Red, pointSize: theme.DefaultFontSize, drawFromHintedCach: true); + } + + return (image.Height <= 185) ? image : ScaleThumbnailImage(185, image); + } + + IEnumerable IObject3DEditor.SupportedTypes() => new[] { typeof(ImageObject3D) }; + + private ImageBuffer ScaleThumbnailImage(int height, ImageBuffer imageBuffer) + { + if (imageBuffer.Height != height) + { + var factor = (double) height / imageBuffer.Height; + + int width = (int)(imageBuffer.Width * factor); + + var scaledImageBuffer = new ImageBuffer(width, height); + scaledImageBuffer.NewGraphics2D().Render(imageBuffer, 0, 0, width, height); + return scaledImageBuffer; + } + + return imageBuffer; + } + + private ImageBuffer ScaleThumbnailImage(int width, int height, ImageBuffer imageBuffer) + { + if (imageBuffer.Width != width) + { + var scaledImageBuffer = new ImageBuffer(width, height); + scaledImageBuffer.NewGraphics2D().Render(imageBuffer, 0, 0, scaledImageBuffer.Width, scaledImageBuffer.Height); + imageBuffer = scaledImageBuffer; + } + + return imageBuffer; + } + + } +}