以下の tiff_to_pdf()、conv_tiff_arrays2pdf()の通りです。
tiff.js、jsPDFだけでなく、javascriptによるbinary処理の振り返りになります。
参考url
html + javascript
<!DOCTYPE html> <html lang="ja"> <head> <meta charset="utf-8"> <style> body {font-family: "ヒラギノ角ゴ ProN W3", HiraKakuProN-W3, 游ゴシック, "Yu Gothic", Meiryo, Verdana, Helvetica, Arial, sans-serif; } h1 {font-size :x-large; padding :0; margin :5px; } table {border-collapse:collapse; } th,td {border :1px solid #555; white-space :nowrap; padding :0 10px; } th {font-weight :normal; background-color:#f0f8ff; } th.zuban {resize :horizontal; width :400px; overflow :hidden; } tbody textarea{resize :none; width :100%; height :100%; } #thumb_nails{margin :10px; } .pdf_basename{width :250px } </style> </head> <body> <h1>SCAN TIFF IMAGE → PDF</h1> 「download」ボタンをクリックし、少々、お待ちください <table> <thead> <tr> <th>PDFファイル名</th><th class="zuban">図番</th><th></th> </tr> </thead> <tbody> <tr> <td> <input type="text" class="pdf_basename" value="○○○マニュアル">.pdf </td> <td><textarea>HOGE</textarea></td> <td><button type="button">download</button></td> </tr> <tr> <td> <input type="text" class="pdf_basename" value="△△△マニュアル">.pdf </td> <td><textarea>ZUMEN1 ZUMEN2 ZUMEN3</textarea></td> <td><button type="button">download</button></td> </tr> </tbody> </table> <div id="thumb_nails"></div> <!-- https://github.com/seikichi/tiff.js --> <script src="tiff.min.js"></script> <!-- https://github.com/parallax/jsPDF --> <script src="jspdf.umd.min.js" ></script> <script> "strict"; const req_url_base = "http://192.168.56.114:8080/scan/zumens_2.dat"; let btn_elms = document.getElementsByTagName("button"); for (let btn_elm of btn_elms) { btn_elm.addEventListener("click",(e)=>{ tiff_to_pdf(e.target) }); } const tiff_to_pdf=(btn_elm)=>{ let tr_elm = btn_elm.parentNode.parentNode; let pdf_basename = tr_elm.children[0].children[0].value.trim(); pdf_basename = pdf_basename.replace(/[\s\/\\\.\?]/g,"_"); let zumens_str = tr_elm.children[1].children[0].value.trim(); let req_url = req_url_base + "?" + zumens_str.replace(/\s+/g, ",").toUpperCase(); fetch(req_url,{method:"GET", cache:"no-cache"}) .then((res)=>{ if(!res.ok){ throw new Error(`${res.status} ${res.statusText}`); } return res.arrayBuffer(); }) .then((org_array)=>{ let tiff_arrays = parse_scan_res( org_array ); let div_elm = document.querySelector("#thumb_nails"); div_elm.innerHTML = ""; conv_tiff_arrays2pdf(tiff_arrays,pdf_basename,div_elm); }) .catch((reason)=>{ alert(reason); }); } const conv_tiff_arrays2pdf=(tiff_arrays,pdf_basename,div_elm)=>{ let pdf = new jspdf.jsPDF("landscape","mm","a4"); //A4横 let i = 0; for(let tiff_array of tiff_arrays){ i++; let uint8array = Uint8Array.from(tiff_array); let tiff = new Tiff({buffer:uint8array.buffer}); let canvas = tiff.toCanvas(); //tiff→canvas if(i>1) pdf.addPage(); //pdf page追加 pdf.addImage(canvas.toDataURL(),"PNG",0,0,297,210); //canvas→pdf let img_elm = document.createElement("img"); //thumb nail表示 img_elm.src = canvas.toDataURL(); img_elm.width = String(canvas.width / 10); img_elm.height = String(canvas.height/ 10); div_elm.append(img_elm); } pdf.save(pdf_basename+".pdf"); } const parse_scan_res=(org_array)=>{ ret_tiff_arrays = []; tmp_img_head = []; tmp_img_body = []; img_body_size = 0; org_array = new Uint8Array(org_array); let part = "ATR"; for(let tmp_byte of org_array ) { if(part=="ATR"){ if(tmp_byte==10) part="IMG_HEAD"; continue; } if(part=="IMG_HEAD"){ if(tmp_byte != 10){ tmp_img_head.push(tmp_byte); continue; } let img_head = String.fromCharCode.apply( "",new Uint16Array(tmp_img_head)); img_body_size = parseInt( img_head.split(" ")[2] ); tmp_img_head = []; part="IMG_BODY"; continue; } if(part=="IMG_BODY"){ if(tmp_img_body.length < img_body_size){ tmp_img_body.push(tmp_byte); continue; } ret_tiff_arrays.push( Array.from(tmp_img_body) ); tmp_img_body = []; part = "ATR"; } } return ret_tiff_arrays; } </script> </body> </html>