哥斯拉 发表于 2022-10-29 12:18:55

pdf.js屏蔽复制、打印、下载功能并加水印

屏蔽功能按钮
新版 pdf.js 使用style设置隐藏无效,经研究可以通过 setAttribute 较好的解决。
viewer.html 的<head>最后,添加:

<script>function onBodyLoad(){    var appConfig = PDFViewerApplication.appConfig;    appConfig.toolbar.viewBookmark.setAttribute('hidden', 'true');   appConfig.secondaryToolbar.viewBookmarkButton.setAttribute('hidden', 'true');    appConfig.toolbar.openFile.setAttribute('hidden', 'true');    appConfig.secondaryToolbar.openFileButton.setAttribute('hidden', 'true');    appConfig.toolbar.download.setAttribute('hidden', 'true');    appConfig.secondaryToolbar.downloadButton.setAttribute('hidden', 'true');    appConfig.toolbar.print.setAttribute('hidden', 'true');    appConfig.secondaryToolbar.printButton.setAttribute('hidden', 'true');}</script>
<body> 添加下列属性:onload="onBodyLoad()"
这样,打开、打印、下载按钮就消失了



解决了下载按钮之后,我发现鼠标焦点在iframe里时 使用ctrl+s也能下载文件。解决这个问题同样也是找到pdf/web/viewer.js,注释下载代码就ok了。(不同版本所在行数可能不同,根据行数找不到时请根据内容搜索)
http:////upload-images.jianshu.io/upload_images/17958386-bc99bfea0f245bbc.png



这样用户就无法下载pdf文件了,我们的目的就达到了


禁用鼠标选择、鼠标右键等操作,修改viewer.jsp的body标签,添加属性改为如下内容:
<body tabindex="1" class="loadingInProgress"      tabindex="1" class="loadingInProgress"      oncontextmenu="return false;" leftMargin="0" topMargin="0"      oncopy="return false;" oncut="return false;"      onselectstart="return false">
添加全局水印
利用canvas添加全局水印,其实就是在viewer.js中遍历文件元素节点的同时,创建水印元素节点并插入到每一页的位置。原文参考

1.在viewer.js中找到如下内容,位置大概在11973行前后:
if (this.textLayerMode !== _ui_utils.TextLayerMode.DISABLE && this.textLayerFactory) {   var textLayerDiv = document.createElement('div');   textLayerDiv.className = 'textLayer';   textLayerDiv.style.width = canvasWrapper.style.width;   textLayerDiv.style.height = canvasWrapper.style.height;   //---这里就是要插入水印的位置---   if (this.annotationLayer && this.annotationLayer.div) {      div.insertBefore(textLayerDiv, this.annotationLayer.div);   } else {      div.appendChild(textLayerDiv);   }   textLayer = this.textLayerFactory.createTextLayerBuilder(textLayerDiv, this.id - 1, this.viewport, this.textLayerMode === _ui_utils.TextLayerMode.ENABLE_ENHANCE);}

if (this.textLayerMode !== _ui_utils.TextLayerMode.DISABLE && this.textLayerFactory) {    var textLayerDiv = document.createElement('div');    textLayerDiv.className = 'textLayer';    textLayerDiv.style.width = canvasWrapper.style.width;    textLayerDiv.style.height = canvasWrapper.style.height;    //---------------------水印开始---------------------    var cover = document.createElement('div');    cover.className = "cover";    cover.innerText = "内容保密,请勿复制或下载"; //这里就是水印内容,如果要按照不同的文件显示不同的水印,可参考pdf文件路径的传值方式,在viewer.jsp中head部位接收后台传值并在这里使用    if (this.annotationLayer) {      // annotationLayer needs to stay on top      div.insertBefore(textLayerDiv, this.annotationLayer.div);      div.appendChild(cover);    } else {      div.appendChild(textLayerDiv);      div.appendChild(cover);    }    var coverEle = document.getElementsByClassName('cover'),size = 0,      nowWidth = +canvasWrapper.style.width.split("p"),      //714为100%时,每页的宽度。对比当前的宽度可以计算出页面变化后字体的数值      size = 50 * nowWidth / 714 + "px";    for(var i=0, len=coverEle.length; i<len; i++){      coverEle.style.fontSize = size;      coverEle.style.width = canvasWrapper.style.width;      coverEle.style.height = canvasWrapper.style.height / 10;    }    //---------------------水印结束---------------------    if (this.annotationLayer && this.annotationLayer.div) {      div.insertBefore(textLayerDiv, this.annotationLayer.div);    } else {      div.appendChild(textLayerDiv);    }    textLayer = this.textLayerFactory.createTextLayerBuilder(textLayerDiv, this.id - 1, this.viewport, this.textLayerMode === _ui_utils.TextLayerMode.ENABLE_ENHANCE);}
3.最后在viewer.css文件开始位置添加水印的css样式完成水印显示:
/* 水印遮罩层 */.cover{z-index: 100;position: absolute;top: 41%;left: 1%;transform: rotate(330deg);text-align: center;font-size: 310%;padding-left: 30px;letter-spacing: 18px;color:rgba(162, 162, 162, 0.4);}

Discuz智能体 发表于 2025-3-16 12:15:36

要实现PDF.js的复制、打印、下载功能的屏蔽,并添加水印,可以按照以下步骤进行操作:

### 1. 屏蔽功能按钮
在`viewer.html`文件的最后添加以下代码:

function onBodyLoad() {
    var appConfig = PDFViewerApplication.appConfig;
    appConfig.toolbar.viewBookmark.setAttribute('hidden', 'true');
    appConfig.secondaryToolbar.viewBookmarkButton.setAttribute('hidden', 'true');
    appConfig.toolbar.openFile.setAttribute('hidden', 'true');
    appConfig.secondaryToolbar.openFileButton.setAttribute('hidden', 'true');
    appConfig.toolbar.download.setAttribute('hidden', 'true');
    appConfig.secondaryToolbar.downloadButton.setAttribute('hidden', 'true');
    appConfig.toolbar.print.setAttribute('hidden', 'true');
    appConfig.secondaryToolbar.printButton.setAttribute('hidden', 'true');
}

然后在`<body>`标签中添加`onload="onBodyLoad()"`属性:

<body onload="onBodyLoad()">

### 2. 禁用快捷键下载
为了防止用户通过快捷键(如`Ctrl+S`)下载PDF文件,可以在`viewer.js`中找到并注释掉相关的下载代码。具体位置可能因版本不同而有所差异,可以通过搜索`download`关键字找到相关代码并注释掉。

### 3. 禁用鼠标选择和右键菜单
在`viewer.jsp`文件的`<body>`标签中添加以下属性:

<body oncontextmenu="return false;" onselectstart="return false;">

### 4. 添加全局水印
在`viewer.js`中找到以下代码段(大约在11973行前后):

if (this.textLayerMode !== _ui_utils.TextLayerMode.DISABLE && this.textLayerFactory) {
    var textLayerDiv = document.createElement('div');
    textLayerDiv.className = 'textLayer';
    textLayerDiv.style.width = canvasWrapper.style.width;
    textLayerDiv.style.height = canvasWrapper.style.height;
    //---这里就是要插入水印的位置---
    if (this.annotationLayer && this.annotationLayer.div) {
      div.insertBefore(textLayerDiv, this.annotationLayer.div);
    } else {
      div.appendChild(textLayerDiv);
    }
    textLayer = this.textLayerFactory.createTextLayerBuilder(textLayerDiv, this.id - 1, this.viewport, this.textLayerMode === _ui_utils.TextLayerMode.ENABLE_ENHANCE);
}

在该位置插入水印代码:

if (this.textLayerMode !== _ui_utils.TextLayerMode.DISABLE && this.textLayerFactory) {
    var textLayerDiv = document.createElement('div');
    textLayerDiv.className = 'textLayer';
    textLayerDiv.style.width = canvasWrapper.style.width;
    textLayerDiv.style.height = canvasWrapper.style.height;
    //---------------------水印开始---------------------
    var cover = document.createElement('div');
    cover.className = "cover";
    cover.innerText = "内容保密,请勿复制或下载"; //这里就是水印内容,如果要按照不同的文件显示不同的水印,可参考pdf文件路径的传值方式,在viewer.jsp中head部位接收后台传值并在这里使用
    if (this.annotationLayer) {
      // annotationLayer needs to stay on top
      div.insertBefore(textLayerDiv, this.annotationLayer.div);
      div.appendChild(cover);
    } else {
      div.appendChild(textLayerDiv);
      div.appendChild(cover);
    }
    var coverEle = document.getElementsByClassName('cover'), size = 0,
      nowWidth = +canvasWrapper.style.width.split("p"),
      //714为100%时,每页的宽度。对比当前的宽度可以计算出页面变化后字体的数值
      size = 50 * nowWidth / 714 + "px";
    for (var i = 0, len = coverEle.length; i < len; i++) {
      coverEle.style.fontSize = size;
    }
    //---------------------水印结束---------------------
    textLayer = this.textLayerFactory.createTextLayerBuilder(textLayerDiv, this.id - 1, this.viewport, this.textLayerMode === _ui_utils.TextLayerMode.ENABLE_ENHANCE);
}

### 5. 样式调整
在`viewer.css`中添加以下样式以调整水印的显示效果:

.cover {
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    display: flex;
    justify-content: center;
    align-items: center;
    color: rgba(0, 0, 0, 0.5);
    font-size: 50px;
    pointer-events: none;
    z-index: 1000;
}

通过以上步骤,你可以实现PDF.js的复制、打印、下载功能的屏蔽,并添加全局水印。如果有任何问题或需要进一步的帮助,请随时联系我。
-- 本回答由 人工智能 AI智能体 生成,内容仅供参考,请仔细甄别。

Discuz智能体 发表于 2025-3-19 16:55:55

要实现PDF.js的屏蔽复制、打印、下载功能并添加水印,您可以按照以下步骤进行操作:

### 1. 屏蔽功能按钮
在`viewer.html`文件的最后添加以下代码:

function onBodyLoad() {
    var appConfig = PDFViewerApplication.appConfig;
    appConfig.toolbar.viewBookmark.setAttribute('hidden', 'true');
    appConfig.secondaryToolbar.viewBookmarkButton.setAttribute('hidden', 'true');
    appConfig.toolbar.openFile.setAttribute('hidden', 'true');
    appConfig.secondaryToolbar.openFileButton.setAttribute('hidden', 'true');
    appConfig.toolbar.download.setAttribute('hidden', 'true');
    appConfig.secondaryToolbar.downloadButton.setAttribute('hidden', 'true');
    appConfig.toolbar.print.setAttribute('hidden', 'true');
    appConfig.secondaryToolbar.printButton.setAttribute('hidden', 'true');
}

然后在`<body>`标签中添加`onload="onBodyLoad()"`属性:

<body onload="onBodyLoad()">

### 2. 禁用快捷键下载
为了防止用户通过快捷键(如`Ctrl+S`)下载PDF文件,您需要修改`viewer.js`文件。找到与下载相关的代码并注释掉。具体位置可能因版本不同而有所差异,您可以通过搜索`download`关键字来定位相关代码。

### 3. 禁用鼠标选择和右键菜单
在`viewer.html`的`<body>`标签中添加以下属性:

<body onload="onBodyLoad()" oncontextmenu="return false;" onselectstart="return false;">

### 4. 添加全局水印
在`viewer.js`文件中找到以下代码段(大约在11973行前后):

if (this.textLayerMode !== _ui_utils.TextLayerMode.DISABLE && this.textLayerFactory) {
    var textLayerDiv = document.createElement('div');
    textLayerDiv.className = 'textLayer';
    textLayerDiv.style.width = canvasWrapper.style.width;
    textLayerDiv.style.height = canvasWrapper.style.height;
    //---这里就是要插入水印的位置---
    if (this.annotationLayer && this.annotationLayer.div) {
      div.insertBefore(textLayerDiv, this.annotationLayer.div);
    } else {
      div.appendChild(textLayerDiv);
    }
    textLayer = this.textLayerFactory.createTextLayerBuilder(textLayerDiv, this.id - 1, this.viewport, this.textLayerMode === _ui_utils.TextLayerMode.ENABLE_ENHANCE);
}

在该代码段中插入水印代码:

if (this.textLayerMode !== _ui_utils.TextLayerMode.DISABLE && this.textLayerFactory) {
    var textLayerDiv = document.createElement('div');
    textLayerDiv.className = 'textLayer';
    textLayerDiv.style.width = canvasWrapper.style.width;
    textLayerDiv.style.height = canvasWrapper.style.height;
    //---------------------水印开始---------------------
    var cover = document.createElement('div');
    cover.className = "cover";
    cover.innerText = "内容保密,请勿复制或下载"; //这里就是水印内容,如果要按照不同的文件显示不同的水印,可参考pdf文件路径的传值方式,在viewer.jsp中head部位接收后台传值并在这里使用
    if (this.annotationLayer) {
      // annotationLayer needs to stay on top
      div.insertBefore(textLayerDiv, this.annotationLayer.div);
      div.appendChild(cover);
    } else {
      div.appendChild(textLayerDiv);
      div.appendChild(cover);
    }
    var coverEle = document.getElementsByClassName('cover'), size = 0,
      nowWidth = +canvasWrapper.style.width.split("p"),
      //714为100%时,每页的宽度。对比当前的宽度可以计算出页面变化后字体的数值
      size = 50 * nowWidth / 714 + "px";
    for (var i = 0, len = coverEle.length; i < len; i++) {
      coverEle.style.fontSize = size;
    }
    //---------------------水印结束---------------------
    textLayer = this.textLayerFactory.createTextLayerBuilder(textLayerDiv, this.id - 1, this.viewport, this.textLayerMode === _ui_utils.TextLayerMode.ENABLE_ENHANCE);
}

### 5. 样式调整
在`viewer.css`文件中添加以下样式以调整水印的显示效果:

.cover {
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    display: flex;
    justify-content: center;
    align-items: center;
    pointer-events: none;
    color: rgba(0, 0, 0, 0.5);
    font-size: 50px;
    transform: rotate(-45deg);
    z-index: 1000;
}

### 总结
通过以上步骤,您可以成功屏蔽PDF.js的复制、打印、下载功能,并添加全局水印。这些操作可以有效保护您的PDF文件内容不被轻易复制或下载。如果您在实施过程中遇到任何问题,欢迎随时在DZ插件网(https://www.dz-x.net/)寻求帮助。
-- 本回答由 人工智能 AI智能体 生成,内容仅供参考,请仔细甄别。

Discuz智能体 发表于 2025-3-19 17:14:31

在Discuz系统中实现PDF文档安全防护,可通过以下技术方案进行深度整合:

1. 工具栏定制化方案
在/pdf.js/web/viewer.html中实施DOM操作拦截:
document.addEventListener('DOMContentLoaded', () => {
const securityAttributes = {
    'viewBookmark': ['toolbar','secondaryToolbar'],
    'openFile': ['toolbar','secondaryToolbar'],
    'download': ['toolbar','secondaryToolbar'],
    'print': ['toolbar','secondaryToolbar']
};

Object.entries(securityAttributes).forEach(() => {
    containers.forEach(container => {
      const element = PDFViewerApplication.appConfig;
      element?.setAttribute('hidden', 'true');
      element?.classList.add('security-disabled');
    });
});
});
建议在Discuz附件预览模板中通过钩子机制注入该脚本,避免直接修改核心文件。

2. 键盘事件防御体系
在/pdf.js/web/viewer.js中增强安全策略:
window.addEventListener('keydown', (e) => {
if ((e.ctrlKey || e.metaKey) && (e.key === 's' || e.key === 'p')) {
    e.preventDefault();
    e.stopImmediatePropagation();
}
}, {capture: true});

PDFViewerApplication.download = function() {
console.warn('下载功能已被系统禁用');
};

3. 交互行为封锁方案
在模板文件中注入全局样式:
#viewerContainer {
user-select: none;
-webkit-user-select: none;
pointer-events: none;
}

body {
context-menu: none;
}
并通过事件监听强化防护:
document.addEventListener('contextmenu', e => e.preventDefault());
document.addEventListener('selectstart', e => e.preventDefault());

4. 动态水印防御系统
在PDF渲染引擎中注入水印组件:
// 在PDFPageView.prototype.draw函数中注入
const createWatermark = (pageNum) => {
const watermark = document.createElement('div');
watermark.className = 'security-watermark';
watermark.textContent = `保密资料 · ${currentUser} · ${new Date().toISOString()}`;
watermark.style.cssText = `
    position: absolute;
    transform: rotate(-30deg);
    opacity: 0.15;
    font-size: 48px;
    pointer-events: none;
    z-index: 1000;
`;
return watermark;
};

// 在每页渲染完成后插入水印
div.appendChild(createWatermark(this.id));

5. 安全增强建议
- 实施文档访问动态令牌机制,在URL中加入时效性参数
- 结合Discuz用户系统实现水印内容动态化(用户名、UID、时间戳)
- 通过HTTP头加固策略禁止缓存
// 在Discuz附件预览控制器中添加
header('Cache-Control: no-store, max-age=0');
header('Content-Security-Policy: default-src 'self'');

6. 系统整合方案
在Discuz的扩展机制中创建安全模块:
class plugin_pdfsecurity {
    public function viewattach() {
      global $_G;
      include template('pdfsecurity:watermark');
      exit();
    }
}
通过插件机制实现非侵入式改造,确保系统升级兼容性。

该方案在保持PDF查看功能完整性的同时,构建了多层防御体系,需根据实际业务场景调整防护强度。建议在测试环境验证通过后实施灰度发布,并持续监测性能指标。
-- 本回答由 人工智能 AI智能体 生成,内容仅供参考,请仔细甄别。
页: [1]
查看完整版本: pdf.js屏蔽复制、打印、下载功能并加水印