python - 使用 Django Python 下载带有水印的 PDF 格式的动态 html
问题描述
我正在尝试创建一个测验网络应用程序,用户可以在其中在线或离线进行测验。在离线模式下,用户应该能够单击一个按钮并下载带有图像和水印的 pdf 内容。我的动态 html 内容还包含使用 Mathjx 和 WIRIS 插件打印的数学方程。
我尝试了以下方法,但是
- 它的渲染速度超级慢
- 我无法在对角线中间打印水印。
我也尝试过使用 jquery/canvas 进行打印,但由于 html 是动态生成的,因此打印不起作用。这可以使用 jquery 和一些 javascript 包来实现吗?
如果可能,请建议一种更快的方法。此外,当我单击 时,下载文件大约需要 15 秒。我想使用 ajax 方法来显示正在进行但无法实现。任何帮助表示赞赏。
class GeneratePdf(View):
def get(self, request, *args, **kwargs):
#template = get_template('dashboard/exam-pdf.html')
quizid = request.GET.get('quizid')
quiz = Quiz.objects.get(id=quizid)
questions= #Rendering Questions from model with images and MCQ Options
print("link clicked")
context = {
'questions': questions,
'essayquestions': essayquestions,
'quizid':quizid,
'quiz': quiz
}
pdf = render_to_pdf('dashboard/exam-pdf.html',context)
#rendering the template
return HttpResponse(pdf, content_type='application/pdf')
我的考试-pdf.html
{% extends 'base.html' %}
{% load static %}
{% block stylecss %}
<style>
@page {
size: "A4";
background-image: url('http://127.0.0.1:8000/static/images/watermark.PNG');
@frame header_frame { /* Static Frame */
-pdf-frame-content: header_content;
left: 30pt; width: 512pt; top: 10pt; height: 30pt;
}
@frame content_frame { /* Content Frame */
left: 30pt; width: 512pt; top: 30pt; height: 632pt;
background-color: #c48a8a;
}
@frame footer_frame { /* Another static Frame */
-pdf-frame-content: footer_content;
left: 30pt; width: 512pt; top: 772pt; height: 20pt;
}
}
</style>
{% endblock %}
{% block content %}
<div id="header_content">{{quiz.category.subjectDescr}}
</div>
<div id="footer_content">Page <pdf:pagenumber>
of <pdf:pagecount>
</div>
{% for question in questions %}
<div class="row" >
<div id="waterMarkContent">
{%block page_body%}
<img src="http://127.0.0.1:8000/static/images/watermark.PNG" width="1.5cm">
{%endblock%}
</div>
<div class="col-md-10" >
<input type=hidden name="question_id" value="{{ question.id }}" class="question_id">
<div class="panel-heading">
<p class="panel-title mb-2 mt-2" >
<li style="list-style-type: none;" class="mb-1 mt-1"><span style="padding-right:5px;text-decoration:underline">Question #{{forloop.counter}}:</span><strong> {% autoescape off %}{{ question.content }}{% endautoescape %} </strong></li>
<div id="waterMarkContent">
<img src="http://127.0.0.1:8000/static/images/watermark.PNG" width="1.5cm">
</div>
{% if question.figure %}
<div class="row mb-1">
<img src="{{ question.figure.url }}" alt="{{ question.content }}" />
</div>
{% endif %}
{% if question.questionmarks %}
<div class="row ml-1" >
<p style="font-size:0.8rem"><b>Marks :</b> {{ question.questionmarks }}</p>
</div>
{% endif %}
</div>
<div class="panel-body ">
<ul >
{% regroup question.answer_set.all by get_content_display as answer_list %}
{% for answers in answer_list %}
<ol>
<span>{{ section.grouper }}</span>
{% for answer in answers.list %}
<li class="list-group-item quiz-answers" >
<span><label for="id_answers_0">
{{answer.content}} </label> </span>
</li>
{% endfor %}
</ol>
{% endfor %}
</ul>
</div>
</div>
</div>
<hr>
{% endfor %}
{% if essayquestions %}
{% for question in essayquestions %}
<div class="row mt-2 mb-4 shadow-1 text-left">
<div class="col-md-10">
<input type=hidden name="question_id" value="{{ question.id }}" class="question_id">
<div class="panel-heading">
<p class="panel-title mb-1" >
<li style="list-style-type: none;"><strong> {% autoescape off %}{{ question.content }}{% endautoescape %} </strong></li>
<div class="row mb-1">
{% if question.figure %}
<img src="{{ question.figure.url }}" alt="{{ question.content }}" />
{% endif %}
</div>
{% if question.questionmarks %}
<div class="row mb-1 ml-1" >
<p style="font-size:0.8rem"><b>Marks :</b> {{ question.questionmarks }}</p>
</div>
{% endif %}
</p>
<div class="panel-body mb-2">
<ul class="list-group mb-2" style="list-style-type: none;">
<li class="list-group-item quiz-answers mb-1">
<span><textarea name="answers" cols="40" rows="5" style="width:100%" id="answer_{{question.id}}" required>
</textarea> </span>
</li>
</ul>
</div>
</div>
</div>
</div>
<hr>
{% endfor %}
{% endif %}
</div>
</div>
{% endblock %}
{% block scripts %}
<script src="https://www.wiris.net/demo/plugins/app/WIRISplugins.js?viewer=image"></script>
<script type='text/javascript' async src='https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.5/MathJax.js?config=TeX-MML-AM_CHTML'></script>
<script>
function tex2img(formula, callback) {
MathJax.Hub.Queue(function () {
var wrapper = MathJax.HTML.Element("span", {}, formula);
MathJax.Hub.Typeset(wrapper, function () {
var svg = wrapper.getElementsByTagName("svg")[0];
svg.setAttribute("xmlns", "http://www.w3.org/2000/svg");
var image = new Image();
image.src = 'data:image/svg+xml;base64,' + window.btoa(unescape(encodeURIComponent(svg.outerHTML)));
image.onload = function () {
var canvas = document.createElement('canvas');
canvas.width = image.width;
canvas.height = image.height;
var context = canvas.getContext('2d');
context.drawImage(image, 0, 0);
var img = '<img src="' + canvas.toDataURL('image/png') + '"/>';
callback(img);
};
});
})
}
function render() {
var dom = document.getElementById("math-tex");
tex2img(dom.innerText, function (output) {
dom.innerHTML = output
});
}
</script>
<script type="text/javascript">
function updateMathContent(s) {
var math = MathJax.Hub.getAllJax("mathdiv")[0];
MathJax.Hub.Queue(["Text", math, s]);
}
Array.from(document.querySelectorAll('.watermarked')).forEach(function(el) {
el.dataset.watermark = (el.dataset.watermark + ' ').repeat(300);
});
</script>
{% endblock %}
实用程序.py
从 io 导入 BytesIO 从 django.http 导入 HttpResponse 从 django.template.loader 导入 get_template
从 xhtml2pdf 导入比萨
def render_to_pdf(template_src, context_dict={}):
template = get_template(template_src)
html = template.render(context_dict)
result = BytesIO()
pdf = pisa.pisaDocument(BytesIO(html.encode("UTF-8")), result)
if not pdf.err:
return HttpResponse(result.getvalue(), content_type='application/pdf')
return None
解决方案
推荐阅读
- python - 当数据既连续又离散时,如何使用 hmmlearn 处理(半)隐马尔可夫模型?
- node.js - 我可以使用 Typescript 在 Express 中使用 process.env.FOO 初始化静态只读类字段吗?
- c++ - Visual Studio 2019 C++ 对概念的支持 - 编译成功但出现错误:为什么?
- android - 我已将应用程序上传到 google play 商店。但它不支持设备华为和其他手机。会是什么呢?这是我的清单
- python - 如何通过字符串访问熊猫数据框?
- c++ - 如何正确分配和解除分配向量图
- flutter - 如何在 Flutter 中制作不换行的多行 TextField?
- javascript - 避免 vueJS 中的 props 突变
- java - NodeJs 使用 pbkdf2Sync 加密并在 java 中解密
- xpath - 具有多个后代条件的 Xpath