mirror of
https://gitee.com/kekingcn/file-online-preview.git
synced 2026-09-13 00:14:56 +00:00
Compare commits
1 Commits
v5.0.2
...
codex/fix-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a199b4a7fe |
@@ -1,5 +1,18 @@
|
|||||||
var kkhighlightAll;
|
var kkhighlightAll;
|
||||||
var watermarkTxt;
|
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 queryString = document.location.search.substring(1);
|
||||||
const params = (0, parseQueryString)(queryString);
|
const params = (0, parseQueryString)(queryString);
|
||||||
|
|
||||||
@@ -13,6 +26,30 @@ if (kkpdfAutoFetch == "true") {
|
|||||||
function isNotEmpty(value) {
|
function isNotEmpty(value) {
|
||||||
return value !== null && value !== undefined && value !== '' && value !== 'false' ;
|
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 - 水印容器(相对定位的父元素)
|
* @param {HTMLElement} container - 水印容器(相对定位的父元素)
|
||||||
@@ -23,20 +60,7 @@ function isNotEmpty(value) {
|
|||||||
function addWatermark(container, watermarkTxt, explicitWidth = null, explicitHeight = null) {
|
function addWatermark(container, watermarkTxt, explicitWidth = null, explicitHeight = null) {
|
||||||
if (!isNotEmpty(watermarkTxt)) return;
|
if (!isNotEmpty(watermarkTxt)) return;
|
||||||
|
|
||||||
// 公共配置
|
const settings = watermarkSettings;
|
||||||
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
|
|
||||||
};
|
|
||||||
|
|
||||||
// 确定实际使用的宽高
|
// 确定实际使用的宽高
|
||||||
let pageWidth, pageHeight;
|
let pageWidth, pageHeight;
|
||||||
@@ -55,30 +79,30 @@ function addWatermark(container, watermarkTxt, explicitWidth = null, explicitHei
|
|||||||
maxY = Math.max(maxY, 250);
|
maxY = Math.max(maxY, 250);
|
||||||
|
|
||||||
const fragment = document.createDocumentFragment();
|
const fragment = document.createDocumentFragment();
|
||||||
for (let x = settings.start_x; x < maxX; x += settings.x_space) {
|
const xStep = settings.width + settings.x_space;
|
||||||
for (let y = settings.start_y; y < maxY; y += settings.y_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');
|
const div = document.createElement('div');
|
||||||
div.className = 'mask_div';
|
div.className = 'mask_div';
|
||||||
div.appendChild(document.createTextNode(watermarkTxt));
|
div.appendChild(document.createTextNode(watermarkTxt));
|
||||||
div.style.cssText = `
|
div.style.filter = `progid:DXImageTransform.Microsoft.Alpha(opacity=${settings.alpha * 100})`;
|
||||||
filter: progid:DXImageTransform.Microsoft.Alpha(opacity=${settings.alpha * 100});
|
div.style.transform = `rotate(-${settings.angle}deg)`;
|
||||||
transform: rotate(-${settings.angle}deg);
|
div.style.visibility = 'visible';
|
||||||
visibility: visible;
|
div.style.position = 'absolute';
|
||||||
position: absolute;
|
div.style.left = `${x}px`;
|
||||||
left: ${x}px;
|
div.style.top = `${y}px`;
|
||||||
top: ${y}px;
|
div.style.overflow = 'hidden';
|
||||||
overflow: hidden;
|
div.style.zIndex = '100';
|
||||||
z-index: 100;
|
div.style.pointerEvents = 'none';
|
||||||
pointer-events: none;
|
div.style.opacity = settings.alpha;
|
||||||
opacity: ${settings.alpha};
|
div.style.fontSize = settings.fontsize;
|
||||||
font-size: ${settings.fontsize};
|
div.style.fontFamily = settings.font;
|
||||||
font-family: ${settings.font};
|
div.style.color = settings.color;
|
||||||
color: ${settings.color};
|
div.style.textAlign = 'center';
|
||||||
text-align: center;
|
div.style.width = `${settings.width}px`;
|
||||||
width: ${settings.width}px;
|
div.style.height = `${settings.height}px`;
|
||||||
height: ${settings.height}px;
|
div.style.display = 'block';
|
||||||
display: block;
|
|
||||||
`;
|
|
||||||
fragment.appendChild(div);
|
fragment.appendChild(div);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -22069,7 +22093,8 @@ const PDFViewerApplication = {
|
|||||||
disableBookmark = params.get("disablebookmark") ?? 'false';
|
disableBookmark = params.get("disablebookmark") ?? 'false';
|
||||||
disableEditing = params.get("disableediting") ?? 'false';
|
disableEditing = params.get("disableediting") ?? 'false';
|
||||||
kkhighlightAll = params.get("pdfhighlightall") ?? 'false';
|
kkhighlightAll = params.get("pdfhighlightall") ?? 'false';
|
||||||
watermarkTxt= params.get('watermarktxt') ?? 'false';
|
watermarkTxt = params.get('watermarktxt') ?? 'false';
|
||||||
|
configureWatermark(params);
|
||||||
try {
|
try {
|
||||||
file = new URL(file).href;
|
file = new URL(file).href;
|
||||||
} catch {
|
} catch {
|
||||||
@@ -24017,4 +24042,4 @@ if (document.readyState === "interactive" || document.readyState === "complete")
|
|||||||
|
|
||||||
export { PDFViewerApplication, AppConstants as PDFViewerApplicationConstants, AppOptions as PDFViewerApplicationOptions };
|
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}";
|
url = baseUrl + 'getCorsFile?urlPath=' + encodeURIComponent(Base64.encode(url)) + "&key=${kkkey}";
|
||||||
}
|
}
|
||||||
var viewerUrl = baseUrl + "pdfjs/web/viewer.html?file=" + encodeURIComponent(url);
|
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}');
|
var highlightEncoded = encodeURIComponent('${highlightall?js_string}');
|
||||||
viewerUrl += "&disablepresentationmode=${pdfPresentationModeDisable}";
|
viewerUrl += "&disablepresentationmode=${pdfPresentationModeDisable}";
|
||||||
viewerUrl += "&disableopenfile=${pdfOpenFileDisable}";
|
viewerUrl += "&disableopenfile=${pdfOpenFileDisable}";
|
||||||
@@ -61,7 +72,9 @@
|
|||||||
viewerUrl += "&disabledownload=${pdfDownloadDisable}";
|
viewerUrl += "&disabledownload=${pdfDownloadDisable}";
|
||||||
viewerUrl += "&disablebookmark=${pdfBookmarkDisable}";
|
viewerUrl += "&disablebookmark=${pdfBookmarkDisable}";
|
||||||
viewerUrl += "&disableediting=${pdfDisableEditing}";
|
viewerUrl += "&disableediting=${pdfDisableEditing}";
|
||||||
viewerUrl += "&watermarktxt=" + watermarkEncoded;
|
Object.keys(watermarkParams).forEach(function (name) {
|
||||||
|
viewerUrl += "&" + name + "=" + encodeURIComponent(watermarkParams[name]);
|
||||||
|
});
|
||||||
viewerUrl += "&pdfhighlightall=" + highlightEncoded;
|
viewerUrl += "&pdfhighlightall=" + highlightEncoded;
|
||||||
viewerUrl += "#page=${page}"; // ?c 确保数字不包含千位分隔符
|
viewerUrl += "#page=${page}"; // ?c 确保数字不包含千位分隔符
|
||||||
<#if "true" == pdfSidebarOpen>
|
<#if "true" == pdfSidebarOpen>
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import org.junit.jupiter.api.Test;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
@@ -35,6 +36,38 @@ public class PdfViewerCompatibilityTests {
|
|||||||
assertTrue(pdfTemplate.contains("viewerUrl += \"&pagemode=none\";"));
|
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
|
@Test
|
||||||
void shouldPreferPdfForOfficePreviewByDefault() throws IOException {
|
void shouldPreferPdfForOfficePreviewByDefault() throws IOException {
|
||||||
String properties = readResource("/application.properties");
|
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();
|
const body = await resp.text();
|
||||||
expect(body).toContain('不受信任');
|
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