mirror of
https://gitee.com/kekingcn/file-online-preview.git
synced 2026-09-12 16:05:00 +00:00
Merge pull request #782 from kekingcn/codex/fix-custom-watermark-settings
fix: 修复 PDF/Word 自定义水印设置不生效
This commit is contained in:
@@ -1,5 +1,18 @@
|
||||
var kkhighlightAll;
|
||||
var watermarkTxt;
|
||||
var watermarkSettings = {
|
||||
start_x: 80,
|
||||
start_y: 80,
|
||||
x_space: 80,
|
||||
y_space: 80,
|
||||
color: 'black',
|
||||
alpha: 0.2,
|
||||
fontsize: '18px',
|
||||
font: '微软雅黑',
|
||||
width: 200,
|
||||
height: 80,
|
||||
angle: 30
|
||||
};
|
||||
const queryString = document.location.search.substring(1);
|
||||
const params = (0, parseQueryString)(queryString);
|
||||
|
||||
@@ -13,6 +26,30 @@ if (kkpdfAutoFetch == "true") {
|
||||
function isNotEmpty(value) {
|
||||
return value !== null && value !== undefined && value !== '' && value !== 'false' ;
|
||||
}
|
||||
|
||||
function getWatermarkStringParam(params, name, fallback) {
|
||||
const value = params.get(name);
|
||||
return isNotEmpty(value) ? value : fallback;
|
||||
}
|
||||
|
||||
function getWatermarkNumberParam(params, name, fallback, isValid) {
|
||||
const rawValue = params.get(name);
|
||||
if (!isNotEmpty(rawValue)) return fallback;
|
||||
const value = Number(rawValue);
|
||||
return Number.isFinite(value) && isValid(value) ? value : fallback;
|
||||
}
|
||||
|
||||
function configureWatermark(params) {
|
||||
watermarkSettings.x_space = getWatermarkNumberParam(params, "watermarkxspace", watermarkSettings.x_space, value => value >= 0);
|
||||
watermarkSettings.y_space = getWatermarkNumberParam(params, "watermarkyspace", watermarkSettings.y_space, value => value >= 0);
|
||||
watermarkSettings.font = getWatermarkStringParam(params, "watermarkfont", watermarkSettings.font);
|
||||
watermarkSettings.fontsize = getWatermarkStringParam(params, "watermarkfontsize", watermarkSettings.fontsize);
|
||||
watermarkSettings.color = getWatermarkStringParam(params, "watermarkcolor", watermarkSettings.color);
|
||||
watermarkSettings.alpha = getWatermarkNumberParam(params, "watermarkalpha", watermarkSettings.alpha, value => value >= 0 && value <= 1);
|
||||
watermarkSettings.width = getWatermarkNumberParam(params, "watermarkwidth", watermarkSettings.width, value => value > 0);
|
||||
watermarkSettings.height = getWatermarkNumberParam(params, "watermarkheight", watermarkSettings.height, value => value > 0);
|
||||
watermarkSettings.angle = getWatermarkNumberParam(params, "watermarkangle", watermarkSettings.angle, Number.isFinite);
|
||||
}
|
||||
/**
|
||||
* 通用水印生成函数
|
||||
* @param {HTMLElement} container - 水印容器(相对定位的父元素)
|
||||
@@ -23,20 +60,7 @@ function isNotEmpty(value) {
|
||||
function addWatermark(container, watermarkTxt, explicitWidth = null, explicitHeight = null) {
|
||||
if (!isNotEmpty(watermarkTxt)) return;
|
||||
|
||||
// 公共配置
|
||||
const settings = {
|
||||
start_x: 80,
|
||||
start_y: 80,
|
||||
x_space: 80,
|
||||
y_space: 80,
|
||||
color: 'black',
|
||||
alpha: 0.2,
|
||||
fontsize: '18px',
|
||||
font: '微软雅黑',
|
||||
width: 200,
|
||||
height: 80,
|
||||
angle: 30
|
||||
};
|
||||
const settings = watermarkSettings;
|
||||
|
||||
// 确定实际使用的宽高
|
||||
let pageWidth, pageHeight;
|
||||
@@ -55,30 +79,30 @@ function addWatermark(container, watermarkTxt, explicitWidth = null, explicitHei
|
||||
maxY = Math.max(maxY, 250);
|
||||
|
||||
const fragment = document.createDocumentFragment();
|
||||
for (let x = settings.start_x; x < maxX; x += settings.x_space) {
|
||||
for (let y = settings.start_y; y < maxY; y += settings.y_space) {
|
||||
const xStep = settings.width + settings.x_space;
|
||||
const yStep = settings.height + settings.y_space;
|
||||
for (let x = settings.start_x; x < maxX; x += xStep) {
|
||||
for (let y = settings.start_y; y < maxY; y += yStep) {
|
||||
const div = document.createElement('div');
|
||||
div.className = 'mask_div';
|
||||
div.appendChild(document.createTextNode(watermarkTxt));
|
||||
div.style.cssText = `
|
||||
filter: progid:DXImageTransform.Microsoft.Alpha(opacity=${settings.alpha * 100});
|
||||
transform: rotate(-${settings.angle}deg);
|
||||
visibility: visible;
|
||||
position: absolute;
|
||||
left: ${x}px;
|
||||
top: ${y}px;
|
||||
overflow: hidden;
|
||||
z-index: 100;
|
||||
pointer-events: none;
|
||||
opacity: ${settings.alpha};
|
||||
font-size: ${settings.fontsize};
|
||||
font-family: ${settings.font};
|
||||
color: ${settings.color};
|
||||
text-align: center;
|
||||
width: ${settings.width}px;
|
||||
height: ${settings.height}px;
|
||||
display: block;
|
||||
`;
|
||||
div.style.filter = `progid:DXImageTransform.Microsoft.Alpha(opacity=${settings.alpha * 100})`;
|
||||
div.style.transform = `rotate(-${settings.angle}deg)`;
|
||||
div.style.visibility = 'visible';
|
||||
div.style.position = 'absolute';
|
||||
div.style.left = `${x}px`;
|
||||
div.style.top = `${y}px`;
|
||||
div.style.overflow = 'hidden';
|
||||
div.style.zIndex = '100';
|
||||
div.style.pointerEvents = 'none';
|
||||
div.style.opacity = settings.alpha;
|
||||
div.style.fontSize = settings.fontsize;
|
||||
div.style.fontFamily = settings.font;
|
||||
div.style.color = settings.color;
|
||||
div.style.textAlign = 'center';
|
||||
div.style.width = `${settings.width}px`;
|
||||
div.style.height = `${settings.height}px`;
|
||||
div.style.display = 'block';
|
||||
fragment.appendChild(div);
|
||||
}
|
||||
}
|
||||
@@ -22069,7 +22093,8 @@ const PDFViewerApplication = {
|
||||
disableBookmark = params.get("disablebookmark") ?? 'false';
|
||||
disableEditing = params.get("disableediting") ?? 'false';
|
||||
kkhighlightAll = params.get("pdfhighlightall") ?? 'false';
|
||||
watermarkTxt= params.get('watermarktxt') ?? 'false';
|
||||
watermarkTxt = params.get('watermarktxt') ?? 'false';
|
||||
configureWatermark(params);
|
||||
try {
|
||||
file = new URL(file).href;
|
||||
} catch {
|
||||
@@ -24017,4 +24042,4 @@ if (document.readyState === "interactive" || document.readyState === "complete")
|
||||
|
||||
export { PDFViewerApplication, AppConstants as PDFViewerApplicationConstants, AppOptions as PDFViewerApplicationOptions };
|
||||
|
||||
//# sourceMappingURL=viewer.mjs.map
|
||||
//# sourceMappingURL=viewer.mjs.map
|
||||
|
||||
@@ -53,7 +53,18 @@
|
||||
url = baseUrl + 'getCorsFile?urlPath=' + encodeURIComponent(Base64.encode(url)) + "&key=${kkkey}";
|
||||
}
|
||||
var viewerUrl = baseUrl + "pdfjs/web/viewer.html?file=" + encodeURIComponent(url);
|
||||
var watermarkEncoded = encodeURIComponent('${watermarkTxt?js_string}');
|
||||
var watermarkParams = {
|
||||
watermarktxt: '${watermarkTxt?js_string}',
|
||||
watermarkxspace: '${watermarkXSpace?js_string}',
|
||||
watermarkyspace: '${watermarkYSpace?js_string}',
|
||||
watermarkfont: '${watermarkFont?js_string}',
|
||||
watermarkfontsize: '${watermarkFontsize?js_string}',
|
||||
watermarkcolor: '${watermarkColor?js_string}',
|
||||
watermarkalpha: '${watermarkAlpha?js_string}',
|
||||
watermarkwidth: '${watermarkWidth?js_string}',
|
||||
watermarkheight: '${watermarkHeight?js_string}',
|
||||
watermarkangle: '${watermarkAngle?js_string}'
|
||||
};
|
||||
var highlightEncoded = encodeURIComponent('${highlightall?js_string}');
|
||||
viewerUrl += "&disablepresentationmode=${pdfPresentationModeDisable}";
|
||||
viewerUrl += "&disableopenfile=${pdfOpenFileDisable}";
|
||||
@@ -61,7 +72,9 @@
|
||||
viewerUrl += "&disabledownload=${pdfDownloadDisable}";
|
||||
viewerUrl += "&disablebookmark=${pdfBookmarkDisable}";
|
||||
viewerUrl += "&disableediting=${pdfDisableEditing}";
|
||||
viewerUrl += "&watermarktxt=" + watermarkEncoded;
|
||||
Object.keys(watermarkParams).forEach(function (name) {
|
||||
viewerUrl += "&" + name + "=" + encodeURIComponent(watermarkParams[name]);
|
||||
});
|
||||
viewerUrl += "&pdfhighlightall=" + highlightEncoded;
|
||||
viewerUrl += "#page=${page}"; // ?c 确保数字不包含千位分隔符
|
||||
<#if "true" == pdfSidebarOpen>
|
||||
|
||||
@@ -5,6 +5,7 @@ import org.junit.jupiter.api.Test;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
@@ -35,6 +36,38 @@ public class PdfViewerCompatibilityTests {
|
||||
assertTrue(pdfTemplate.contains("viewerUrl += \"&pagemode=none\";"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldForwardAndApplyAllPdfWatermarkSettings() throws IOException {
|
||||
String pdfTemplate = readResource("/web/pdf.ftl");
|
||||
String viewerScript = readResource("/static/pdfjs/web/viewer.mjs");
|
||||
Map<String, String> watermarkParams = Map.ofEntries(
|
||||
Map.entry("watermarktxt", "watermarkTxt"),
|
||||
Map.entry("watermarkxspace", "watermarkXSpace"),
|
||||
Map.entry("watermarkyspace", "watermarkYSpace"),
|
||||
Map.entry("watermarkfont", "watermarkFont"),
|
||||
Map.entry("watermarkfontsize", "watermarkFontsize"),
|
||||
Map.entry("watermarkcolor", "watermarkColor"),
|
||||
Map.entry("watermarkalpha", "watermarkAlpha"),
|
||||
Map.entry("watermarkwidth", "watermarkWidth"),
|
||||
Map.entry("watermarkheight", "watermarkHeight"),
|
||||
Map.entry("watermarkangle", "watermarkAngle")
|
||||
);
|
||||
|
||||
watermarkParams.forEach((queryParam, templateAttribute) -> {
|
||||
assertTrue(pdfTemplate.contains(queryParam + ": '${" + templateAttribute + "?js_string}'"),
|
||||
() -> "PDF template does not forward " + templateAttribute);
|
||||
assertTrue(viewerScript.contains("\"" + queryParam + "\"")
|
||||
|| viewerScript.contains("'" + queryParam + "'"),
|
||||
() -> "PDF viewer does not consume " + queryParam);
|
||||
});
|
||||
assertTrue(viewerScript.contains("div.style.fontFamily = settings.font;"));
|
||||
assertTrue(viewerScript.contains("div.style.fontSize = settings.fontsize;"));
|
||||
assertTrue(viewerScript.contains("div.style.color = settings.color;"));
|
||||
assertTrue(viewerScript.contains("div.style.opacity = settings.alpha;"));
|
||||
assertTrue(viewerScript.contains("const xStep = settings.width + settings.x_space;"));
|
||||
assertTrue(viewerScript.contains("const yStep = settings.height + settings.y_space;"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldPreferPdfForOfficePreviewByDefault() throws IOException {
|
||||
String properties = readResource("/application.properties");
|
||||
|
||||
@@ -172,3 +172,53 @@ test('21 security: block 10.x host in getCorsFile', async ({ request }) => {
|
||||
const body = await resp.text();
|
||||
expect(body).toContain('不受信任');
|
||||
});
|
||||
|
||||
test('22 pdf preview applies custom watermark settings', async ({ page }) => {
|
||||
const query = new URLSearchParams({
|
||||
url: b64(`${fixtureBase}/sample.pdf`),
|
||||
watermarkTxt: 'Custom watermark',
|
||||
watermarkXSpace: '37',
|
||||
watermarkYSpace: '43',
|
||||
watermarkFont: 'Courier New',
|
||||
watermarkFontsize: '31px',
|
||||
watermarkColor: 'rgb(1, 2, 3)',
|
||||
watermarkAlpha: '0.65',
|
||||
watermarkWidth: '100',
|
||||
watermarkHeight: '77',
|
||||
watermarkAngle: '17',
|
||||
});
|
||||
|
||||
await page.goto(`/onlinePreview?${query.toString()}`);
|
||||
const watermark = page.frameLocator('#pdfFrame').locator('.mask_div').first();
|
||||
await expect(watermark).toHaveText('Custom watermark');
|
||||
|
||||
const style = await watermark.evaluate(element => ({
|
||||
fontFamily: element.style.fontFamily,
|
||||
fontSize: element.style.fontSize,
|
||||
color: element.style.color,
|
||||
opacity: element.style.opacity,
|
||||
width: element.style.width,
|
||||
height: element.style.height,
|
||||
transform: element.style.transform,
|
||||
}));
|
||||
expect(style).toEqual({
|
||||
fontFamily: '"Courier New"',
|
||||
fontSize: '31px',
|
||||
color: 'rgb(1, 2, 3)',
|
||||
opacity: '0.65',
|
||||
width: '100px',
|
||||
height: '77px',
|
||||
transform: 'rotate(-17deg)',
|
||||
});
|
||||
|
||||
const positions = await page.frameLocator('#pdfFrame').locator('.mask_div').evaluateAll(elements =>
|
||||
elements.map(element => ({
|
||||
left: Number.parseFloat(element.style.left),
|
||||
top: Number.parseFloat(element.style.top),
|
||||
})),
|
||||
);
|
||||
const nextColumn = positions.find(position => position.left !== positions[0].left);
|
||||
expect(positions[1].top - positions[0].top).toBe(120);
|
||||
expect(nextColumn).toBeDefined();
|
||||
expect(nextColumn!.left - positions[0].left).toBe(137);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user