// Fixed server-side code. WatermarkInput is decoded from the job's structured JSON data.
|
builderJS.OpenFile(WatermarkInput.sourceUrl);
|
var outputFormat = 'docx';
|
var outputName = 'Watermark.docx';
|
try {
|
var doc = Api.GetDocument();
|
if (typeof doc.AddDrawingToPage !== 'function') throw new Error('UNSUPPORTED_VERSION');
|
var pageCount = doc.GetPageCount();
|
var plans = [];
|
var pageAnchors = {};
|
var endPosition = doc.GetRange().GetEndPos();
|
function pageAnchor(page) {
|
if (pageAnchors[page]) return pageAnchors[page];
|
// GoToPage can leave the cursor on an earlier page of the same paragraph.
|
// Locate the first text position on the physical page independently of that cursor.
|
var low = 0;
|
var high = endPosition;
|
while (low < high) {
|
var middle = Math.floor((low + high) / 2);
|
if (doc.GetRange(middle, middle).GetStartPage() < page - 1) low = middle + 1;
|
else high = middle;
|
}
|
var range = doc.GetRange(low, low);
|
if (range.GetStartPage() !== page - 1) throw new Error('PAGE_ANCHOR_NOT_FOUND|' + page);
|
pageAnchors[page] = { range: range, position: low };
|
return pageAnchors[page];
|
}
|
WatermarkInput.overlays.forEach(function (overlay, groupIndex) {
|
overlay.pages.forEach(function (page) {
|
// The stored Word page count can differ from OnlyOffice pagination.
|
// Ignore watermark targets that do not exist in the rendered document.
|
if (page > pageCount) return;
|
var anchor = pageAnchor(page);
|
if (!anchor.range.MoveCursorToPos(anchor.position)) throw new Error('PAGE_ANCHOR_NOT_FOUND|' + page);
|
var paragraph = doc.GetCurrentParagraph();
|
var section = paragraph && paragraph.GetSection();
|
if (!section) throw new Error('PAGE_SECTION_NOT_FOUND|' + page);
|
var width = section.GetPageWidth() * 25.4 / 1440;
|
var height = section.GetPageHeight() * 25.4 / 1440;
|
var variant = overlay.variants.find(function (item) {
|
return Math.abs(item.widthMm - width) < 0.2 && Math.abs(item.heightMm - height) < 0.2;
|
});
|
if (!variant) throw new Error('PAGE_SIZE_NOT_FOUND|' + page);
|
plans.push({ page: page, group: groupIndex, variant: variant, position: anchor.position });
|
});
|
});
|
var tracked = doc.IsTrackRevisions();
|
doc.SetTrackRevisions(false);
|
// Earlier character positions remain stable when drawings are inserted from the last page.
|
plans.sort(function (left, right) { return right.page - left.page; });
|
plans.forEach(function (plan) {
|
if (doc.GetPageCount() !== pageCount) throw new Error('PAGINATION_CHANGED');
|
if (!doc.GetRange(plan.position, plan.position).MoveCursorToPos(plan.position)) {
|
throw new Error('PAGE_ANCHOR_NOT_FOUND|' + plan.page);
|
}
|
var variant = plan.variant;
|
var drawingWidthMm = variant.drawingWidthMm || variant.widthMm;
|
var drawingHeightMm = variant.drawingHeightMm || variant.heightMm;
|
var offsetXMm = variant.offsetXMm || 0;
|
var offsetYMm = variant.offsetYMm || 0;
|
var drawing = Api.CreateImage('data:image/png;base64,' + variant.pngBase64,
|
Math.round(drawingWidthMm * 36000), Math.round(drawingHeightMm * 36000));
|
drawing.SetName(WatermarkInput.markerPrefix + '_' + plan.group + '_' + plan.page);
|
drawing.SetWrappingStyle('behind');
|
if (!doc.AddDrawingToPage(drawing, plan.page - 1,
|
Math.round(offsetXMm * 36000), Math.round(offsetYMm * 36000))) {
|
throw new Error('INSERT_FAILED|' + plan.page);
|
}
|
});
|
doc.SetTrackRevisions(tracked);
|
if (doc.GetPageCount() !== pageCount) throw new Error('PAGINATION_CHANGED');
|
} catch (error) {
|
// Return a bounded diagnostic as a separate artifact, never a partly watermarked document.
|
var failedDoc = Api.GetDocument();
|
failedDoc.SetTrackRevisions(false);
|
failedDoc.RemoveAllElements();
|
var diagnostic = Api.CreateParagraph();
|
diagnostic.AddText('DMS_WATERMARK_ERROR:' + String(error.message).slice(0, 300));
|
failedDoc.Push(diagnostic);
|
outputFormat = 'txt';
|
outputName = 'WatermarkError.txt';
|
}
|
builderJS.SaveFile(outputFormat, outputName);
|
builderJS.CloseFile();
|