- Services/PdfRedactText.cs: strip text whose origin falls inside a CoverAnnotation from the page content stream at save time, hooked into PdfBurn.DrawAnnotationsIntoDoc. Fixes edited values staying recoverable by text extraction. - Themes/MMD.xaml replaces all thirteen themes; picker and accent strip removed; no dark mode. - Rename KillerPDF -> MMD PDF across code, resources, packaging and locale strings; new icon. - Remove the upstream author credit and the in-app install button.
115 lines
4.0 KiB
C#
115 lines
4.0 KiB
C#
using System.Windows;
|
|
using MmdPdf.Services;
|
|
using Xunit;
|
|
|
|
namespace MmdPdf.Tests;
|
|
|
|
// #169: rotating a page must keep its overlay annotations and turn them with the page.
|
|
// The mapping runs in render-dim space; a +90 turn takes frame (W, H) to (H, W), so
|
|
// round-trip tests swap the frame between passes exactly as the live reload does.
|
|
public sealed class AnnotationRotateTests
|
|
{
|
|
private const double W = 800, H = 600;
|
|
|
|
[Fact]
|
|
public void Highlight_QuarterTurn_TurnsWithTheContent()
|
|
{
|
|
var ha = new HighlightAnnotation { Bounds = new Rect(10, 20, 100, 40) };
|
|
AnnotationRotate.Remap([ha], 90, W, H);
|
|
|
|
// Corners (10,20)-(110,60) map to (580,10)-(540,110): the region swaps its axes.
|
|
Assert.Equal(540, ha.Bounds.X, 3);
|
|
Assert.Equal(10, ha.Bounds.Y, 3);
|
|
Assert.Equal(40, ha.Bounds.Width, 3);
|
|
Assert.Equal(100, ha.Bounds.Height, 3);
|
|
}
|
|
|
|
[Fact]
|
|
public void Highlight_FourQuarterTurns_IsIdentity()
|
|
{
|
|
var start = new Rect(10, 20, 100, 40);
|
|
var ha = new HighlightAnnotation { Bounds = start };
|
|
AnnotationRotate.Remap([ha], 90, W, H);
|
|
AnnotationRotate.Remap([ha], 90, H, W);
|
|
AnnotationRotate.Remap([ha], 90, W, H);
|
|
AnnotationRotate.Remap([ha], 90, H, W);
|
|
Assert.Equal(start, ha.Bounds);
|
|
}
|
|
|
|
[Fact]
|
|
public void Highlight_TurnThenCounterTurn_IsIdentity()
|
|
{
|
|
var start = new Rect(33, 44, 55, 66);
|
|
var ha = new HighlightAnnotation { Bounds = start };
|
|
AnnotationRotate.Remap([ha], 90, W, H);
|
|
AnnotationRotate.Remap([ha], -90, H, W);
|
|
Assert.Equal(start, ha.Bounds);
|
|
}
|
|
|
|
[Fact]
|
|
public void Highlight_TwoQuarterTurns_MatchHalfTurn()
|
|
{
|
|
var a = new HighlightAnnotation { Bounds = new Rect(10, 20, 100, 40) };
|
|
var b = new HighlightAnnotation { Bounds = new Rect(10, 20, 100, 40) };
|
|
AnnotationRotate.Remap([a], 90, W, H);
|
|
AnnotationRotate.Remap([a], 90, H, W);
|
|
AnnotationRotate.Remap([b], 180, W, H);
|
|
Assert.Equal(b.Bounds, a.Bounds);
|
|
}
|
|
|
|
[Fact]
|
|
public void TextBox_KeepsSize_CenterFollowsThePage()
|
|
{
|
|
var ta = new TextAnnotation { Position = new Point(10, 70), Width = 100, Height = 40 };
|
|
AnnotationRotate.Remap([ta], 90, W, H);
|
|
|
|
// Center (60,90) maps to (510,60); the box keeps 100x40 around it.
|
|
Assert.Equal(460, ta.Position.X, 3);
|
|
Assert.Equal(40, ta.Position.Y, 3);
|
|
Assert.Equal(100, ta.Width, 3);
|
|
Assert.Equal(40, ta.Height, 3);
|
|
}
|
|
|
|
[Fact]
|
|
public void UprightTextBoxNearLongEdge_IsClampedInsideRotatedPage()
|
|
{
|
|
// Fully inside the old 800x600 page. Keeping this tall box upright after a clockwise turn
|
|
// would put its bottom at 870 on the new 600x800 page unless the remap clamps it.
|
|
var ta = new TextAnnotation { Position = new Point(750, 100), Width = 40, Height = 200 };
|
|
AnnotationRotate.Remap([ta], 90, W, H);
|
|
|
|
Assert.Equal(380, ta.Position.X, 3);
|
|
Assert.Equal(600, ta.Position.Y, 3);
|
|
Assert.InRange(ta.Position.X + ta.Width, 0, H);
|
|
Assert.InRange(ta.Position.Y + ta.Height, 0, W);
|
|
}
|
|
|
|
[Fact]
|
|
public void UprightPlacedItemNearLongEdge_IsClampedInsideRotatedPage()
|
|
{
|
|
var image = new ImageAnnotation
|
|
{
|
|
Position = new Point(750, 100),
|
|
SourceWidth = 40,
|
|
SourceHeight = 200,
|
|
Scale = 1
|
|
};
|
|
|
|
AnnotationRotate.Remap([image], 90, W, H);
|
|
|
|
Assert.Equal(380, image.Position.X, 3);
|
|
Assert.Equal(600, image.Position.Y, 3);
|
|
Assert.InRange(image.Position.X + image.SourceWidth * image.Scale, 0, H);
|
|
Assert.InRange(image.Position.Y + image.SourceHeight * image.Scale, 0, W);
|
|
}
|
|
|
|
[Fact]
|
|
public void InkPoints_MapPerPoint()
|
|
{
|
|
var ia = new InkAnnotation { Points = [new Point(0, 0), new Point(100, 50)] };
|
|
AnnotationRotate.Remap([ia], 90, W, H);
|
|
Assert.Equal(new Point(H, 0), ia.Points[0]);
|
|
Assert.Equal(new Point(H - 50, 100), ia.Points[1]);
|
|
}
|
|
}
|