Skip to content

Commit 845ef97

Browse files
committed
offset preview rendering by the image offset amount
1 parent 7ba6194 commit 845ef97

File tree

3 files changed

+36
-44
lines changed

3 files changed

+36
-44
lines changed

Gui/ViewModels/SubObjectTypes/ImageTableViewModel.cs

Lines changed: 9 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
using Common.Logging;
66
using Definitions.ObjectModels;
77
using Definitions.ObjectModels.Types;
8-
using DynamicData;
98
using ReactiveUI;
109
using ReactiveUI.Fody.Helpers;
1110
using SixLabors.ImageSharp;
@@ -62,9 +61,6 @@ public class ImageTableViewModel : ReactiveObject, IExtraContentViewModel
6261
[Reactive]
6362
public SelectionModel<ImageViewModel> SelectionModel { get; set; }
6463

65-
[Reactive]
66-
public IList<ImageViewModel> SelectedImages { get; set; }
67-
6864
[Reactive]
6965
public ImageViewModel? SelectedImage { get; set; }
7066

@@ -84,8 +80,8 @@ public ImageTableViewModel(IList<GraphicsElement> graphicsElements, IImageTableN
8480
var index = 0;
8581
foreach (var ge in graphicsElements)
8682
{
87-
_ = imageNameProvider.TryGetImageName(index, out var imageName);
88-
ImageViewModels.Add(new ImageViewModel(index, imageName, ge, paletteMap));
83+
var success = imageNameProvider.TryGetImageName(index, out var imageName);
84+
ImageViewModels.Add(new ImageViewModel(index, success ? imageName! : "failed to get image name", ge, paletteMap));
8985
index++;
9086
}
9187

@@ -119,10 +115,7 @@ public ImageTableViewModel(IList<GraphicsElement> graphicsElements, IImageTableN
119115
ImportImagesCommand = ReactiveCommand.CreateFromTask(ImportImages);
120116
ExportImagesCommand = ReactiveCommand.CreateFromTask(ExportImages);
121117
ReplaceImageCommand = ReactiveCommand.CreateFromTask(ReplaceImage);
122-
CropAllImagesCommand = ReactiveCommand.Create(() =>
123-
{
124-
CropAllImages(SelectedPrimarySwatch, SelectedSecondarySwatch);
125-
});
118+
CropAllImagesCommand = ReactiveCommand.Create(CropAllImages);
126119

127120
ZeroOffsetAllImagesCommand = ReactiveCommand.Create(() =>
128121
{
@@ -164,19 +157,16 @@ void SelectionChanged(object sender, SelectionModelSelectionChangedEventArgs e)
164157
{
165158
return;
166159
}
167-
168-
// ... handle selection changed
169-
SelectedImages = [.. sm.SelectedItems.Cast<ImageViewModel>()];
170160
}
171161

172162
void AnimationTimer_Tick(object? sender, EventArgs e)
173163
{
174-
if (SelectionModel == null || SelectedImages == null || SelectedImages.Count == 0 || SelectionModel.SelectedIndexes.Count == 0)
164+
if (SelectionModel == null || SelectionModel.SelectedIndexes.Count == 0)
175165
{
176166
return;
177167
}
178168

179-
if (currentFrameIndex >= SelectedImages.Count)
169+
if (currentFrameIndex >= SelectionModel.SelectedIndexes.Count)
180170
{
181171
currentFrameIndex = 0;
182172
}
@@ -185,7 +175,7 @@ void AnimationTimer_Tick(object? sender, EventArgs e)
185175
SelectedImageIndex = SelectionModel.SelectedIndexes[currentFrameIndex]; // disabling this also makes the memory leaks stop
186176

187177
// Move to the next frame, looping back to the beginning if necessary
188-
currentFrameIndex = (currentFrameIndex + 1) % SelectedImages.Count;
178+
currentFrameIndex = (currentFrameIndex + 1) % SelectionModel.SelectedIndexes.Count;
189179
}
190180

191181
public void ClearSelectionModel()
@@ -207,7 +197,7 @@ public async Task ImportImages()
207197
}
208198

209199
var dirPath = dir.Path.LocalPath;
210-
await ImportImages(dirPath, SelectedPrimarySwatch, SelectedSecondarySwatch);
200+
await ImportImages(dirPath);
211201
}
212202

213203
animationTimer.Start();
@@ -257,7 +247,7 @@ public void RecolourImages(ColourRemapSwatch primary, ColourRemapSwatch secondar
257247
}
258248
}
259249

260-
public void CropAllImages(ColourRemapSwatch primary, ColourRemapSwatch secondary)
250+
public void CropAllImages()
261251
{
262252
foreach (var ivm in ImageViewModels)
263253
{
@@ -276,7 +266,7 @@ public static string TrimZeroes(string str)
276266
return result.Length == 0 ? "0" : result;
277267
}
278268

279-
public async Task ImportImages(string directory, ColourRemapSwatch primary, ColourRemapSwatch secondary)
269+
public async Task ImportImages(string directory)
280270
{
281271
if (string.IsNullOrEmpty(directory))
282272
{

Gui/ViewModels/SubObjectTypes/ImageViewModel.cs

Lines changed: 22 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -31,43 +31,40 @@ public class ImageViewModel : ReactiveObject
3131
[Reactive, Browsable(false)]
3232
public Image<Rgba32> UnderlyingImage { get; set; }
3333

34-
[Browsable(false)]
35-
public Avalonia.Size SelectedBitmapPreviewBorder
34+
public Avalonia.Rect SelectedBitmapPreviewBorder
3635
=> Image == null
37-
? new Avalonia.Size()
38-
: new Avalonia.Size(Image.Size.Width + 2, Image.Size.Height + 2);
36+
? new Avalonia.Rect()
37+
: new Avalonia.Rect(
38+
XOffset - 1,
39+
YOffset - 1,
40+
Image.Size.Width + 2,
41+
Image.Size.Height + 2);
3942

40-
PaletteMap PaletteMap;
41-
42-
ImageViewModel() { }
43+
readonly PaletteMap PaletteMap;
4344

4445
public ImageViewModel(int imageIndex, string imageName, GraphicsElement graphicsElement, PaletteMap paletteMap)
45-
: this()
4646
{
4747
ImageIndex = imageIndex;
4848
ImageName = imageName;
4949
XOffset = graphicsElement.XOffset;
5050
YOffset = graphicsElement.YOffset;
5151
Flags = graphicsElement.Flags;
5252
ZoomOffset = graphicsElement.ZoomOffset;
53+
PaletteMap = paletteMap;
5354

5455
_ = this.WhenAnyValue(o => o.UnderlyingImage)
5556
.Where(x => x != null)
56-
.Subscribe(_ =>
57-
{
58-
Image = UnderlyingImage!.ToAvaloniaBitmap();
59-
});
57+
.Subscribe(_ => UnderlyingImageChanged());
6058

6159
_ = this.WhenAnyValue(o => o.Image)
6260
.Subscribe(_ => this.RaisePropertyChanged(nameof(SelectedBitmapPreviewBorder)));
6361

64-
if (paletteMap.TryConvertG1ToRgba32Bitmap(graphicsElement, ColourRemapSwatch.PrimaryRemap, ColourRemapSwatch.SecondaryRemap, out var image))
62+
if (!PaletteMap.TryConvertG1ToRgba32Bitmap(graphicsElement, ColourRemapSwatch.PrimaryRemap, ColourRemapSwatch.SecondaryRemap, out var image))
6563
{
66-
UnderlyingImage = image;
67-
//Image = image.ToAvaloniaBitmap();
64+
throw new Exception("Failed to convert image");
6865
}
6966

70-
PaletteMap = paletteMap;
67+
UnderlyingImage = image!;
7168
}
7269

7370
public void RecolourImage(ColourRemapSwatch primary, ColourRemapSwatch secondary)
@@ -88,26 +85,31 @@ public void RecolourImage(ColourRemapSwatch primary, ColourRemapSwatch secondary
8885

8986
if (!PaletteMap.TryConvertG1ToRgba32Bitmap(dummyElement, primary, secondary, out var image))
9087
{
88+
throw new Exception("Failed to recolour image");
9189
}
92-
Image = image.ToAvaloniaBitmap();
90+
91+
// only update the UI image - don't update the underlying image as we want to keep the original
92+
Image = image!.ToAvaloniaBitmap();
9393
}
9494

95+
void UnderlyingImageChanged()
96+
=> Image = UnderlyingImage!.ToAvaloniaBitmap();
97+
9598
public void CropImage()
9699
{
97100
var cropRegion = FindCropRegion(UnderlyingImage);
98101

99102
if (cropRegion.Width <= 0 || cropRegion.Height <= 0)
100103
{
101104
UnderlyingImage.Mutate(i => i.Crop(new Rectangle(0, 0, 1, 1)));
102-
103-
Image = UnderlyingImage.ToAvaloniaBitmap();
105+
UnderlyingImageChanged();
104106
XOffset = 0;
105107
YOffset = 0;
106108
}
107109
else
108110
{
109111
UnderlyingImage.Mutate(i => i.Crop(cropRegion));
110-
Image = UnderlyingImage.ToAvaloniaBitmap();
112+
UnderlyingImageChanged();
111113
XOffset += cropRegion.Left;
112114
YOffset += cropRegion.Top;
113115
}

Gui/Views/ImageTableView.axaml

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -131,14 +131,14 @@
131131
</Button.Flyout>
132132
</Button>
133133
</StackPanel>
134-
<paz:ZoomBorder Name="ZoomBorder" MinWidth="256" MinHeight="256" Stretch="None" ZoomSpeed="1.2" MinZoomX="0.5" MaxZoomX="30" MinZoomY="0.5" MaxZoomY="30" ClipToBounds="True" Focusable="True" VerticalAlignment="Stretch" HorizontalAlignment="Stretch" PanButton="Left" Background="{Binding #ImageColorViewPreviewBackground.Color, ConverterParameter={x:Static Brushes.Transparent}, Converter={StaticResource ColorToBrushConverter}}" >
135-
<Canvas Width="{Binding SelectedImage.Width}" Height="{Binding SelectedImage.Height}" HorizontalAlignment="Center" VerticalAlignment="Center" Background="Gray">
134+
<paz:ZoomBorder Name="ZoomBorder" MinWidth="256" MinHeight="256" Stretch="None" ZoomSpeed="2.0" MinZoomX="0.5" MaxZoomX="64" MinZoomY="0.5" MaxZoomY="64" ClipToBounds="True" Focusable="True" VerticalAlignment="Stretch" HorizontalAlignment="Stretch" PanButton="Left" Background="{Binding #ImageColorViewPreviewBackground.Color, ConverterParameter={x:Static Brushes.Transparent}, Converter={StaticResource ColorToBrushConverter}}" >
135+
<Canvas HorizontalAlignment="Center" VerticalAlignment="Center" Background="Gray">
136136
<!--Bounding box-->
137-
<Rectangle Canvas.Top="-1" Canvas.Left="-1" StrokeThickness="1.0" Width="{Binding SelectedImage.SelectedBitmapPreviewBorder.Width}" Height="{Binding SelectedImage.SelectedBitmapPreviewBorder.Height}" Opacity="1.0" Fill="{Binding #ImageColorViewPreviewBackground.Color, ConverterParameter={x:Static Brushes.Transparent}, Converter={StaticResource ColorToBrushConverter}}" Stroke="{Binding #ImageColorViewBorder.Color, ConverterParameter={x:Static Brushes.Transparent}, Converter={StaticResource ColorToBrushConverter}}" />
137+
<Rectangle Canvas.Left="{Binding SelectedImage.SelectedBitmapPreviewBorder.X}" Canvas.Top="{Binding SelectedImage.SelectedBitmapPreviewBorder.Y}" StrokeThickness="1.0" Width="{Binding SelectedImage.SelectedBitmapPreviewBorder.Width}" Height="{Binding SelectedImage.SelectedBitmapPreviewBorder.Height}" Opacity="1.0" Fill="{Binding #ImageColorViewPreviewBackground.Color, ConverterParameter={x:Static Brushes.Transparent}, Converter={StaticResource ColorToBrushConverter}}" Stroke="{Binding #ImageColorViewBorder.Color, ConverterParameter={x:Static Brushes.Transparent}, Converter={StaticResource ColorToBrushConverter}}" />
138138
<!--Image-->
139-
<Image Name="AnimationPreviewPP" Canvas.Top="0" Canvas.Left ="0" Source="{Binding SelectedImage.Image}" RenderOptions.BitmapInterpolationMode="None" Stretch="None"/>
139+
<Image Canvas.Left="{Binding SelectedImage.XOffset}" Canvas.Top="{Binding SelectedImage.YOffset}" Source="{Binding SelectedImage.Image}" RenderOptions.BitmapInterpolationMode="None" Stretch="None"/>
140140
<!--Origin point-->
141-
<Rectangle Canvas.Left="{Binding SelectedImage.XOffset, Converter={StaticResource NegativeValueConverter}}" Canvas.Top="{Binding SelectedImage.YOffset, Converter={StaticResource NegativeValueConverter}}" Width="1" Height="1" Opacity="1.0" Fill="{Binding #ImageColorViewOriginPoint.Color, ConverterParameter={x:Static Brushes.Transparent}, Converter={StaticResource ColorToBrushConverter}}" />
141+
<Rectangle Canvas.Left="0" Canvas.Top="0" Width="1" Height="1" Opacity="1.0" Fill="{Binding #ImageColorViewOriginPoint.Color, ConverterParameter={x:Static Brushes.Transparent}, Converter={StaticResource ColorToBrushConverter}}" />
142142
</Canvas>
143143
</paz:ZoomBorder>
144144
<TextBlock HorizontalAlignment="Center" Text="{Binding #ZoomBorder.ZoomX, StringFormat='Zoom: {0:F2}x | \'R\' to reset'}"></TextBlock>

0 commit comments

Comments
 (0)