瀏覽代碼

Previews are now generating much faster

flabbet 4 年之前
父節點
當前提交
4eec45075c

+ 2 - 2
PixiEditor/App.xaml

@@ -16,8 +16,8 @@
                 <ResourceDictionary Source="Styles/ImageCheckBoxStyle.xaml" />
                 <ResourceDictionary Source="Styles/DarkCheckboxStyle.xaml" />
                 <ResourceDictionary Source="Styles/LabelStyles.xaml" />
-                <ResourceDictionary Source="Styles/AvalonDock/DarkBrushs.xaml" />
-                <ResourceDictionary Source="Styles/AvalonDock/Themes/Menu/DarkBrushs.xaml" />
+                <ResourceDictionary Source="Styles/AvalonDock/DarkBrushes.xaml" />
+                <ResourceDictionary Source="Styles/AvalonDock/Themes/Menu/DarkBrushes.xaml" />
                 <ResourceDictionary Source="Styles/AvalonDock/OverlayButtons.xaml" />
                 <ResourceDictionary Source="Styles/AvalonDock/Themes/Menu/MenuItem.xaml" />
                 <ResourceDictionary Source="Styles/AvalonDock/Themes/Icons/IconGeometry.xaml" />

+ 28 - 21
PixiEditor/Models/ImageManipulation/BitmapUtils.cs

@@ -35,13 +35,9 @@ namespace PixiEditor.Models.ImageManipulation
         /// </summary>
         /// <param name="layers">Layers to combine.</param>
         /// <param name="width">Width of final bitmap.</param>
-        /// <param name="height">Height of final bitmap.</param>
-        /// <param name="stepX">Width precision, determinates how much pixels per row to calculate.
-        /// Ex. layer width = 500, stepX = 5, output image would be 50px wide. So to fill all space, width would need to be 50.</param>
-        /// /// <param name="stepY">Height precision, determinates how much pixels per column to calculate.
-        /// Ex. layer height = 500, stepY = 5, output image would be 50px high. So to fill all space, height would need to be 50.</param>
+        /// <param name="height">Height of final bitmap.</param>        
         /// <returns>WriteableBitmap of layered bitmaps.</returns>
-        public static WriteableBitmap CombineLayers(Layer[] layers, int width, int height, int stepX = 1, int stepY = 1)
+        public static WriteableBitmap CombineLayers(Layer[] layers, int width, int height)
         {
             WriteableBitmap finalBitmap = BitmapFactory.New(width, height);
 
@@ -50,14 +46,16 @@ namespace PixiEditor.Models.ImageManipulation
                 for (int i = 0; i < layers.Length; i++)
                 {
                     float layerOpacity = layers[i].Opacity;
-                    for (int y = 0; y < finalBitmap.Height; y += stepY)
+                    Layer layer = layers[i];
+
+                    for (int y = 0; y < layers[i].Height; y++)
                     {
-                        for (int x = 0; x < finalBitmap.Width; x += stepX)
+                        for (int x = 0; x < layers[i].Width; x++)
                         {
-                            Color color = layers[i].GetPixelWithOffset(x, y);
+                            Color color = layer.GetPixel(x, y);
                             if (i > 0 && ((color.A < 255 && color.A > 0) || (layerOpacity < 1f && layerOpacity > 0 && color.A > 0)))
                             {
-                                var lastLayerPixel = finalBitmap.GetPixel(x, y);
+                                var lastLayerPixel = finalBitmap.GetPixel(x + layer.OffsetX, y + layer.OffsetY);
                                 byte pixelA = (byte)(color.A * layerOpacity);
                                 byte r = (byte)((color.R * pixelA / 255) + (lastLayerPixel.R * lastLayerPixel.A * (255 - pixelA) / (255 * 255)));
                                 byte g = (byte)((color.G * pixelA / 255) + (lastLayerPixel.G * lastLayerPixel.A * (255 - pixelA) / (255 * 255)));
@@ -72,7 +70,7 @@ namespace PixiEditor.Models.ImageManipulation
 
                             if (color.A > 0)
                             {
-                                finalBitmap.SetPixel(x, y, color);
+                                finalBitmap.SetPixel(x + layer.OffsetX, y + layer.OffsetY, color);
                             }
                         }
                     }
@@ -82,21 +80,30 @@ namespace PixiEditor.Models.ImageManipulation
             return finalBitmap;
         }
 
+        /// <summary>
+        /// Generates simplified preview from Document, very fast, great for creating small previews. Creates uniform streched image.
+        /// </summary>
+        /// <param name="document">Document which be used to generate preview.</param>
+        /// <param name="maxPreviewWidth">Max width of preview.</param>
+        /// <param name="maxPreviewHeight">Max height of preview.</param>
+        /// <returns>WriteableBitmap image.</returns>
         public static WriteableBitmap GeneratePreviewBitmap(Document document, int maxPreviewWidth, int maxPreviewHeight)
         {
-            int stepX = 1;
-            int stepY = 1;
-            int targetWidth = document.Width;
-            int targetHeight = document.Height;
-            if (document.Width > maxPreviewWidth || document.Height > maxPreviewHeight)
+            WriteableBitmap previewBitmap = BitmapFactory.New(document.Width, document.Height);
+
+            // 0.8 because blit doesn't take into consideration layer opacity. Small images with opacity > 80% are simillar enough.
+            foreach (var layer in document.Layers.Where(x => x.IsVisible && x.Opacity > 0.8f))
             {
-                stepX = (int)Math.Floor((float)document.Width / maxPreviewWidth);
-                stepY = (int)Math.Floor((float)document.Height / maxPreviewHeight);
-                targetWidth = maxPreviewWidth;
-                targetHeight = maxPreviewHeight;
+                previewBitmap.Blit(
+                    new Rect(layer.OffsetX, layer.OffsetY, layer.Width, layer.Height),
+                    layer.LayerBitmap,
+                    new Rect(0, 0, layer.Width, layer.Height));
             }
 
-            return CombineLayers(document.Layers.ToArray(), document.Width, document.Height, stepX, stepY);
+            int width = document.Width >= document.Height ? maxPreviewWidth : document.Width / (document.Height / maxPreviewHeight);
+            int height = document.Height > document.Width ? maxPreviewHeight : document.Height / (document.Width / maxPreviewWidth);
+
+            return previewBitmap.Resize(width, height, WriteableBitmapExtensions.Interpolation.NearestNeighbor);
         }
 
         public static Dictionary<Layer, Color[]> GetPixelsForSelection(Layer[] layers, Coordinates[] selection)

+ 4 - 4
PixiEditor/Styles/AvalonDock/DarkBrushs.xaml → PixiEditor/Styles/AvalonDock/DarkBrushes.xaml

@@ -4,7 +4,7 @@
 	xmlns:options="http://schemas.microsoft.com/winfx/2006/xaml/presentation/options" 
 	xmlns:reskeys="clr-namespace:PixiEditor.Styles.AvalonDock.Themes">
 	<ResourceDictionary.MergedDictionaries>
-		<ResourceDictionary Source="Themes/Menu/DarkBrushs.xaml" />
+		<ResourceDictionary Source="Themes/Menu/DarkBrushes.xaml" />
 	</ResourceDictionary.MergedDictionaries>
 
 	<!--  Accent Keys  -->
@@ -94,7 +94,7 @@
 	<SolidColorBrush
 		x:Key="{x:Static reskeys:ResourceKeys.DocumentWellTabSelectedActiveBackground}"
 		options:Freeze="true"
-		Color="#505056" />
+		Color="#B00022" />
 
 	<SolidColorBrush
 		x:Key="{x:Static reskeys:ResourceKeys.DocumentWellTabSelectedActiveText}"
@@ -323,7 +323,7 @@
 	<SolidColorBrush
 		x:Key="{x:Static reskeys:ResourceKeys.ToolWindowTabSelectedActiveText}"
 		options:Freeze="true"
-		Color="#B00022" />
+		Color="#FFFFFF" />
 	<SolidColorBrush
 		x:Key="{x:Static reskeys:ResourceKeys.ToolWindowTabSelectedInactiveBackground}"
 		options:Freeze="true"
@@ -349,7 +349,7 @@
 	<SolidColorBrush
 		x:Key="{x:Static reskeys:ResourceKeys.ToolWindowTabUnselectedHoveredText}"
 		options:Freeze="true"
-		Color="#D60029" />
+		Color="Gray" />
 
 	<!--  Floating Document Window  -->
 	<SolidColorBrush

+ 1 - 1
PixiEditor/Styles/AvalonDock/PixiEditorDockTheme.xaml

@@ -1,6 +1,6 @@
 <ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
     <ResourceDictionary.MergedDictionaries>
-        <ResourceDictionary Source="/Styles/AvalonDock/DarkBrushs.xaml" />
+        <ResourceDictionary Source="/Styles/AvalonDock/DarkBrushes.xaml" />
         <ResourceDictionary Source="/Styles/AvalonDock/Themes/Generic.xaml" />
     </ResourceDictionary.MergedDictionaries>
 

+ 1 - 1
PixiEditor/Styles/AvalonDock/Themes/Generic.xaml

@@ -7,7 +7,7 @@
 	xmlns:avalonDockProperties="clr-namespace:AvalonDock.Properties;assembly=AvalonDock"
 	xmlns:reskeys="clr-namespace:PixiEditor.Styles.AvalonDock.Themes"
     xmlns:ex="clr-namespace:PixiEditor.Helpers.Extensions"
-	xmlns:shell="clr-namespace:Microsoft.Windows.Shell;assembly=AvalonDock" xmlns:converters="clr-namespace:PixiEditor.Helpers.Converters">
+	xmlns:shell="clr-namespace:Microsoft.Windows.Shell;assembly=AvalonDock">
 	<ResourceDictionary.MergedDictionaries>
 		<ResourceDictionary Source="/Styles/AvalonDock/OverlayButtons.xaml" />
         <ResourceDictionary Source="/Styles/AvalonDock/Themes/Menu/MenuItem.xaml" />

+ 0 - 0
PixiEditor/Styles/AvalonDock/Themes/Menu/DarkBrushs.xaml → PixiEditor/Styles/AvalonDock/Themes/Menu/DarkBrushes.xaml


+ 0 - 1
PixiEditor/Views/MainWindow.xaml

@@ -5,7 +5,6 @@
         xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
         xmlns:vm="clr-namespace:PixiEditor.ViewModels"
         xmlns:vws="clr-namespace:PixiEditor.Views"
-        xmlns:ex="clr-namespace:PixiEditor.Helpers.Extensions"
         xmlns:converters="clr-namespace:PixiEditor.Helpers.Converters"
         xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
         xmlns:ui="clr-namespace:PixiEditor.Helpers.UI"