Skip to content

Commit

Permalink
Merge pull request #583 from PixiEditor/fixes
Browse files Browse the repository at this point in the history
Fixes
  • Loading branch information
flabbet committed Dec 4, 2023
2 parents 5db10cb + e6593ad commit a31173b
Show file tree
Hide file tree
Showing 26 changed files with 116 additions and 58 deletions.
2 changes: 1 addition & 1 deletion src/ChunkyImageLib/DataHolders/AffectedArea.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ public struct AffectedArea
public HashSet<VecI> Chunks { get; set; }

/// <summary>
/// A rectangle in global full-scale coordinat
/// A rectangle in global full-scale coordinates
/// </summary>
public RectI? GlobalArea { get; set; }

Expand Down
6 changes: 3 additions & 3 deletions src/ChunkyImageLib/DataHolders/ColorBounds.cs
Original file line number Diff line number Diff line change
Expand Up @@ -65,10 +65,10 @@ public unsafe bool IsWithinBounds(Half* pixel)

public bool IsWithinBounds(Color toCompare)
{
float r = toCompare.R / 255f;
float g = toCompare.G / 255f;
float b = toCompare.B / 255f;
float a = toCompare.A / 255f;
float r = (toCompare.R / 255f) * a;
float g = (toCompare.G / 255f) * a;
float b = (toCompare.B / 255f) * a;

if (r < LowerR || r > UpperR)
return false;
Expand Down
2 changes: 1 addition & 1 deletion src/ChunkyImageLib/Operations/OperationHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -234,7 +234,7 @@ public static HashSet<VecI> FindChunksFullyInsideQuadrilateral(ShapeCorners corn

public static HashSet<VecI> FindChunksTouchingRectangle(RectI rect, int chunkSize)
{
if (rect.Width > chunkSize * 40 * 20 || rect.Height > chunkSize * 40 * 20)
if (rect.Width > chunkSize * 40 * 20 || rect.Height > chunkSize * 40 * 20 || rect.IsZeroOrNegativeArea)
return new HashSet<VecI>();

VecI min = GetChunkPos(rect.TopLeft, chunkSize);
Expand Down
2 changes: 2 additions & 0 deletions src/ChunkyImageLib/Surface.cs
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,8 @@ public static Surface Load(string path)
public static Surface Load(byte[] encoded)
{
using var image = Image.FromEncodedData(encoded);
if (image is null)
throw new ArgumentException($"The passed byte array does not contain a valid image");

var surface = new Surface(new VecI(image.Width, image.Height));
surface.DrawingSurface.Canvas.DrawImage(image, 0, 0);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ public static Dictionary<VecI, Chunk> FloodFill(
static (EmptyChunk _) => Colors.Transparent
);

if ((colorToReplace.A == 0 && drawingColor.A == 0) || colorToReplace == drawingColor)
if ((drawingColor.A == 0) || colorToReplace == drawingColor)
return new();

RectI globalSelectionBounds = (RectI?)selection?.TightBounds ?? new RectI(VecI.Zero, document.Size);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -177,9 +177,13 @@ public override void Dispose()
{
if (hasEnqueudImages)
throw new InvalidOperationException("Attempted to dispose the change while it's internally stored image is still used enqueued in some ChunkyImage. Most likely someone tried to dispose a change after ApplyTemporarily was called but before the subsequent call to Apply. Don't do that.");
foreach (var (_, (image, _)) in images!)

if (images is not null)
{
image.Dispose();
foreach (var (_, (image, _)) in images)
{
image.Dispose();
}
}

if (savedChunks is not null)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ public override OneOf<None, IChangeInfo, List<IChangeInfo>> Apply(Document targe
}
});

if (!bounds.HasValue)
if (!bounds.HasValue || bounds.Value.IsZeroOrNegativeArea || bounds.Value == new RectI(VecI.Zero, target.Size))
{
ignoreInUndo = true;
return new None();
Expand All @@ -48,12 +48,6 @@ public override OneOf<None, IChangeInfo, List<IChangeInfo>> Apply(Document targe
Resize(member.Mask, member.GuidValue, newBounds.Size, -newBounds.Pos, deletedMaskChunks);
});

if (newBounds.IsZeroOrNegativeArea)
{
ignoreInUndo = true;
return new None();
}

ignoreInUndo = false;
return new Size_ChangeInfo(newBounds.Size, target.VerticalSymmetryAxisX, target.HorizontalSymmetryAxisY);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ public override bool InitializeAndValidate(Document target)
return true;
}

/// <summary>
/// Notice: this commits image changes, you won't have a chance to revert or set ignoreInUndo to true
/// </summary>
protected virtual void Resize(ChunkyImage img, Guid memberGuid, VecI size, VecI offset, Dictionary<Guid, CommittedChunkStorage> deletedChunksDict)
{
img.EnqueueResize(size);
Expand All @@ -31,9 +34,6 @@ protected virtual void Resize(ChunkyImage img, Guid memberGuid, VecI size, VecI

public override OneOf<None, IChangeInfo, List<IChangeInfo>> Revert(Document target)
{
if (target.Size == _originalSize)
return new None();

target.Size = _originalSize;
target.ForEveryMember((member) =>
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ public override bool InitializeAndValidate(Document target)
{
if (!target.TryFindMember<Layer>(layerGuid, out Layer? layer))
return false;
duplicateGuid = Guid.NewGuid();
return true;
}

Expand All @@ -23,7 +24,6 @@ public override OneOf<None, IChangeInfo, List<IChangeInfo>> Apply(Document targe
(Layer existingLayer, Folder parent) = ((Layer, Folder))target.FindChildAndParentOrThrow(layerGuid);

Layer clone = existingLayer.Clone();
duplicateGuid = Guid.NewGuid();
clone.GuidValue = duplicateGuid;

int index = parent.Children.IndexOf(existingLayer);
Expand Down
11 changes: 6 additions & 5 deletions src/PixiEditor.ChangeableDocument/Rendering/ChunkRenderer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -247,22 +247,23 @@ private static OneOf<Chunk, EmptyChunk> MergeFolderContents(
OneOf<All, HashSet<Guid>> membersToMerge,
RectI? transformedClippingRect)
{
if (folder.Children.Count == 0)
var folderChildren = folder.Children;
if (folderChildren.Count == 0)
return new EmptyChunk();

Chunk targetChunk = Chunk.Create(resolution);
targetChunk.Surface.DrawingSurface.Canvas.Clear();

OneOf<FilledChunk, EmptyChunk, Chunk> clippingChunk = new FilledChunk();
for (int i = 0; i < folder.Children.Count; i++)
for (int i = 0; i < folderChildren.Count; i++)
{
var child = folder.Children[i];
var child = folderChildren[i];

// next child might use clip to member below in which case we need to save the clip image
bool needToSaveClippingChunk =
i < folder.Children.Count - 1 &&
i < folderChildren.Count - 1 &&
!child.ClipToMemberBelow &&
folder.Children[i + 1].ClipToMemberBelow;
folderChildren[i + 1].ClipToMemberBelow;

// if the current member doesn't need a clip, get rid of it
if (!child.ClipToMemberBelow && !clippingChunk.IsT0)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ public interface IImageImplementation
{
public Image Snapshot(DrawingSurface drawingSurface);
public void DisposeImage(Image image);
public Image FromEncodedData(string path);
public Image FromEncodedData(byte[] dataBytes);
public Image? FromEncodedData(string path);
public Image? FromEncodedData(byte[] dataBytes);
public void GetColorShifts(ref int platformColorAlphaShift, ref int platformColorRedShift, ref int platformColorGreenShift, ref int platformColorBlueShift);
public ImgData Encode(Image image);
public int GetWidth(IntPtr objectPointer);
Expand Down
2 changes: 1 addition & 1 deletion src/PixiEditor.DrawingApi.Core/Numerics/RectI.cs
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ public VecI Size
public int Width { readonly get => right - left; set => right = left + value; }
public int Height { readonly get => bottom - top; set => bottom = top + value; }
public readonly bool IsZeroArea => left == right || top == bottom;
public readonly bool IsZeroOrNegativeArea => left >= right || top >= bottom;
public readonly bool IsZeroOrNegativeArea => left >= right || top >= bottom || Width < 0 || Height < 0; // checking Width and Height too as they can overflow in large rectangles

public RectI()
{
Expand Down
4 changes: 2 additions & 2 deletions src/PixiEditor.DrawingApi.Core/Surface/ImageData/Image.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,12 @@ public override void Dispose()
DrawingBackendApi.Current.ImageImplementation.DisposeImage(this);
}

public static Image FromEncodedData(string path)
public static Image? FromEncodedData(string path)
{
return DrawingBackendApi.Current.ImageImplementation.FromEncodedData(path);
}

public static Image FromEncodedData(byte[] dataBytes)
public static Image? FromEncodedData(byte[] dataBytes)
{
return DrawingBackendApi.Current.ImageImplementation.FromEncodedData(dataBytes);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,11 @@ public Image Snapshot(DrawingSurface drawingSurface)
return new Image(snapshot.Handle);
}

public Image FromEncodedData(byte[] dataBytes)
public Image? FromEncodedData(byte[] dataBytes)
{
SKImage img = SKImage.FromEncodedData(dataBytes);
if (img is null)
return null;
ManagedInstances[img.Handle] = img;

return new Image(img.Handle);
Expand All @@ -45,9 +47,11 @@ public void DisposeImage(Image image)
ManagedInstances.TryRemove(image.ObjectPointer, out _);
}

public Image FromEncodedData(string path)
public Image? FromEncodedData(string path)
{
var nativeImg = SKImage.FromEncodedData(path);
if (nativeImg is null)
return null;
ManagedInstances[nativeImg.Handle] = nativeImg;
return new Image(nativeImg.Handle);
}
Expand Down
2 changes: 1 addition & 1 deletion src/PixiEditor.Zoombox/Operations/ZoomDragOperation.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ public void Update(MouseEventArgs e)
double deltaX = curScreenPos.X - screenScaleOrigin.X;
double deltaPower = deltaX / 10.0;

parent.Scale = originalScale * Math.Pow(Zoombox.ScaleFactor, deltaPower);
parent.Scale = Math.Clamp(originalScale * Math.Pow(Zoombox.ScaleFactor, deltaPower), parent.MinScale, Zoombox.MaxScale);

VecD shiftedOrigin = parent.ToZoomboxSpace(screenScaleOrigin);
parent.Center += scaleOrigin - shiftedOrigin;
Expand Down
2 changes: 1 addition & 1 deletion src/PixiEditor.Zoombox/Zoombox.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -284,7 +284,7 @@ public void CenterContent(VecD newSize)
Angle = 0;
FlipX = false;
FlipY = false;
Scale = 1 / scaleFactor;
Scale = Math.Clamp(1 / scaleFactor, MinScale, MaxScale);
Center = newSize / 2;
}

Expand Down
9 changes: 7 additions & 2 deletions src/PixiEditor/Helpers/Converters/ReciprocalConverter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,13 @@ public override object Convert(object value, Type targetType, object parameter,
{
if (value is not double num)
return DependencyProperty.UnsetValue;

double result;
if (parameter is not double mult)
return 1 / num;
return mult / num;
result = 1 / num;
else
result = mult / num;

return Math.Clamp(result, 1e-15, 1e15);
}
}
6 changes: 5 additions & 1 deletion src/PixiEditor/Helpers/ProcessHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using System.IO;
using System.Security.Principal;
using System.Windows.Input;
using PixiEditor.Exceptions;

namespace PixiEditor.Helpers;

Expand Down Expand Up @@ -32,10 +33,13 @@ public static void OpenInExplorer(string path)
{
string fixedPath = Path.GetFullPath(path);
var process = Process.Start("explorer.exe", $"/select,\"{fixedPath}\"");

// Explorer might need a second to show up
process.WaitForExit(500);
}
catch (Win32Exception)
{
throw new RecoverableException("ERROR_FAILED_TO_OPEN_EXPLORER");
}
finally
{
Mouse.OverrideCursor = null;
Expand Down
9 changes: 5 additions & 4 deletions src/PixiEditor/Models/Controllers/MouseUpdateController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,16 +21,17 @@ public MouseUpdateController(UIElement uiElement, MouseEventHandler onMouseMove)
element = uiElement;

_timer = new System.Timers.Timer(MouseUpdateIntervalMs);
_timer.AutoReset = true;
_timer.Elapsed += TimerOnElapsed;

element.MouseMove += OnMouseMove;
}

private void TimerOnElapsed(object sender, ElapsedEventArgs e)
{
_timer.Stop();
element.MouseMove += OnMouseMove;
Application.Current?.Dispatcher.Invoke(() =>
{
element.MouseMove += OnMouseMove;
});
}

private void OnMouseMove(object sender, MouseEventArgs e)
Expand All @@ -42,7 +43,7 @@ private void OnMouseMove(object sender, MouseEventArgs e)

public void Dispose()
{
_timer.Dispose();
element.MouseMove -= OnMouseMove;
_timer.Dispose();
}
}
4 changes: 3 additions & 1 deletion src/PixiEditor/Models/DocumentModels/DocumentUpdater.cs
Original file line number Diff line number Diff line change
Expand Up @@ -190,12 +190,14 @@ private void ProcessAddSoftSelectedMember(AddSoftSelectedMember_PassthroughActio

private void ProcessSetSelectedMember(SetSelectedMember_PassthroughAction info)
{
StructureMemberViewModel? member = doc.StructureHelper.Find(info.GuidValue);
if (member is null || member.Selection == StructureMemberSelectionType.Hard)
return;
if (doc.SelectedStructureMember is { } oldMember)
{
oldMember.Selection = StructureMemberSelectionType.None;
oldMember.RaisePropertyChanged(nameof(oldMember.Selection));
}
StructureMemberViewModel? member = doc.StructureHelper.FindOrThrow(info.GuidValue);
member.Selection = StructureMemberSelectionType.Hard;
member.RaisePropertyChanged(nameof(member.Selection));
doc.InternalSetSelectedMember(member);
Expand Down
9 changes: 8 additions & 1 deletion src/PixiEditor/Models/IO/Exporter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,14 @@ public static SaveResult TrySave(DocumentViewModel document, string pathWithExte
}
else
{
Parser.PixiParser.Serialize(document.ToSerializable(), pathWithExtension);
try
{
Parser.PixiParser.Serialize(document.ToSerializable(), pathWithExtension);
}
catch (UnauthorizedAccessException)
{
return SaveResult.SecurityError;
}
}

return SaveResult.Success;
Expand Down
17 changes: 14 additions & 3 deletions src/PixiEditor/Models/IO/Importer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,19 @@ internal class Importer : NotifyableObject
/// <returns>WriteableBitmap of imported image.</returns>
public static Surface? ImportImage(string path, VecI size)
{
if (!Path.Exists(path)) return null;
Surface original = Surface.Load(path);
if (!Path.Exists(path))
throw new MissingFileException();

Surface original;
try
{
original = Surface.Load(path);
}
catch (Exception e) when (e is ArgumentException or FileNotFoundException)
{
throw new CorruptedFileException(e);
}

if (original.Size == size || size == VecI.NegativeOne)
{
return original;
Expand Down Expand Up @@ -95,7 +106,7 @@ public static DocumentViewModel ImportDocument(string path, bool associatePath =

return doc;
}
catch (InvalidFileException e)
catch (Exception e)
{
throw new CorruptedFileException("FAILED_TO_OPEN_FILE", e);
}
Expand Down
2 changes: 1 addition & 1 deletion src/PixiEditor/Models/Rendering/MemberPreviewUpdater.cs
Original file line number Diff line number Diff line change
Expand Up @@ -563,7 +563,7 @@ private void RenderMaskPreviews(
continue;

if (tightBounds is null)
tightBounds = lastMainPreviewTightBounds[guid];
tightBounds = lastMaskPreviewTightBounds[guid];

var previewSize = StructureMemberViewModel.CalculatePreviewSize(tightBounds.Value.Size);
float scaling = (float)previewSize.X / tightBounds.Value.Width;
Expand Down
Loading

0 comments on commit a31173b

Please sign in to comment.