Improve crop editor and copy publish output to dist
Add resize handles, zoom, view brightness, and a multi-frame still strip. Keep the crop box on mouse-up, and copy AmiReel.exe to dist.
This commit is contained in:
@@ -6,6 +6,21 @@ public readonly record struct PixelInsets(int Left, int Right, int Top, int Bott
|
||||
public bool IsEmpty => Left == 0 && Right == 0 && Top == 0 && Bottom == 0;
|
||||
}
|
||||
|
||||
/// <summary>Which part of an existing crop rectangle a pointer is on.</summary>
|
||||
public enum CropHit
|
||||
{
|
||||
None,
|
||||
Move,
|
||||
North,
|
||||
South,
|
||||
East,
|
||||
West,
|
||||
NorthWest,
|
||||
NorthEast,
|
||||
SouthWest,
|
||||
SouthEast,
|
||||
}
|
||||
|
||||
/// <summary>Maps a dragged display rectangle onto source-pixel crop insets.</summary>
|
||||
public static class SourceCropSelection
|
||||
{
|
||||
@@ -58,15 +73,14 @@ public static class SourceCropSelection
|
||||
double scaleY = pixelHeight / displayHeight;
|
||||
int left = ToEvenPixel(x * scaleX, pixelWidth - MinimumSize);
|
||||
int top = ToEvenPixel(y * scaleY, pixelHeight - MinimumSize);
|
||||
int right = ToEvenPixel((displayWidth - x - width) * scaleX, pixelWidth - MinimumSize - left);
|
||||
int bottom = ToEvenPixel((displayHeight - y - height) * scaleY, pixelHeight - MinimumSize - top);
|
||||
int cropWidth = ToEvenPixel(width * scaleX, pixelWidth - left);
|
||||
int cropHeight = ToEvenPixel(height * scaleY, pixelHeight - top);
|
||||
if (cropWidth < MinimumSize)
|
||||
cropWidth = Math.Min(MinimumSize, pixelWidth - left);
|
||||
if (cropHeight < MinimumSize)
|
||||
cropHeight = Math.Min(MinimumSize, pixelHeight - top);
|
||||
|
||||
if (pixelWidth - left - right < MinimumSize)
|
||||
right = Math.Max(0, pixelWidth - left - MinimumSize);
|
||||
if (pixelHeight - top - bottom < MinimumSize)
|
||||
bottom = Math.Max(0, pixelHeight - top - MinimumSize);
|
||||
|
||||
return new PixelInsets(left, right, top, bottom);
|
||||
return new PixelInsets(left, pixelWidth - left - cropWidth, top, pixelHeight - top - cropHeight);
|
||||
}
|
||||
|
||||
public static (double X, double Y, double Width, double Height) ToDisplayRect(
|
||||
@@ -87,6 +101,102 @@ public static class SourceCropSelection
|
||||
public static (double X, double Y) ClampToDisplay(double x, double y, double displayWidth, double displayHeight) =>
|
||||
(Math.Clamp(x, 0, Math.Max(0, displayWidth)), Math.Clamp(y, 0, Math.Max(0, displayHeight)));
|
||||
|
||||
public static CropHit HitTest(
|
||||
double rectX, double rectY, double rectWidth, double rectHeight, double pointerX, double pointerY, double handleSize)
|
||||
{
|
||||
if (rectWidth <= 0 || rectHeight <= 0 || handleSize < 0)
|
||||
return CropHit.None;
|
||||
|
||||
bool nearLeft = Math.Abs(pointerX - rectX) <= handleSize;
|
||||
bool nearRight = Math.Abs(pointerX - (rectX + rectWidth)) <= handleSize;
|
||||
bool nearTop = Math.Abs(pointerY - rectY) <= handleSize;
|
||||
bool nearBottom = Math.Abs(pointerY - (rectY + rectHeight)) <= handleSize;
|
||||
bool alongX = pointerX >= rectX - handleSize && pointerX <= rectX + rectWidth + handleSize;
|
||||
bool alongY = pointerY >= rectY - handleSize && pointerY <= rectY + rectHeight + handleSize;
|
||||
|
||||
if (nearTop && nearLeft)
|
||||
return CropHit.NorthWest;
|
||||
if (nearTop && nearRight)
|
||||
return CropHit.NorthEast;
|
||||
if (nearBottom && nearLeft)
|
||||
return CropHit.SouthWest;
|
||||
if (nearBottom && nearRight)
|
||||
return CropHit.SouthEast;
|
||||
if (nearTop && alongX)
|
||||
return CropHit.North;
|
||||
if (nearBottom && alongX)
|
||||
return CropHit.South;
|
||||
if (nearLeft && alongY)
|
||||
return CropHit.West;
|
||||
if (nearRight && alongY)
|
||||
return CropHit.East;
|
||||
if (pointerX >= rectX && pointerX <= rectX + rectWidth && pointerY >= rectY && pointerY <= rectY + rectHeight)
|
||||
return CropHit.Move;
|
||||
return CropHit.None;
|
||||
}
|
||||
|
||||
public static (double X, double Y, double Width, double Height) AdjustRect(
|
||||
double x,
|
||||
double y,
|
||||
double width,
|
||||
double height,
|
||||
CropHit hit,
|
||||
double deltaX,
|
||||
double deltaY,
|
||||
double displayWidth,
|
||||
double displayHeight)
|
||||
{
|
||||
const double minSize = 8;
|
||||
double left = x;
|
||||
double top = y;
|
||||
double right = x + width;
|
||||
double bottom = y + height;
|
||||
|
||||
if (hit == CropHit.Move)
|
||||
{
|
||||
left = Math.Clamp(left + deltaX, 0, Math.Max(0, displayWidth - width));
|
||||
top = Math.Clamp(top + deltaY, 0, Math.Max(0, displayHeight - height));
|
||||
return (left, top, width, height);
|
||||
}
|
||||
|
||||
if (hit is CropHit.West or CropHit.NorthWest or CropHit.SouthWest)
|
||||
left = Math.Clamp(left + deltaX, 0, right - minSize);
|
||||
if (hit is CropHit.East or CropHit.NorthEast or CropHit.SouthEast)
|
||||
right = Math.Clamp(right + deltaX, left + minSize, displayWidth);
|
||||
if (hit is CropHit.North or CropHit.NorthWest or CropHit.NorthEast)
|
||||
top = Math.Clamp(top + deltaY, 0, bottom - minSize);
|
||||
if (hit is CropHit.South or CropHit.SouthWest or CropHit.SouthEast)
|
||||
bottom = Math.Clamp(bottom + deltaY, top + minSize, displayHeight);
|
||||
|
||||
return (left, top, Math.Max(minSize, right - left), Math.Max(minSize, bottom - top));
|
||||
}
|
||||
|
||||
public static PixelInsets Nudge(PixelInsets insets, int pixelWidth, int pixelHeight, int deltaX, int deltaY)
|
||||
{
|
||||
int width = pixelWidth - insets.Left - insets.Right;
|
||||
int height = pixelHeight - insets.Top - insets.Bottom;
|
||||
if (width < MinimumSize || height < MinimumSize)
|
||||
return insets;
|
||||
|
||||
int left = ToEvenPixel(insets.Left + deltaX, pixelWidth - width);
|
||||
int top = ToEvenPixel(insets.Top + deltaY, pixelHeight - height);
|
||||
return new PixelInsets(left, pixelWidth - left - width, top, pixelHeight - top - height);
|
||||
}
|
||||
|
||||
public static PixelInsets NudgeEdge(
|
||||
PixelInsets insets, int pixelWidth, int pixelHeight, int dLeft, int dTop, int dRight, int dBottom)
|
||||
{
|
||||
int left = ToEvenPixel(insets.Left + dLeft, pixelWidth - MinimumSize);
|
||||
int top = ToEvenPixel(insets.Top + dTop, pixelHeight - MinimumSize);
|
||||
int right = ToEvenPixel(insets.Right + dRight, pixelWidth - MinimumSize - left);
|
||||
int bottom = ToEvenPixel(insets.Bottom + dBottom, pixelHeight - MinimumSize - top);
|
||||
if (pixelWidth - left - right < MinimumSize)
|
||||
right = Math.Max(0, pixelWidth - left - MinimumSize);
|
||||
if (pixelHeight - top - bottom < MinimumSize)
|
||||
bottom = Math.Max(0, pixelHeight - top - MinimumSize);
|
||||
return new PixelInsets(left, right, top, bottom);
|
||||
}
|
||||
|
||||
private static void Normalize(ref double x, ref double y, ref double width, ref double height)
|
||||
{
|
||||
if (width < 0)
|
||||
|
||||
Reference in New Issue
Block a user