0

I need generate Word document (.doc). Export HTML to Word Document with JavaScript. I have ready code which work fine with small images, but the problem is when I want to upload big and a few images. I have function "exportHTML", where is generating bodyDoc, this is source HTML which looks like exemple below. HTML is generating, with data which are get from frontend inputs. On the frontend I use Bootstrap 4.

To upload images I use on the frontend:

<input type="file" name="img[]" class="file" accept="image/*">
   <label for="PhotoPlate">Photo plate</label>
   <div class="input-group my-3">
      <input type="text" class="form-control" disabled placeholder="Upload File" id="file">
   <div class="input-group-append">
      <button type="button" class="browse btn btn-primary">Browse...</button>
   </div></div>
   <div class="ml-2 col-sm-6 preview">
      <img src="https://placehold.it/80x80" id="preview" class="img-thumbnail">
   </div>

And JavaScript:

 $('input[type="file"]').change(function(e) {
    var fileName = e.target.files[0].name;
    $("#file").val(fileName);

    var reader = new FileReader();
    reader.onload = function(e) {
        // get loaded data and render thumbnail.
        document.getElementById("preview").src = e.target.result;
    };
    // read the image file as a data URL.
    reader.readAsDataURL(this.files[0]);
});

To generate HTML code, where is images, I do something like that:

"<tr><th>Photo plate</th><td><img src=\"" + $("#file").val() + "\" width = \"300\" height =\"200\"></td></tr>"

I receive something like below:

        <style>@page{size:21cm 29.7cmt;  /* A4 */margin:1cm 1cm 1cm 1cm; /* Margins: 2.5 cm on each side */ mso-page-orientation: portrait; }@page Section1 { }div.Section1 { page:Section1; }{ border: 1px solid black; }</style>
    <div class=Section1><h1><center>Report</center></h1><p>Created Date: 7-6-2020</p>
<style>table,td,th { border: 1px solid #464545; text-align: left; font-family: Times New Roman, Times, serif; font-size: 16px; } table {border-collapse: collapse; width: 80%;}th,td {padding: 5px;}th { background-color: #D9D9D9;} </style>
    <table  align='center' style='margin: 0px auto;'><thead><tr><th style= 'font-size: 20px;' colspan=2><center>General Information</center></th></tr></thead><tbody><tr><th style= 'width: 40%'>Country</th><td>Poland</td></tr><tr><th>Name of Customer</th><td>Wind Service</td></tr><tr><th>Site</th><td>Dobieslaw</td></tr><tr><th>Turbine</th><td>Enercon</td></tr><tr><th>WTG no</th><td>B4</td></tr><tr><th>Hub height</th><td>85m</td></tr><tr><th>Blade manufacturer</th><td>TPI</td></tr><tr><th>Blade no</th><td>234</td></tr><tr><th>SET no</th><td>345</td></tr><tr><th>Technicians</th><td>undefined, undefined</td></tr><tr><th>Access Method</th><td>Rope Access</td></tr><tr><th>Date</th><td>Start date: 04/01/2020<br/>End date: 05/29/2020</td></tr>
<tr><th>Photo plate</th><td><img src="buy-me-min.png" width = "300" height ="200"></td></tr>
<tr><th>Additional comment</th><td></td></tr></tbody></table>
<br clear=all style='mso-special-character:line-break;page-break-before:always'><h1 style = " margin-bottom: 40px;"><center>Abreviations / Explanation</center></h1><p style="text-align:center;">
**<img src="AbreviationsExplanation.jpg" width = "720" height ="760">**
</p><br/><br clear=all style='mso-special-character:line-break;page-break-before:always'><br/>
<style>table {width: 100%;}</style><table><thead><tr><th colspan=6><center>Blade no: 234 </center></th></tr></thead><tbody><tr><th>Damage no.</th><th>Case no.</th><th>Distance from root  [m]</th><th>Location</th><th>Damage type</th><th>Size [cm]</th></tr><tr><td>No. 1</td><td>2</td><td>2</td><td>TE</td><td>Dirt</td><td>2</td></tr></tbody></table><br clear=all style='mso-special-character:line-break;page-break-before:always'><style>th { background-color: #BFBFBF;} td { background-color: #D9D9D9;} </style><table><thead><tr><th><h5 style='font-size:16px'>No. 1</h5></th><th>Case no: 2 </th></tr></thead><tbody><tr><td style= 'width: 50%'>Location: TE</td><td>Distance from root: 2[m]</td></tr><tr><td>Size: 2[cm]</td><td>Damage type: Dirt</td></tr><tr><th style= 'background-color: #8DB3E2' colspan=2>Existing damage condition:</th></tr><tr><td style= 'background-color: white'><center>
**<img src="buy-me-min.png" width = "340" height ="305">**
</center></td><td style= 'background-color: white'><center>
**<img src="buy-me-min.png" width = "340" height ="305">**
</center></td></tr><tr><th style= 'background-color: #8DB3E2' colspan=2>Area after cleaning: </tr></tbody></table><table style = 'width: 50%;'><tbody><tr><td style= 'background-color: white; border-top: none;' colspan=2><center>
**<img src="buy-me-min.png" width = "340" height ="305">**
</center></td></tr></tbody></table><br clear=all style='mso-special-character:line-break;page-break-before:always'>

In function exportHTML I used fileDownload.download to save my word document on my disk.

function exportHTML() {
    var bodyDoc = generateSourceHTML();

    var header = "<html xmlns:o='urn:schemas-microsoft-com:office:office' " +
        "xmlns:w='urn:schemas-microsoft-com:office:word' " +
        "xmlns='http://www.w3.org/TR/REC-html40'>" +
        "<head><meta charset='utf-8'><title>Export HTML to Word Document with JavaScript</title></head><body>";
    var footer = "</body></html>";
    var sourceHTML = header + bodyDoc + footer;

    var source = 'data:application/vnd.ms-word;charset=utf-8,' + encodeURIComponent(sourceHTML);
    var fileDownload = document.createElement("a");
    document.body.appendChild(fileDownload);
    fileDownload.href = source;
    fileDownload.download = 'Document.doc';
    fileDownload.click();
    document.body.removeChild(fileDownload);

}

How looks the problem? After generate in the world I see something like that:

enter image description here

Where is the problem. Is this a problem with browser local storage/cache. What I can to do? I tried convert this to base64 but there is the same problem for many and big size images.

1 Answers1

0

I tried converting HTML to word using below code

// jQuery html to word plugin function
if (typeof jQuery !== "undefined" && typeof saveAs !== "undefined") {
 (function($) {
    $.fn.wordExport = function(fileName) {
        fileName = typeof fileName !== 'undefined' ? fileName : "jQuery-Word-Export";
        var static = {
            mhtml: {
                top: "Mime-Version: 1.0\nContent-Base: " + location.href + "\nContent-Type: Multipart/related; boundary=\"NEXT.ITEM-BOUNDARY\";type=\"text/html\"\n\n--NEXT.ITEM-BOUNDARY\nContent-Type: text/html; charset=\"utf-8\"\nContent-Location: " + location.href + "\n\n<!DOCTYPE html>\n<html>\n_html_</html>",
                head: "<head>\n<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\">\n<style>\n_styles_\n</style>\n</head>\n",
                body: "<body>_body_</body>"
            }
        };
        var options = {
            maxWidth: 624
        };
        // Clone selected element before manipulating it
        var markup = $(this).clone();

        // Remove hidden elements from the output
        markup.each(function() {
            var self = $(this);
            if (self.is(':hidden'))
                self.remove();
        });

        // Embed all images using Data URLs
        var images = Array();
        var img = markup.find('img');
        for (var i = 0; i < img.length; i++) {
            // Calculate dimensions of output image
            var w = Math.min(img[i].width, options.maxWidth);
            var h = img[i].height * (w / img[i].width);
            // Create canvas for converting image to data URL
            var canvas = document.createElement("CANVAS");
            canvas.width = w;
            canvas.height = h;
            // Draw image to canvas
            var context = canvas.getContext('2d');
            context.drawImage(img[i], 0, 0, w, h);
            // Get data URL encoding of image
            var uri = canvas.toDataURL("image/png");
            $(img[i]).attr("src", img[i].src);
            img[i].width = w;
            img[i].height = h;
            // Save encoded image to array
            images[i] = {
                type: uri.substring(uri.indexOf(":") + 1, uri.indexOf(";")),
                encoding: uri.substring(uri.indexOf(";") + 1, uri.indexOf(",")),
                location: $(img[i]).attr("src"),
                data: uri.substring(uri.indexOf(",") + 1)
            };
        }

        // Prepare bottom of mhtml file with image data
        var mhtmlBottom = "\n";
        for (var i = 0; i < images.length; i++) {
            mhtmlBottom += "--NEXT.ITEM-BOUNDARY\n";
            mhtmlBottom += "Content-Location: " + images[i].location + "\n";
            mhtmlBottom += "Content-Type: " + images[i].type + "\n";
            mhtmlBottom += "Content-Transfer-Encoding: " + images[i].encoding + "\n\n";
            mhtmlBottom += images[i].data + "\n\n";
        }
        mhtmlBottom += "--NEXT.ITEM-BOUNDARY--";

        //TODO: load css from included stylesheet
        var styles = "";

        // Aggregate parts of the file together
        var fileContent = static.mhtml.top.replace("_html_", static.mhtml.head.replace("_styles_", styles) + static.mhtml.body.replace("_body_", markup.html())) + mhtmlBottom;

        // Create a Blob with the file contents
        var blob = new Blob([fileContent], {
            type: "application/msword;charset=utf-8"
        });
        saveAs(blob, fileName + ".doc");
    };
  })(jQuery);
 }  
 else {
 if (typeof jQuery === "undefined") {
    console.error("jQuery Word Export: missing dependency (jQuery)");
}
if (typeof saveAs === "undefined") {
    console.error("jQuery Word Export: missing dependency (FileSaver.js)");
  }
}


 jQuery(document).ready(function($) {
    $("a.word-export").click(function(event)      {
        $("#MainHTML").wordExport();
    });
});

Original Source : Convert html to word with images (Using Javascript OR Using jQuery plugin)

For sample purpose, I used 2.5Mb image and converted into base 64, which worked for me, here is the sample fiddle link

https://jsfiddle.net/7dxe5tm1/

If your images are more than 5mb try to compress them using C#/php/java etc or whatever back-end language you are using.

If you want to upload image and read it as base64 using HTML/javascript check this link https://stackoverflow.com/a/17711190/3559462

Code from the above link

function readFile() {

if (this.files && this.files[0]) {

  var FR= new FileReader();

   FR.addEventListener("load", function(e) {
     document.getElementById("img").src       = e.target.result;
    document.getElementById("b64").innerHTML = e.target.result;
  }); 

  FR.readAsDataURL( this.files[0] );
 }  
}document.getElementById("inp").addEventListener("change", readFile);

your HTML

<input id="inp" type='file'>
<p id="b64"></p>
<img id="img" height="150">
Vikas Lalwani
  • 1,041
  • 18
  • 29