Skip to content

Commit af438b6

Browse files
authored
Add "crop images" button and functionality (#172)
resolves #171
1 parent 91d4540 commit af438b6

File tree

2 files changed

+74
-2
lines changed

2 files changed

+74
-2
lines changed

Gui/ViewModels/SubObjectTypes/ImageTableViewModel.cs

Lines changed: 68 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
using ReactiveUI.Fody.Helpers;
1111
using SixLabors.ImageSharp;
1212
using SixLabors.ImageSharp.PixelFormats;
13+
using SixLabors.ImageSharp.Processing;
1314
using System;
1415
using System.Collections.Generic;
1516
using System.Collections.ObjectModel;
@@ -94,6 +95,9 @@ public class ImageTableViewModel : ReactiveObject, IExtraContentViewModel
9495
[Reactive]
9596
public ICommand ExportImagesCommand { get; set; }
9697

98+
[Reactive]
99+
public ICommand CropAllImagesCommand { get; set; }
100+
97101
[Reactive]
98102
public int Zoom { get; set; } = 1;
99103

@@ -142,6 +146,7 @@ public ImageTableViewModel(IHasG1Elements g1ElementProvider, IImageTableNameProv
142146
ImportImagesCommand = ReactiveCommand.Create(ImportImages);
143147
ExportImagesCommand = ReactiveCommand.Create(ExportImages);
144148
ReplaceImageCommand = ReactiveCommand.Create(ReplaceImage);
149+
CropAllImagesCommand = ReactiveCommand.Create(CropAllImages);
145150

146151
CreateSelectionModel();
147152

@@ -340,6 +345,62 @@ public async Task ExportImages()
340345
}
341346
}
342347

348+
public void CropAllImages()
349+
{
350+
for (var i = 0; i < Images.Count; ++i)
351+
{
352+
var image = Images[i];
353+
354+
var cropRegion = FindCropRegion(image);
355+
356+
if (cropRegion.Width <= 0 || cropRegion.Height <= 0)
357+
{
358+
image.Mutate(i => i.Crop(new Rectangle(0, 0, 1, 1)));
359+
UpdateImage(image, i, 0, 0);
360+
}
361+
else
362+
{
363+
image.Mutate(i => i.Crop(cropRegion));
364+
var currG1 = G1Provider.G1Elements[i];
365+
366+
// set to bitmaps
367+
UpdateImage(image, i, (short)(currG1.XOffset + cropRegion.Left), (short)(currG1.YOffset + cropRegion.Top));
368+
}
369+
}
370+
371+
this.RaisePropertyChanged(nameof(Bitmaps));
372+
this.RaisePropertyChanged(nameof(SelectedG1Element));
373+
}
374+
375+
static Rectangle FindCropRegion(Image<Rgba32> image)
376+
{
377+
var minX = image.Width;
378+
var maxX = 0;
379+
var minY = image.Height;
380+
var maxY = 0;
381+
382+
for (var y = 0; y < image.Height; y++)
383+
{
384+
for (var x = 0; x < image.Width; x++)
385+
{
386+
var pixel = image[x, y];
387+
388+
if (pixel.A > 0)
389+
{
390+
minX = Math.Min(minX, x);
391+
maxX = Math.Max(maxX, x);
392+
minY = Math.Min(minY, y);
393+
maxY = Math.Max(maxY, y);
394+
}
395+
}
396+
}
397+
398+
// Calculate the crop area. Ensure it is within image bounds.
399+
var width = Math.Max(0, Math.Min(maxX - minX + 1, image.Width - minX));
400+
var height = Math.Max(0, Math.Min(maxY - minY + 1, image.Height - minY));
401+
return new Rectangle(minX, minY, width, height);
402+
}
403+
343404
public async Task ReplaceImage()
344405
{
345406
if (SelectedImageIndex == -1)
@@ -368,6 +429,11 @@ public async Task ReplaceImage()
368429
}
369430

370431
void UpdateImage(Image<Rgba32> img, int index, SpriteOffset? offset = null)
432+
{
433+
UpdateImage(img, index, offset?.X, offset?.Y);
434+
}
435+
436+
void UpdateImage(Image<Rgba32> img, int index, short? xOffset, short? yOffset)
371437
{
372438
if (index == -1)
373439
{
@@ -381,8 +447,8 @@ void UpdateImage(Image<Rgba32> img, int index, SpriteOffset? offset = null)
381447
Height = (int16_t)img.Height,
382448
Flags = currG1.Flags,
383449
ImageData = PaletteMap.ConvertRgba32ImageToG1Data(img, currG1.Flags),
384-
XOffset = offset?.X ?? currG1.XOffset,
385-
YOffset = offset?.Y ?? currG1.YOffset,
450+
XOffset = xOffset ?? currG1.XOffset,
451+
YOffset = yOffset ?? currG1.YOffset,
386452
};
387453
G1Provider.G1Elements[index] = currG1;
388454
Images[index] = img;

Gui/Views/ImageTableView.axaml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,12 @@
4040
</Flyout>
4141
</Button.Flyout>
4242
</Button>
43+
<Button Command="{Binding CropAllImagesCommand}" HorizontalAlignment="Stretch" Margin="2" Padding="2" ToolTip.Tip="Crops all images and adjusts offsets">
44+
<DockPanel>
45+
<materialIcons:MaterialIcon Kind="Crop" Width="24" Height="24" Margin="2" />
46+
<TextBlock HorizontalAlignment="Stretch" VerticalAlignment="Center" Margin="4">Crop all images</TextBlock>
47+
</DockPanel>
48+
</Button>
4349
<!--<ComboBox ItemsSource="{Binding ColourSwatchesArr}" SelectedItem="{Binding SelectedColourSwatch}" HorizontalAlignment="Stretch" VerticalAlignment="Center" />-->
4450
</StackPanel>
4551
<Grid ColumnDefinitions="*, Auto, 384">

0 commit comments

Comments
 (0)