Skip to content

Commit

Permalink
[1] Show mean values in BitmapHistogramsView.
Browse files Browse the repository at this point in the history
[2] Fine tune colors of BitmapHistogramsView.
  • Loading branch information
hamster620 committed Oct 4, 2023
1 parent f5fadb5 commit 08cc106
Show file tree
Hide file tree
Showing 7 changed files with 108 additions and 15 deletions.
1 change: 1 addition & 0 deletions PixelViewer/ChangeList-zh-CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
## 新功能
+ 添加 **「Bayer 排列 (8 位)」** 格式。
+ 支持指定色彩空间转换的时机。
+ 在亮度/红/绿/蓝色阶分布图中显示色彩平均值。
+ 支持自动最小化图像查看器的滚动条,如果不需要可以关闭。
+ 开启 **「启用色彩管理」** 时,将选取的色彩空间写入至图片中。
+ 支持使用内建中文字型 (思源黑体)。
Expand Down
1 change: 1 addition & 0 deletions PixelViewer/ChangeList-zh-TW.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
## 新功能
+ 新增 **「Bayer 排列 (8 位元)」** 格式。
+ 支援指定色彩空間轉換的時機。
+ 在亮度/紅/綠/藍色階分佈圖中顯示色彩平均值。
+ 支援自動將圖片檢視器捲動軸最小化,亦可關閉此功能。
+ 開啟 **「啟用色彩管理」** 時,將選取的色彩空間儲存於圖片中。
+ 支援使用內建中文字型 (思源黑體)。
Expand Down
1 change: 1 addition & 0 deletions PixelViewer/ChangeList.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
## New Features
+ Add **'Bayer Pattern (8-bit)'** format.
+ Support specifying timing of color space conversion.
+ Show mean values in histogram of Luminance/Red/Green/Blue.
+ Support minimizing scroll bars of image viewer automatically, it can be turned off if you don't want it.
+ Save image with color space when **'Enable color management'** is on.
+ Support using built-in font (Noto Sans) for Chinese.
Expand Down
39 changes: 30 additions & 9 deletions PixelViewer/Controls/BitmapHistogramsView.axaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:a="using:Avalonia"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="Carina.PixelViewer.Controls.BitmapHistogramsView">
x:Class="Carina.PixelViewer.Controls.BitmapHistogramsView"
Name="root">

<Grid RowDefinitions="Auto,*,Auto">

Expand All @@ -21,32 +22,52 @@
</Panel.Styles>

<!-- Red -->
<Image IsVisible="{Binding $parent[UserControl].IsRedHistogramVisible}" Source="{Binding $parent[UserControl].RedHistogramImage}">
<Image IsVisible="{Binding #root.IsRedHistogramVisible}" Source="{Binding #root.RedHistogramImage}">
<Image.RenderTransform>
<ScaleTransform ScaleY="{Binding $parent[UserControl].RedHistogramScaleY}"/>
<ScaleTransform ScaleY="{Binding #root.RedHistogramScaleY}"/>
</Image.RenderTransform>
</Image>
<Line EndPoint="0,10" HorizontalAlignment="Left" IsVisible="{Binding #root.IsRedHistogramVisible}" StartPoint="0,0" Stretch="Fill" Stroke="{DynamicResource Brush/BitmapHistogramsView.MeanOfRed}" StrokeDashArray="3,1.5" VerticalAlignment="Stretch" Width="1">
<Line.RenderTransform>
<TranslateTransform X="{Binding #root.MeanOfRedOffset}"/>
</Line.RenderTransform>
</Line>

<!-- Green -->
<Image IsVisible="{Binding $parent[UserControl].IsGreenHistogramVisible}" Source="{Binding $parent[UserControl].GreenHistogramImage}">
<Image IsVisible="{Binding #root.IsGreenHistogramVisible}" Source="{Binding #root.GreenHistogramImage}">
<Image.RenderTransform>
<ScaleTransform ScaleY="{Binding $parent[UserControl].GreenHistogramScaleY}"/>
<ScaleTransform ScaleY="{Binding #root.GreenHistogramScaleY}"/>
</Image.RenderTransform>
</Image>
<Line EndPoint="0,10" HorizontalAlignment="Left" IsVisible="{Binding #root.IsGreenHistogramVisible}" StartPoint="0,0" Stretch="Fill" Stroke="{DynamicResource Brush/BitmapHistogramsView.MeanOfGreen}" StrokeDashArray="3,1.5" VerticalAlignment="Stretch" Width="1">
<Line.RenderTransform>
<TranslateTransform X="{Binding #root.MeanOfGreenOffset}"/>
</Line.RenderTransform>
</Line>

<!-- Blue -->
<Image IsVisible="{Binding $parent[UserControl].IsBlueHistogramVisible}" Source="{Binding $parent[UserControl].BlueHistogramImage}">
<Image IsVisible="{Binding #root.IsBlueHistogramVisible}" Source="{Binding #root.BlueHistogramImage}">
<Image.RenderTransform>
<ScaleTransform ScaleY="{Binding $parent[UserControl].BlueHistogramScaleY}"/>
<ScaleTransform ScaleY="{Binding #root.BlueHistogramScaleY}"/>
</Image.RenderTransform>
</Image>
<Line EndPoint="0,10" HorizontalAlignment="Left" IsVisible="{Binding #root.IsBlueHistogramVisible}" StartPoint="0,0" Stretch="Fill" Stroke="{DynamicResource Brush/BitmapHistogramsView.MeanOfBlue}" StrokeDashArray="3,1.5" VerticalAlignment="Stretch" Width="1">
<Line.RenderTransform>
<TranslateTransform X="{Binding #root.MeanOfBlueOffset}"/>
</Line.RenderTransform>
</Line>

<!-- Luminance -->
<Image IsVisible="{Binding $parent[UserControl].IsLuminanceHistogramVisible}" Source="{Binding $parent[UserControl].LuminanceHistogramImage}">
<Image IsVisible="{Binding #root.IsLuminanceHistogramVisible}" Source="{Binding #root.LuminanceHistogramImage}">
<Image.RenderTransform>
<ScaleTransform ScaleY="{Binding $parent[UserControl].LuminanceHistogramScaleY}"/>
<ScaleTransform ScaleY="{Binding #root.LuminanceHistogramScaleY}"/>
</Image.RenderTransform>
</Image>
<Line EndPoint="0,10" HorizontalAlignment="Left" IsVisible="{Binding #root.IsLuminanceHistogramVisible}" StartPoint="0,0" Stretch="Fill" Stroke="{DynamicResource Brush/BitmapHistogramsView.MeanOfLuminance}" StrokeDashArray="3,1.5" VerticalAlignment="Stretch" Width="1">
<Line.RenderTransform>
<TranslateTransform X="{Binding #root.MeanOfLuminanceOffset}"/>
</Line.RenderTransform>
</Line>

</Panel>

Expand Down
61 changes: 56 additions & 5 deletions PixelViewer/Controls/BitmapHistogramsView.axaml.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using Avalonia;
using Avalonia.Controls;
using Avalonia.Media;
using Avalonia.Markup.Xaml;
using Carina.PixelViewer.Media;
Expand Down Expand Up @@ -60,6 +61,10 @@ class BitmapHistogramsView : UserControl<IAppSuiteApplication>
static readonly StyledProperty<double> GreenHistogramScaleYProperty = AvaloniaProperty.Register<BitmapHistogramsView, double>(nameof(GreenHistogramScaleY), 0);
static readonly StyledProperty<IImage?> LuminanceHistogramImageProperty = AvaloniaProperty.Register<BitmapHistogramsView, IImage?>(nameof(LuminanceHistogramImage));
static readonly StyledProperty<double> LuminanceHistogramScaleYProperty = AvaloniaProperty.Register<BitmapHistogramsView, double>(nameof(LuminanceHistogramScaleY), 0);
static readonly StyledProperty<double> MeanOfBlueOffsetProperty = AvaloniaProperty.Register<BitmapHistogramsView, double>(nameof(MeanOfBlueOffset), double.NaN);
static readonly StyledProperty<double> MeanOfGreenOffsetProperty = AvaloniaProperty.Register<BitmapHistogramsView, double>(nameof(MeanOfGreenOffset), double.NaN);
static readonly StyledProperty<double> MeanOfLuminanceOffsetProperty = AvaloniaProperty.Register<BitmapHistogramsView, double>(nameof(MeanOfLuminanceOffset), double.NaN);
static readonly StyledProperty<double> MeanOfRedOffsetProperty = AvaloniaProperty.Register<BitmapHistogramsView, double>(nameof(MeanOfRedOffset), double.NaN);
static readonly StyledProperty<IImage?> RedHistogramImageProperty = AvaloniaProperty.Register<BitmapHistogramsView, IImage?>(nameof(RedHistogramImage));
static readonly StyledProperty<double> RedHistogramScaleYProperty = AvaloniaProperty.Register<BitmapHistogramsView, double>(nameof(RedHistogramScaleY), 0);

Expand All @@ -71,6 +76,7 @@ class BitmapHistogramsView : UserControl<IAppSuiteApplication>
int maxRedValue;
readonly ScheduledAction updateHistogramImagesAction;
readonly ScheduledAction updateHistogramScalesAction;
readonly ScheduledAction updateMeanOfColorsAction;


/// <summary>
Expand All @@ -83,7 +89,7 @@ public BitmapHistogramsView()
this.IsEnabled = false;

// create actions
this.updateHistogramImagesAction = new ScheduledAction(() =>
this.updateHistogramImagesAction = new(() =>
{
if (this.DataContext is BitmapHistograms histograms)
{
Expand All @@ -100,7 +106,7 @@ public BitmapHistogramsView()
this.SetValue(LuminanceHistogramImageProperty, null);
}
});
this.updateHistogramScalesAction = new ScheduledAction(() =>
this.updateHistogramScalesAction = new(() =>
{
// check state
if (this.DataContext is not BitmapHistograms histograms)
Expand All @@ -115,6 +121,26 @@ public BitmapHistogramsView()
this.SetValue(BlueHistogramScaleYProperty, this.IsBlueHistogramVisible ? this.maxBlueValue / maxValue : 0);
this.SetValue(LuminanceHistogramScaleYProperty, this.IsLuminanceHistogramVisible ? this.maxLuminanceValue / maxValue : 0);
});
this.updateMeanOfColorsAction = new(() =>
{
var width = this.Bounds.Width;
if (width <= 0)
return;
if (this.DataContext is BitmapHistograms histograms)
{
this.SetValue(MeanOfBlueOffsetProperty, width * histograms.MeanOfBlue / histograms.ColorCount);
this.SetValue(MeanOfGreenOffsetProperty, width * histograms.MeanOfGreen / histograms.ColorCount);
this.SetValue(MeanOfLuminanceOffsetProperty, width * histograms.MeanOfLuminance / histograms.ColorCount);
this.SetValue(MeanOfRedOffsetProperty, width * histograms.MeanOfRed / histograms.ColorCount);
}
else
{
this.SetValue(MeanOfBlueOffsetProperty, double.NaN);
this.SetValue(MeanOfGreenOffsetProperty, double.NaN);
this.SetValue(MeanOfLuminanceOffsetProperty, double.NaN);
this.SetValue(MeanOfRedOffsetProperty, double.NaN);
}
});
}


Expand Down Expand Up @@ -173,12 +199,12 @@ void DetachFromBitmapHistograms(BitmapHistograms histograms)
pathBuilder.Append(" Z");
try
{
return new DrawingImage()
return new DrawingImage
{
Drawing = new GeometryDrawing()
Drawing = new GeometryDrawing
{
Brush = brush,
Geometry = PathGeometry.Parse(pathBuilder.ToString()),
Geometry = StreamGeometry.Parse(pathBuilder.ToString()),
},
};
}
Expand Down Expand Up @@ -270,6 +296,22 @@ public IBrush? LuminanceHistogramBrush
double LuminanceHistogramScaleY => this.GetValue(LuminanceHistogramScaleYProperty);


// Pixel offset of mean of blue.
double MeanOfBlueOffset => this.GetValue(MeanOfBlueOffsetProperty);


// Pixel offset of mean of green.
double MeanOfGreenOffset => this.GetValue(MeanOfGreenOffsetProperty);


// Pixel offset of mean of luminance.
double MeanOfLuminanceOffset => this.GetValue(MeanOfLuminanceOffsetProperty);


// Pixel offset of mean of red.
double MeanOfRedOffset => this.GetValue(MeanOfRedOffsetProperty);


/// <inheritdoc/>
protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change)
{
Expand All @@ -286,6 +328,7 @@ protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs chang
{
(change.OldValue as BitmapHistograms)?.Let(this.DetachFromBitmapHistograms);
(change.NewValue as BitmapHistograms)?.Let(this.AttachToBitmapHistograms);
this.updateMeanOfColorsAction.Schedule();
}
else if (property == IsBlueHistogramVisibleProperty
|| property == IsGreenHistogramVisibleProperty
Expand All @@ -297,6 +340,14 @@ protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs chang
}


/// <inheritdoc/>
protected override void OnSizeChanged(SizeChangedEventArgs e)
{
base.OnSizeChanged(e);
this.updateMeanOfColorsAction.Schedule();
}


/// <summary>
/// Get or set brush for histogram of red channel.
/// </summary>
Expand Down
10 changes: 9 additions & 1 deletion PixelViewer/Styles/Base.axaml
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,18 @@
<SolidColorBrush x:Key="Brush/BitmapHistogramsView.BlueHistogram.Background" Color="{DynamicResource Color/BitmapHistogramsView.BlueHistogram.Background}"/>
<SolidColorBrush x:Key="Brush/BitmapHistogramsView.GreenHistogram.Background" Color="{DynamicResource Color/BitmapHistogramsView.GreenHistogram.Background}"/>
<SolidColorBrush x:Key="Brush/BitmapHistogramsView.LuminanceHistogram.Background" Color="{DynamicResource Color/BitmapHistogramsView.LuminanceHistogram.Background}"/>
<SolidColorBrush x:Key="Brush/BitmapHistogramsView.MeanOfBlue" Color="{DynamicResource Color/BitmapHistogramsView.MeanOfBlue}"/>
<SolidColorBrush x:Key="Brush/BitmapHistogramsView.MeanOfGreen" Color="{DynamicResource Color/BitmapHistogramsView.MeanOfGreen}"/>
<SolidColorBrush x:Key="Brush/BitmapHistogramsView.MeanOfLuminance" Color="{DynamicResource Color/BitmapHistogramsView.MeanOfLuminance}"/>
<SolidColorBrush x:Key="Brush/BitmapHistogramsView.MeanOfRed" Color="{DynamicResource Color/BitmapHistogramsView.MeanOfRed}"/>
<SolidColorBrush x:Key="Brush/BitmapHistogramsView.RedHistogram.Background" Color="{DynamicResource Color/BitmapHistogramsView.RedHistogram.Background}"/>
<Color x:Key="Color/BitmapHistogramsView.BlueHistogram.Background">#3f3fff</Color>
<Color x:Key="Color/BitmapHistogramsView.GreenHistogram.Background">#3fff3f</Color>
<Color x:Key="Color/BitmapHistogramsView.GreenHistogram.Background">#32cc32</Color>
<Color x:Key="Color/BitmapHistogramsView.LuminanceHistogram.Background">#bfbfbf</Color>
<Color x:Key="Color/BitmapHistogramsView.MeanOfBlue">#80b0ff</Color>
<Color x:Key="Color/BitmapHistogramsView.MeanOfGreen">#99ff99</Color>
<Color x:Key="Color/BitmapHistogramsView.MeanOfLuminance">#ffffff</Color>
<Color x:Key="Color/BitmapHistogramsView.MeanOfRed">#ff9a9a</Color>
<Color x:Key="Color/BitmapHistogramsView.RedHistogram.Background">#ff3f3f</Color>
<Thickness x:Key="Thickness/BitmapHistogramsView.Border">1</Thickness>
<Thickness x:Key="Thickness/BitmapHistogramsView.Padding">5,0,5,0</Thickness>
Expand Down
10 changes: 10 additions & 0 deletions PixelViewer/Styles/Light.axaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,16 @@

<!-- Resources -->
<Styles.Resources>

<!-- BitmapHistogramsView -->
<Color x:Key="Color/BitmapHistogramsView.BlueHistogram.Background">#1717e6</Color>
<Color x:Key="Color/BitmapHistogramsView.GreenHistogram.Background">#10a610</Color>
<Color x:Key="Color/BitmapHistogramsView.LuminanceHistogram.Background">#7f7f7f</Color>
<Color x:Key="Color/BitmapHistogramsView.MeanOfBlue">#0a0a66</Color>
<Color x:Key="Color/BitmapHistogramsView.MeanOfGreen">#084d08</Color>
<Color x:Key="Color/BitmapHistogramsView.MeanOfLuminance">#333333</Color>
<Color x:Key="Color/BitmapHistogramsView.MeanOfRed">#801313</Color>
<Color x:Key="Color/BitmapHistogramsView.RedHistogram.Background">#cd1e1e</Color>

<!-- SessionControl -->
<Color x:Key="Color/SessionControl.ColorSpaceLabel.Background.Custom">#004a7f</Color>
Expand Down

0 comments on commit 08cc106

Please sign in to comment.