使用数据表和按钮(NOT TableTools,已停用)扩展。有些单元格有进度条和小图标。有没有办法将这些图像(或至少它们的标题)导出为 PDF?在此页面上发现了一些可能的黑客攻击,但所有这些都是针对退休的 TableTools 的。
检查https://datatables.net/reference/button/pdf和https://datatables.net/reference/api/buttons.exportData%28%29但找不到任何方法来实现这个目标.通过添加此代码进行测试:
stripHtml: false
但是整个 HTML 代码(如 img src=...)包含在 PDF 文件中而不是图像中。
如果无法导出图片,有没有办法至少导出每张图片的 alt 或 title 属性?这样就够了。
我假设您使用的是 pdfHtml5。 dataTables 使用 pdfmake 来导出 pdf 文件。当在浏览器中使用 pdfmake 时,它需要将图像定义为 base64 编码的数据 url。
示例:您在某些行的第一列中呈现了
<img src="myglyph.png">
- 这些字形应包含在 PDF 中。首先创建一个 Image
引用字形 :
var myGlyph = new Image();
myGlyph.src = 'myglyph.png';
在你的
customize
功能中你现在必须
1) 构建一个dictionary,其中包含应包含在 PDF 中的所有图像
2)用
text
节点替换image
节点以引用图像
buttons : [
{
extend : 'pdfHtml5',
customize: function(doc) {
//ensure doc.images exists
doc.images = doc.images || {};
//build dictionary
doc.images['myGlyph'] = getBase64Image(myGlyph);
//..add more images[xyz]=anotherDataUrl here
//when the content is <img src="myglyph.png">
//remove the text node and insert an image node
for (var i=1;i<doc.content[1].table.body.length;i++) {
if (doc.content[1].table.body[i][0].text == '<img src="myglyph.png">') {
delete doc.content[1].table.body[i][0].text;
doc.content[1].table.body[i][0].image = 'myGlyph';
}
}
},
exportOptions : {
stripHtml: false
}
}
这里是一个
getBase64Image
函数的例子
function getBase64Image(img) {
var canvas = document.createElement("canvas");
canvas.width = img.width;
canvas.height = img.height;
var ctx = canvas.getContext("2d");
ctx.drawImage(img, 0, 0);
return canvas.toDataURL("image/png");
}
如果您只想在 PDF 中显示图像的
title
- 或者想以任何其他方式操作 PDF 的文本内容 - 那么它会更容易一些。每一行每一列的内容都可以通过exportOptions.format.body
回调进行格式化:
buttons : [
{
extend : 'pdfHtml5',
exportOptions : {
stripHtml: false
format: {
body: function(data, col, row) {
var isImg = ~data.toLowerCase().indexOf('img') ? $(data).is('img') : false;
if (isImg) {
return $(data).attr('title');
}
return data;
}
}
}
]
format.body
不能与图像一起使用的原因是它只让我们将数据传回PDF文档的text
节点部分。
另见
由于没有收到任何建议,我不得不进行破解以使 PDF 文件按照我想要的方式格式化。
如果有人遇到同样的问题,您可以使用隐藏跨度在图像本身附近显示图像 alt/title。我敢肯定这不是最佳做法,但可以解决问题。所以代码看起来像:
<img src='image.png' alt='some_title'/><span class='hidden'>some_title</span>
这样数据表将只显示图像,而 PDF 文件将包含您需要的文本。
这是我的密码!
HTML
<div class="dt-btn"></div>
<table>
<thead><tr><th>No</th><th>IMAGE</th><th>NOTE</th></tr></thead>
<tbody>
<tr>
<td>{{$NO}}</td>
<td>{{$imgSRC}}</td>
<td>{{$NAME}}<br />
{{$GRADE}}<br />
{{$PROFILE}}<br />
{{$CODE}}<br />
</td>
</tr>
</tbody>
</table>
JavaScript
$.extend( true, $.fn.dataTable.defaults, {
buttons: [{
text: '<i class="bx bx-download font-medium-1"></i><span class="align-middle ml-25">Download PDF</span>',
className: 'btn btn-light-secondary mb-1 mx-1 dnPDF',
extend: 'pdfHtml5',
pageSize: 'A4',
styles: {
fullWidth: { fontSize: 11, bold: true, alignment: 'left', margin: [0,0,0,0] }
},
action: function ( e, dt, node, config ) {
var that = this;
setTimeout( function () {
$.fn.dataTable.ext.buttons.pdfHtml5.action.call(that, e, dt, node, config);
$( ".donePDF" ).remove();
$( ".dnPDF" ).prop("disabled", false);
}, 50);
},
customize: function(doc) {
doc.defaultStyle.fontSize = 11;
doc.defaultStyle.alignment = 'left';
doc.content[1].table.dontBreakRows = true;
if (doc) {
for (var i = 1; i < doc.content[1].table.body.length; i++) {
// 1st Column - display IMAGE
var imgtext = doc.content[1].table.body[i][0].text;
delete doc.content[1].table.body[i][0].text;
jQuery.ajax({
type: "GET",
dataType: "json",
url: "{{route('base64')}}",
data: { src: imgtext },
async: false,
success: function(resp) {
//console.log(resp.data);
doc.content[1].table.body[i][0] = {
margin: [0, 0, 0, 3],
alignment: 'center',
image: resp.data,
width: 80,
height: 136
};
}
});
// 2nd Column - display NOTE(4 line)
var bodyhtml = doc.content[1].table.body[i][1].text;
var bodytext = bodyhtml.split("\n");
var bodystyle = []
for (var j = 0; j < bodytext.length; j++) {
switch(j) {
case 0:
// NAME
var _text = { margin:[0, 0, 0, 3], color:"#000000", fillColor:'#ffffff', bold:true, fontSize:13, alignment:'center', text:bodytext[j] };
break;
case 1:
// GRADE
var _text = { margin:[0, 0, 0, 3], color:"blue", fillColor:'#ffffff', bold:false, fontSize:11, alignment:'left', text:bodytext[j] };
break;
case 3:
// CODE
var _text = { margin:[0, 0, 0, 3], color:"#000000", fillColor:'#ffffff', bold:true, fontSize:11, alignment:'left', text:bodytext[j] };
break;
default:
// OTHERS
var _text = { margin:[0, 0, 0, 3], color:"#000000", fillColor:'#ffffff', bold:false, fontSize:11, alignment:'left', text:bodytext[j] };
break;
}
bodystyle[j] = _text;
};
doc.content[1].table.body[i][1] = bodystyle;
}
}
},
exportOptions: {
columns: [ 1, 2 ],
stripNewlines: false,
stripHtml: true,
modifier: {
page: 'all' // 'all', 'current'
},
}
}],
columns: [
{ className: 'iNo', orderable: true, visible: true},
{ className: 'iIMG', orderable: false, visible: false },
{ className: 'iPDF', orderable: false, visible: false, responsivePriority: 10001 } ]
});
var table = $('#table').DataTable();
table.buttons().container().appendTo('.dt-btn');
$('.dnPDF').on('click', function(){
$(this).append('<span class="spinner-border spinner-border-sm donePDF" role="status" aria-hidden="true"></span>').closest('button').attr('disabled','disabled');
});
$.fn.dataTable.Buttons.defaults.dom.container.className = '';
$.fn.dataTable.Buttons.defaults.dom.button.className = 'btn';
PHP
public function base64(Request $request)
{
$request->validate([
'src' => 'required|string'
]);
$fTYPE = pathinfo($request->src, PATHINFO_EXTENSION);
$fDATA = @file_get_contents($request->src);
$imgDATA = base64_encode($fDATA);
$imgSRC = 'data:image/' . $fTYPE . ';base64,'.$imgDATA;
$error = ($imgDATA!='') ? 0 : 1;
$msg = ($error) ? 'Error' : 'Success';
return response()->json([ 'msg' => $msg, 'error'=> $error, 'data' => $imgSRC]);
}
[样本][1]:https://i.stack.imgur.com/35Wlm.jpg
除了davidkonrad的回答。我动态创建了所有 base64 图像并在 Datatables pdfmake 中使用它们,如下所示:
for (var i = 1; i < doc.content[2].table.body.length; i++) {
if (doc.content[2].table.body[i][1].text.indexOf('<img src=') !== -1) {
html = doc.content[2].table.body[i][1].text;
var regex = /<img.*?src=['"](.*?)['"]/;
var src = regex.exec(html)[1];
var tempImage = new Image();
tempImage.src = src;
doc.images[src] = getBase64Image(tempImage)
delete doc.content[2].table.body[i][1].text;
doc.content[2].table.body[i][1].image = src;
doc.content[2].table.body[i][1].fit = [50, 50];
}
//here i am removing the html links so that i can use stripHtml: true,
if (doc.content[2].table.body[i][2].text.indexOf('<a href="details.php?') !== -1) {
html = $.parseHTML(doc.content[2].table.body[i][2].text);
delete doc.content[2].table.body[i][1].text;
doc.content[2].table.body[i][2].text = html[0].innerHTML;
}
}
基本思维过程(可以应用于任何堆栈,我使用的是.net)
此方法使用数据表导出选项的正交键(请参阅数据表文档)
<td>
中,声明“data-filter”,如图所示只需设置“data-filter”即可在导出的 pdf/excel 中获取图像标题,除了 exportOptions 之外不需要其他更改(跳过自定义数据表的关键更改)
将“data-filter”设置为带有附加数据的base64字符串,如下
<td>
使用标记语言获取图像(也可以使用纯javascript)
如图所示从窗口的图像键获取数据过滤器值(base64 字符串/图像标题)(硬编码数字表示存储数据过滤器的数据表的列)
删除窗口的文本键
添加图像键并将在上面的点中提取的 base64 字符串/标题分配给图像键。
解决这个问题的相关实际代码行(请根据自己的堆栈更改)
// jQuery
1. @Scripts.Render("~/Assets/Plugins/datatables-exs/js/pdfmake.min.js?v=" + DateTime.Now.Ticks.ToString())//----------make sure to include this min.js file
2. Please apply datatable according to your approach
var table = $('#datatable').DataTable({
lengthChange: true,
dom: 'Blfrtip',
lengthMenu: [
[10, 25, 50, 100, 500, -1],
[10, 25, 50, 100, 500, 'All'],
],
order: [[4, "desc"]],
buttons: [
{ extend: 'copy', text: 'Copy to clipboard', className: 'btn btn-primary' },
{
extend: 'excel', text: 'Download Excel', className: 'btn btn-danger',
exportOptions: {
columns: ':not(.tbl-op)'
}
},
{
extend: 'pdfHtml5', text: 'Download Pdf', className: 'btn btn-warning',
customize: function (window) {//---------------------------------------window contains table data and styles this callback is called on download pdf button click
if (window) {
window.pageSize = "A2";//-------------------------------setting various style and pdf values(reference http://pdfmake.org/#/gettingstarted)
window.pageOrientation= 'portrait';
window.defaultStyle.fontSize = '10';
window.margin = [0, 0, 0, 0];
window.alignment = 'center';
for (var i = 1; i < window.content[1].table.body.length; i++) {//-----traversing entire table data
var img1 = window.content[1].table.body[i][6].text;//-------getting base64 string stored in <td> in data-filter used as orthogonal
var img2 = window.content[1].table.body[i][7].text;//-------6 and 7 are column of tables where image is stored
delete window.content[1].table.body[i][6].text;//-----------deleting text key and adding image key (reference http://pdfmake.org/#/gettingstarted)
delete window.content[1].table.body[i][7].text;
window.content[1].table.body[i][6].image = img1;
window.content[1].table.body[i][6].width = 100;//-----------use debugger to know more about window
window.content[1].table.body[i][6].height = 100;
window.content[1].table.body[i][7].image = img2;
window.content[1].table.body[i][7].width = 100;
window.content[1].table.body[i][7].height = 100;
}
}
},
exportOptions: {
columns: ':not(.tbl-op)',
orthogonal: 'filter' /*Do not change filter as this will break excel export for column*///-----------------important
}
}
],
"fnRowCallback": function (nRow, aData, iDisplayIndex) {
$("td:first", nRow).html(iDisplayIndex + 1);
return nRow;
}
});
table.buttons().container().appendTo('#datatable_wrapper .col-md-6:eq(0)');
table.on('order.dt search.dt', function () {
let i = 1;
table.cells(null, 0, { search: 'applied', order: 'applied' }).every(function (cell) {
this.data(i++);
});
}).draw();
// cshtml 页面
3.
@if (!string.IsNullOrWhiteSpace(Obs.Media1))
{
// -------- below line append base64 string to data:image/jpeg;base64,(remember comma)
<td data-filter="@("data:image/jpeg;base64," + ToBase64String(----inser image path here----))"><img src="@(----inser image path here----)" class="img-thumbnail" width="150" /></td>
}
else
{
<td>No Image</td>
}
4. @functions{//----------------------------------------------marked up c# function to get base64 image string
public string ToBase64String(string path)
{
byte[] imageArray = System.IO.File.ReadAllBytes(Server.MapPath(path));//----server.mappath is imporetant here to get absolute path ...relative path no workinh
string base64Str = Convert.ToBase64String(imageArray);
return base64Str;
}
}