Merge remote-tracking branch 'origin/feature/pdf-redact' into fix/pdf-copy-paste

This commit is contained in:
Svetlana Kulikova
2025-07-18 16:12:09 +03:00
10 changed files with 478 additions and 43 deletions

View File

@ -450,10 +450,13 @@ function readAction(reader, rec, readDoubleFunc, readStringFunc)
}
function readAnnot(reader, rec, readDoubleFunc, readDouble2Func, readStringFunc, isRead = false)
{
rec["AP"] = {};
if (!isRead)
rec["AP"] = {};
// Annot
// number for relations with AP
rec["AP"]["i"] = reader.readInt();
let APi = reader.readInt();
if (!isRead)
rec["AP"]["i"] = APi;
rec["annotflag"] = reader.readInt();
// 12.5.3
let bHidden = (rec["annotflag"] >> 1) & 1; // Hidden
@ -536,16 +539,18 @@ function readAnnot(reader, rec, readDoubleFunc, readDouble2Func, readStringFunc,
if (flags & (1 << 6))
{
if (isRead)
rec["AP"]["render"] = reader.readData(); // TODO use Render - Uint8Array
{
let APrender = reader.readData(); // TODO use Render - Uint8Array
// rec["AP"]["render"] = APrender;
}
else
rec["AP"]["have"] = (flags >> 6) & 1;
}
// User ID
if (flags & (1 << 7))
rec["OUserID"] = readStringFunc.call(reader);
// User ID
if (flags & (1 << 8))
rec["AP"]["Copy"] = reader.readInt();
// if (flags & (1 << 8))
// reader.readInt();
}
function readAnnotAP(reader, AP)
{
@ -581,7 +586,7 @@ function readAnnotType(reader, rec, readDoubleFunc, readDouble2Func, readStringF
{
// Markup
let flags = 0;
if ((rec["Type"] < 18 && rec["Type"] != 1 && rec["Type"] != 15) || rec["Type"] == 25)
if ((rec["type"] < 18 && rec["type"] != 1 && rec["type"] != 15) || rec["type"] == 25)
{
flags = reader.readInt();
if (flags & (1 << 0))
@ -636,7 +641,7 @@ function readAnnotType(reader, rec, readDoubleFunc, readDouble2Func, readStringF
rec["Subj"] = readStringFunc.call(reader);
}
// Text
if (rec["Type"] == 0)
if (rec["type"] == 0)
{
// Background color - C->IC
if (rec["C"])
@ -660,7 +665,7 @@ function readAnnotType(reader, rec, readDoubleFunc, readDouble2Func, readStringF
}
// Line
else if (rec["Type"] == 3)
else if (rec["type"] == 3)
{
// L
rec["L"] = [];
@ -710,7 +715,7 @@ function readAnnotType(reader, rec, readDoubleFunc, readDouble2Func, readStringF
}
}
// Ink
else if (rec["Type"] == 14)
else if (rec["type"] == 14)
{
// offsets like getStructure and viewer.navigate
let n = reader.readInt();
@ -724,7 +729,7 @@ function readAnnotType(reader, rec, readDoubleFunc, readDouble2Func, readStringF
}
}
// Highlight, Underline, Squiggly, Strikeout
else if (rec["Type"] > 7 && rec["Type"] < 12)
else if (rec["type"] > 7 && rec["type"] < 12)
{
// QuadPoints
let n = reader.readInt();
@ -733,7 +738,7 @@ function readAnnotType(reader, rec, readDoubleFunc, readDouble2Func, readStringF
rec["QuadPoints"].push(readDoubleFunc.call(reader));
}
// Square, Circle
else if (rec["Type"] == 4 || rec["Type"] == 5)
else if (rec["type"] == 4 || rec["type"] == 5)
{
// Rect and RD differences
if (flags & (1 << 15))
@ -752,7 +757,7 @@ function readAnnotType(reader, rec, readDoubleFunc, readDouble2Func, readStringF
}
}
// Polygon, PolyLine
else if (rec["Type"] == 6 || rec["Type"] == 7)
else if (rec["type"] == 6 || rec["type"] == 7)
{
let nVertices = reader.readInt();
rec["Vertices"] = [];
@ -780,8 +785,7 @@ function readAnnotType(reader, rec, readDoubleFunc, readDouble2Func, readStringF
rec["IT"] = reader.readByte();
}
// Popup
/*
else if (rec["Type"] == 15)
else if (rec["type"] == 15)
{
flags = reader.readInt();
rec["Open"] = (flags >> 0) & 1;
@ -789,9 +793,8 @@ function readAnnotType(reader, rec, readDoubleFunc, readDouble2Func, readStringF
if (flags & (1 << 1))
rec["PopupParent"] = reader.readInt();
}
*/
// FreeText
else if (rec["Type"] == 2)
else if (rec["type"] == 2)
{
// Background color - C->IC
if (!isRead && rec["C"])
@ -847,7 +850,7 @@ function readAnnotType(reader, rec, readDoubleFunc, readDouble2Func, readStringF
}
}
// Caret
else if (rec["Type"] == 13)
else if (rec["type"] == 13)
{
// Rect and RD differenses
if (flags & (1 << 15))
@ -862,7 +865,7 @@ function readAnnotType(reader, rec, readDoubleFunc, readDouble2Func, readStringF
rec["Sy"] = reader.readByte();
}
// FileAttachment
else if (rec["Type"] == 16)
else if (rec["type"] == 16)
{
if (flags & (1 << 15))
rec["Icon"] = readStringFunc.call(reader);
@ -961,7 +964,7 @@ function readAnnotType(reader, rec, readDoubleFunc, readDouble2Func, readStringF
rec["Desc"] = readStringFunc.call(reader);
}
// Stamp
else if (rec["Type"] == 12)
else if (rec["type"] == 12)
{
rec["Icon"] = readStringFunc.call(reader);
rec["Rotate"] = readDouble2Func.call(reader);
@ -969,6 +972,52 @@ function readAnnotType(reader, rec, readDoubleFunc, readDouble2Func, readStringF
for (let i = 0; i < 8; ++i)
rec["InRect"].push(readDouble2Func.call(reader));
}
// Redact
else if (rec["type"] == 25)
{
// QuadPoints
if (flags & (1 << 15))
{
let n = reader.readInt();
rec["QuadPoints"] = [];
for (let i = 0; i < n; ++i)
rec["QuadPoints"].push(readDoubleFunc.call(reader));
}
// IC
if (flags & (1 << 16))
{
let n = reader.readInt();
rec["IC"] = [];
for (let i = 0; i < n; ++i)
rec["IC"].push(readDouble2Func.call(reader));
}
// OverlayText
if (flags & (1 << 17))
rec["OverlayText"] = readStringFunc.call(reader);
// Repeat
rec["Repeat"] = (flags >> 18) & 1;
// Q - alignment
if (flags & (1 << 19))
{
// 0 - left-justified, 1 - centered, 2 - right-justified
rec["alignment"] = reader.readByte();
}
// Font from DA
if (flags & (1 << 20))
{
rec["font"] = {};
let n = reader.readInt();
rec["font"]["color"] = [];
for (let i = 0; i < n; ++i)
rec["font"]["color"].push(readDouble2Func.call(reader));
rec["font"]["size"] = readDoubleFunc.call(reader);
rec["font"]["name"] = readStringFunc.call(reader);
let fontActual = readStringFunc.call(reader);
if (fontActual != "")
rec["font"]["actual"] = fontActual;
rec["font"]["style"] = reader.readInt();
}
}
}
function readWidgetType(reader, rec, readDoubleFunc, readDouble2Func, readStringFunc, isRead = false)
{
@ -987,7 +1036,7 @@ function readWidgetType(reader, rec, readDoubleFunc, readDouble2Func, readString
rec["font"]["color"].push(readDouble2Func.call(reader));
}
// 0 - left-justified, 1 - centered, 2 - right-justified
if (!isRead || (rec["Type"] != 29 && rec["Type"] != 28 && rec["Type"] != 27))
if (!isRead || (rec["type"] != 29 && rec["type"] != 28 && rec["type"] != 27))
rec["alignment"] = reader.readByte();
rec["flag"] = reader.readInt();
// 12.7.3.1
@ -1131,9 +1180,15 @@ function readWidgetType(reader, rec, readDoubleFunc, readDouble2Func, readString
if (isRead)
{
if (flags & (1 << 12))
rec["AP"]["V"] = readStringFunc.call(reader);
{
let APV = readStringFunc.call(reader);
// rec["AP"]["V"] = APV;
}
if (flags & (1 << 13))
rec["AP"]["render"] = reader.readData(); // TODO use Render - Uint8Array
{
let APrender = reader.readData(); // TODO use Render - Uint8Array
// rec["AP"]["render"] = APrender;
}
}
// 12.7.4.3
if (rec["flag"] >= 0)
@ -1170,7 +1225,10 @@ function readWidgetType(reader, rec, readDoubleFunc, readDouble2Func, readString
if (isRead)
{
if (flags & (1 << 12))
rec["AP"]["V"] = readStringFunc.call(reader);
{
let APV = readStringFunc.call(reader);
// rec["AP"]["V"] = APV;
}
}
else
{
@ -1199,7 +1257,10 @@ function readWidgetType(reader, rec, readDoubleFunc, readDouble2Func, readString
rec["I"].push(reader.readInt());
}
if (flags & (1 << 15))
rec["AP"]["render"] = reader.readData(); // TODO use Render - Uint8Array
{
let APrender = reader.readData(); // TODO use Render - Uint8Array
// rec["AP"]["render"] = APrender;
}
}
// 12.7.4.4
if (rec["flag"] >= 0)
@ -1473,7 +1534,7 @@ CFile.prototype["getAnnotationsInfo"] = function(pageIndex)
// 11 - Strikeout, 12 - Stamp, 13 - Caret, 14 - Ink, 15 - Popup, 16 - FileAttachment,
// 17 - Sound, 18 - Movie, 19 - Widget, 20 - Screen, 21 - PrinterMark,
// 22 - TrapNet, 23 - Watermark, 24 - 3D, 25 - Redact
rec["Type"] = reader.readByte();
rec["type"] = reader.readByte();
// Annot
readAnnot(reader, rec, reader.readDouble, reader.readDouble2, reader.readString);
// Annot type
@ -1548,12 +1609,12 @@ CFile.prototype["readAnnotationsInfoFromBinary"] = function(AnnotInfo)
// 11 - Strikeout, 12 - Stamp, 13 - Caret, 14 - Ink, 15 - Popup, 16 - FileAttachment,
// 17 - Sound, 18 - Movie, 19 - Widget, 20 - Screen, 21 - PrinterMark,
// 22 - TrapNet, 23 - Watermark, 24 - 3D, 25 - Redact
rec["Type"] = reader.readByte();
rec["type"] = reader.readByte();
// Annot
readAnnot(reader, rec, reader.readDouble3, reader.readDouble3, reader.readString2, true);
// Annot type
readAnnotType(reader, rec, reader.readDouble3, reader.readDouble3, reader.readString2, true);
if (rec["Type"] >= 26 && rec["Type"] <= 33)
if (rec["type"] >= 26 && rec["type"] <= 33)
{
// Widget type
readWidgetType(reader, rec, reader.readDouble3, reader.readDouble3, reader.readString2, true);

View File

@ -2043,6 +2043,83 @@ int main(int argc, char* argv[])
i += 4;
std::cout << "Y4 " << (double)nPathLength / 10000.0 << ", ";
}
else if (sType == "Redact")
{
if (nFlags & (1 << 15))
{
std::cout << "QuadPoints";
int nQuadPointsLength = READ_INT(pAnnots + i);
i += 4;
for (int j = 0; j < nQuadPointsLength; ++j)
{
nPathLength = READ_INT(pAnnots + i);
i += 4;
std::cout << " " << (double)nPathLength / 100.0;
}
std::cout << ", ";
}
if (nFlags & (1 << 16))
{
int nICLength = READ_INT(pAnnots + i);
i += 4;
std::cout << "IC ";
for (int j = 0; j < nICLength; ++j)
{
nPathLength = READ_INT(pAnnots + i);
i += 4;
std::cout << (double)nPathLength / 10000.0 << " ";
}
std::cout << ", ";
}
if (nFlags & (1 << 17))
{
nPathLength = READ_INT(pAnnots + i);
i += 4;
std::cout << "OverlayText " << std::string((char*)(pAnnots + i), nPathLength) << ", ";
i += nPathLength;
}
if (nFlags & (1 << 18))
std::cout << "Repeat true, ";
else
std::cout << "Repeat false, ";
if (nFlags & (1 << 19))
{
std::string arrQ[] = {"left-justified", "centered", "right-justified"};
nPathLength = READ_BYTE(pAnnots + i);
i += 1;
std::cout << "Q " << arrQ[nPathLength] << ", ";
}
if (nFlags & (1 << 20))
{
int nICLength = READ_INT(pAnnots + i);
i += 4;
std::cout << "DA color ";
for (int j = 0; j < nICLength; ++j)
{
nPathLength = READ_INT(pAnnots + i);
i += 4;
std::cout << (double)nPathLength / 10000.0 << " ";
}
std::cout << ", size ";
nPathLength = READ_INT(pAnnots + i);
i += 4;
std::cout << (double)nPathLength / 100.0 << ", font ";
nPathLength = READ_INT(pAnnots + i);
i += 4;
std::cout << std::string((char*)(pAnnots + i), nPathLength) << " actual ";
i += nPathLength;
nPathLength = READ_INT(pAnnots + i);
i += 4;
std::cout << std::string((char*)(pAnnots + i), nPathLength) << ", style ";
i += nPathLength;
nPathLength = READ_INT(pAnnots + i);
i += 4;
std::cout << nPathLength << ", ";
}
}
std::cout << std::endl << "]" << std::endl;
}