【问题标题】:DataTables image (or at least image title) export to PDFDataTables 图像(或至少图像标题)导出为 PDF
【发布时间】:2016-01-29 17:42:53
【问题描述】:

使用 DataTables 和 Buttons(NOT TableTools,已停用)扩展。有些单元格有进度条和小图标。有没有办法将这些图像(或至少它们的标题)导出为 PDF?在此页面上发现了一些可能的 hack,但它们都是针对已退役的 TableTools。

检查了https://datatables.net/reference/button/pdfhttps://datatables.net/reference/api/buttons.exportData%28%29,但找不到任何实现此目标的方法。通过添加此代码进行测试:

stripHtml: false

但整个 HTML 代码(如 img src=...)包含在 PDF 文件中而不是图像中。

如果无法导出图片,有没有办法至少导出每张图片的 alt 或 title 属性?这样就够了。

【问题讨论】:

    标签: pdf datatables-1.10


    【解决方案1】:

    我假设您使用的是 pdfHtml5。 dataTables 使用 pdfmake 来导出 pdf 文件。当在浏览器中使用 pdfmake 时,它​​需要将图像定义为 base64 编码的 dataurl。

    示例:您在某些行的第一列中呈现了<img src="myglyph.png"> - 这些字形应该包含在 PDF 中。首先创建一个Image 对字形的引用:

    var myGlyph = new Image();
    myGlyph.src = 'myglyph.png';
    

    在你的customize 函数中你现在必须

    1) 构建一个字典,其中包含应包含在 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 节点部分。

    另请参阅

    【讨论】:

    • 感谢您的详细解答。我是否应该为每张图片添加相同的代码(if (doc.content[1].table.body[i][0].text == '&lt;img src="myglyph.png"&gt;...?问题是我事先不知道表格中将包含哪些图片。使用代码的应用程序是某种类型的计算器;因此,数字图片和图片名称的数量取决于最终的计算结果。
    • @MindaugasLi,是的!对您要替换的每个 &lt;img&gt; 进行该测试,记住 table.body[i][0] 是 col0,table.body[i][1] col 2 等等。您不必创建字典,大多数情况下相同的字形/图像不会重复 1000 次 - 您可以直接使用 dataUrl -> doc.content[1].table.body[i][0].image = getBase64Image(myGlyph) 但随后 PDF 的大小可以显着增加。
    • @davidkonrad 你能帮我解决这个问题吗? stackoverflow.com/questions/44951044/…
    【解决方案2】:

    由于没有收到任何建议,我不得不进行修改以按照我想要的方式格式化 PDF 文件。

    如果有人遇到同样的问题,您可以使用隐藏跨度在图像本身附近显示图像 alt/title。我确信这不是最佳做法,但它会成功。所以代码看起来像:

    <img src='image.png' alt='some_title'/><span class='hidden'>some_title</span>
    

    这样数据表将只显示图像,而 PDF 文件将包含您需要的文本。

    【讨论】:

      【解决方案3】:

      这是我的代码!

      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

      【讨论】:

        【解决方案4】:

        除了davidkonrad's answer。我动态创建了所有 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;
            }
        
        }
        

        【讨论】:

        • 你在 davidkonrad 的回答中到底在哪里?谢谢!
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-07-08
        • 2019-09-25
        • 1970-01-01
        相关资源
        最近更新 更多