mirror of
https://github.com/mozilla/pdf.js.git
synced 2025-04-20 15:18:08 +02:00
Rotate annotations based on the MK::R value (bug 1675139)
- it aims to fix: https://bugzilla.mozilla.org/show_bug.cgi?id=1675139; - An annotation can be rotated (counterclockwise); - the rotation can be set in using JS.
This commit is contained in:
parent
54777b42c2
commit
cdc58b7a52
10 changed files with 562 additions and 78 deletions
|
@ -1401,4 +1401,47 @@ describe("Interaction", () => {
|
|||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe("in bug1675139.pdf", () => {
|
||||
let pages;
|
||||
|
||||
beforeAll(async () => {
|
||||
pages = await loadAndWait("bug1675139.pdf", getSelector("48R"));
|
||||
});
|
||||
|
||||
afterAll(async () => {
|
||||
await closePages(pages);
|
||||
});
|
||||
|
||||
it("must check that data-annotation-rotation is correc", async () => {
|
||||
await Promise.all(
|
||||
pages.map(async ([browserName, page]) => {
|
||||
await page.waitForFunction(
|
||||
"window.PDFViewerApplication.scriptingReady === true"
|
||||
);
|
||||
|
||||
let base = 0;
|
||||
|
||||
while (base !== 360) {
|
||||
for (const [ref, angle] of [
|
||||
[47, 0],
|
||||
[42, 90],
|
||||
[45, 180],
|
||||
[46, 270],
|
||||
]) {
|
||||
const rotation = await page.$eval(
|
||||
`[data-annotation-id='${ref}R']`,
|
||||
el => parseInt(el.getAttribute("data-annotation-rotation") || 0)
|
||||
);
|
||||
expect(rotation)
|
||||
.withContext(`In ${browserName}`)
|
||||
.toEqual((360 + ((360 - (base + angle)) % 360)) % 360);
|
||||
}
|
||||
base += 90;
|
||||
await page.click(getSelector("48R"));
|
||||
}
|
||||
})
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
1
test/pdfs/.gitignore
vendored
1
test/pdfs/.gitignore
vendored
|
@ -528,3 +528,4 @@
|
|||
!bug1771477.pdf
|
||||
!bug1724918.pdf
|
||||
!issue15053.pdf
|
||||
!bug1675139.pdf
|
||||
|
|
BIN
test/pdfs/bug1675139.pdf
Executable file
BIN
test/pdfs/bug1675139.pdf
Executable file
Binary file not shown.
|
@ -6583,5 +6583,44 @@
|
|||
"rounds": 1,
|
||||
"type": "eq",
|
||||
"annotations": true
|
||||
},
|
||||
{ "id": "bug1675139",
|
||||
"file": "pdfs/bug1675139.pdf",
|
||||
"md5": "052c2c3dcc7ef4d4ac622282cb0fb17a",
|
||||
"rounds": 1,
|
||||
"type": "eq",
|
||||
"annotations": true
|
||||
},
|
||||
{ "id": "bug1675139-print",
|
||||
"file": "pdfs/bug1675139.pdf",
|
||||
"md5": "052c2c3dcc7ef4d4ac622282cb0fb17a",
|
||||
"rounds": 1,
|
||||
"type": "eq",
|
||||
"print": true,
|
||||
"annotationStorage": {
|
||||
"42R": {
|
||||
"value": "pi/2"
|
||||
},
|
||||
"46R": {
|
||||
"value": "3*pi/2",
|
||||
"rotation": 180
|
||||
},
|
||||
"47R": {
|
||||
"value": "0*pi/2"
|
||||
},
|
||||
"45R": {
|
||||
"value": "pi"
|
||||
},
|
||||
"55R": {
|
||||
"value": "C",
|
||||
"rotation": 90
|
||||
},
|
||||
"52R": {
|
||||
"value": "Yes"
|
||||
},
|
||||
"56R": {
|
||||
"rotation": 270
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
|
|
|
@ -2058,6 +2058,52 @@ describe("annotation", function () {
|
|||
);
|
||||
});
|
||||
|
||||
it("should save rotated text", async function () {
|
||||
const textWidgetRef = Ref.get(123, 0);
|
||||
const xref = new XRefMock([
|
||||
{ ref: textWidgetRef, data: textWidgetDict },
|
||||
helvRefObj,
|
||||
]);
|
||||
partialEvaluator.xref = xref;
|
||||
const task = new WorkerTask("test save");
|
||||
|
||||
const annotation = await AnnotationFactory.create(
|
||||
xref,
|
||||
textWidgetRef,
|
||||
pdfManagerMock,
|
||||
idFactoryMock
|
||||
);
|
||||
const annotationStorage = new Map();
|
||||
annotationStorage.set(annotation.data.id, {
|
||||
value: "hello world",
|
||||
rotation: 90,
|
||||
});
|
||||
|
||||
const data = await annotation.save(
|
||||
partialEvaluator,
|
||||
task,
|
||||
annotationStorage
|
||||
);
|
||||
expect(data.length).toEqual(2);
|
||||
const [oldData, newData] = data;
|
||||
expect(oldData.ref).toEqual(Ref.get(123, 0));
|
||||
expect(newData.ref).toEqual(Ref.get(2, 0));
|
||||
|
||||
oldData.data = oldData.data.replace(/\(D:\d+\)/, "(date)");
|
||||
expect(oldData.data).toEqual(
|
||||
"123 0 obj\n" +
|
||||
"<< /Type /Annot /Subtype /Widget /FT /Tx /DA (/Helv 5 Tf) /DR " +
|
||||
"<< /Font << /Helv 314 0 R>>>> /Rect [0 0 32 10] " +
|
||||
"/V (hello world) /AP << /N 2 0 R>> /M (date) /MK << /R 90>>>>\nendobj\n"
|
||||
);
|
||||
expect(newData.data).toEqual(
|
||||
"2 0 obj\n<< /Length 74 /Subtype /Form /Resources " +
|
||||
"<< /Font << /Helv 314 0 R>>>> /BBox [0 0 32 10] /Matrix [0 1 -1 0 32 0]>> stream\n" +
|
||||
"/Tx BMC q BT /Helv 5 Tf 1 0 0 1 0 0 Tm 2 3.04 Td (hello world) Tj " +
|
||||
"ET Q EMC\nendstream\nendobj\n"
|
||||
);
|
||||
});
|
||||
|
||||
it("should get field object for usage in JS sandbox", async function () {
|
||||
const textWidgetRef = Ref.get(123, 0);
|
||||
const xDictRef = Ref.get(141, 0);
|
||||
|
@ -2612,6 +2658,57 @@ describe("annotation", function () {
|
|||
expect(data).toEqual(null);
|
||||
});
|
||||
|
||||
it("should save rotated checkboxes", async function () {
|
||||
const appearanceStatesDict = new Dict();
|
||||
const normalAppearanceDict = new Dict();
|
||||
|
||||
normalAppearanceDict.set("Checked", Ref.get(314, 0));
|
||||
normalAppearanceDict.set("Off", Ref.get(271, 0));
|
||||
appearanceStatesDict.set("N", normalAppearanceDict);
|
||||
|
||||
buttonWidgetDict.set("AP", appearanceStatesDict);
|
||||
buttonWidgetDict.set("V", Name.get("Off"));
|
||||
|
||||
const buttonWidgetRef = Ref.get(123, 0);
|
||||
const xref = new XRefMock([
|
||||
{ ref: buttonWidgetRef, data: buttonWidgetDict },
|
||||
]);
|
||||
partialEvaluator.xref = xref;
|
||||
const task = new WorkerTask("test save");
|
||||
|
||||
const annotation = await AnnotationFactory.create(
|
||||
xref,
|
||||
buttonWidgetRef,
|
||||
pdfManagerMock,
|
||||
idFactoryMock
|
||||
);
|
||||
const annotationStorage = new Map();
|
||||
annotationStorage.set(annotation.data.id, { value: true, rotation: 180 });
|
||||
|
||||
const [oldData] = await annotation.save(
|
||||
partialEvaluator,
|
||||
task,
|
||||
annotationStorage
|
||||
);
|
||||
oldData.data = oldData.data.replace(/\(D:\d+\)/, "(date)");
|
||||
expect(oldData.ref).toEqual(Ref.get(123, 0));
|
||||
expect(oldData.data).toEqual(
|
||||
"123 0 obj\n" +
|
||||
"<< /Type /Annot /Subtype /Widget /FT /Btn " +
|
||||
"/AP << /N << /Checked 314 0 R /Off 271 0 R>>>> " +
|
||||
"/V /Checked /AS /Checked /M (date) /MK << /R 180>>>>\nendobj\n"
|
||||
);
|
||||
|
||||
annotationStorage.set(annotation.data.id, { value: false });
|
||||
|
||||
const data = await annotation.save(
|
||||
partialEvaluator,
|
||||
task,
|
||||
annotationStorage
|
||||
);
|
||||
expect(data).toEqual(null);
|
||||
});
|
||||
|
||||
it("should handle radio buttons with a field value", async function () {
|
||||
const parentDict = new Dict();
|
||||
parentDict.set("V", Name.get("1"));
|
||||
|
@ -3485,6 +3582,67 @@ describe("annotation", function () {
|
|||
);
|
||||
});
|
||||
|
||||
it("should save rotated choice", async function () {
|
||||
choiceWidgetDict.set("Opt", ["A", "B", "C"]);
|
||||
choiceWidgetDict.set("V", "A");
|
||||
|
||||
const choiceWidgetRef = Ref.get(123, 0);
|
||||
const xref = new XRefMock([
|
||||
{ ref: choiceWidgetRef, data: choiceWidgetDict },
|
||||
fontRefObj,
|
||||
]);
|
||||
partialEvaluator.xref = xref;
|
||||
const task = new WorkerTask("test save");
|
||||
|
||||
const annotation = await AnnotationFactory.create(
|
||||
xref,
|
||||
choiceWidgetRef,
|
||||
pdfManagerMock,
|
||||
idFactoryMock
|
||||
);
|
||||
const annotationStorage = new Map();
|
||||
annotationStorage.set(annotation.data.id, { value: "C", rotation: 270 });
|
||||
|
||||
const data = await annotation.save(
|
||||
partialEvaluator,
|
||||
task,
|
||||
annotationStorage
|
||||
);
|
||||
expect(data.length).toEqual(2);
|
||||
const [oldData, newData] = data;
|
||||
expect(oldData.ref).toEqual(Ref.get(123, 0));
|
||||
expect(newData.ref).toEqual(Ref.get(2, 0));
|
||||
|
||||
oldData.data = oldData.data.replace(/\(D:\d+\)/, "(date)");
|
||||
expect(oldData.data).toEqual(
|
||||
"123 0 obj\n" +
|
||||
"<< /Type /Annot /Subtype /Widget /FT /Ch /DA (/Helv 5 Tf) /DR " +
|
||||
"<< /Font << /Helv 314 0 R>>>> " +
|
||||
"/Rect [0 0 32 10] /Opt [(A) (B) (C)] /V (C) " +
|
||||
"/AP << /N 2 0 R>> /M (date) /MK << /R 270>>>>\nendobj\n"
|
||||
);
|
||||
expect(newData.data).toEqual(
|
||||
[
|
||||
"2 0 obj",
|
||||
"<< /Length 170 /Subtype /Form /Resources << /Font << /Helv 314 0 R>>>> " +
|
||||
"/BBox [0 0 32 10] /Matrix [0 -1 1 0 0 10]>> stream",
|
||||
"/Tx BMC q",
|
||||
"1 1 10 32 re W n",
|
||||
"0.600006 0.756866 0.854904 rg",
|
||||
"1 11.75 10 6.75 re f",
|
||||
"BT",
|
||||
"/Helv 5 Tf",
|
||||
"1 0 0 1 0 32 Tm",
|
||||
"2 -5.88 Td (A) Tj",
|
||||
"0 -6.75 Td (B) Tj",
|
||||
"0 -6.75 Td (C) Tj",
|
||||
"ET Q EMC",
|
||||
"endstream",
|
||||
"endobj\n",
|
||||
].join("\n")
|
||||
);
|
||||
});
|
||||
|
||||
it("should save choice", async function () {
|
||||
choiceWidgetDict.set("Opt", ["A", "B", "C"]);
|
||||
choiceWidgetDict.set("V", "A");
|
||||
|
|
|
@ -1333,6 +1333,7 @@ describe("api", function () {
|
|||
page: 0,
|
||||
strokeColor: null,
|
||||
fillColor: null,
|
||||
rotation: 0,
|
||||
type: "text",
|
||||
},
|
||||
],
|
||||
|
@ -1354,6 +1355,7 @@ describe("api", function () {
|
|||
page: 0,
|
||||
strokeColor: null,
|
||||
fillColor: new Uint8ClampedArray([192, 192, 192]),
|
||||
rotation: 0,
|
||||
type: "button",
|
||||
},
|
||||
],
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue