JavaScriptでつくったJPEGとPDFコンバータが動作しない

アプリの概要

HTML,JavaScriptでPDFにJPEGを変換する。ページ順は画像アップロード時にアップロードする場所(列)で決まる。その列は追加・削除可能。出力DPIをしていするフォームがある。そこに、自動入力ボタンが押されたらその時点で選択されているJPEGの中で最低のDPIを探し、それを自動入力する。変換ボタンが押されたらPDFに変換し、ダウンロードする。

実現したいこと

このアプリで、動かない問題を解決し、ページサイズがLetterになってしまう問題も解決したいです。

エラーメッセージ(開発者ツールに表示されているもの)

Form elements must have labels: Element has no title attribute Element has no placeholder attribute →影響を受けるソース:<input type="file" accept="image/jpeg" onchange="updateDPI(this)">、<input type="file" accept="image/jpeg" onchange="updateDPI(this)">

これ以外は表示されていません(Edge⦅Windows11⦆の開発者ツール)。

該当のソースコード

<!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>JPEG to PDFコンバータ</title> <style> .overlayL { position: fixed; width: 100%; height: 100%; top: 0; left: 0; background-color: rgba(0, 0, 0, 0.5); display: none; justify-content: center; align-items: center; } .loaderL { display: flex; justify-content: center; align-items: center; } </style> </head> <body> <table id="imageTable"> <thead> <tr> <th>ページ数</th> <th>JPEGアップロード</th> <th>削除</th> </tr> </thead> <tbody> <tr> <td>1</td> <td><input type="file" accept="image/jpeg" onchange="updateDPI(this)" /></td> <td><button onclick="deleteRow(this)">列削除</button></td> </tr> <tr> <td>2</td> <td><input type="file" accept="image/jpeg" onchange="updateDPI(this)" /></td> <td><button onclick="deleteRow(this)">列削除</button></td> </tr> </tbody> </table> <button onclick="addRow()">列追加</button> <button onclick="convertToPDF()">変換</button> <form id="dpiForm"> <label for="dpi">DPI:</label> <input type="number" id="dpi" name="dpi" min="1" step="1" required> <button type="button" onclick="autoFillDPI()">DPI自動入力</button> </form> <div class="overlayL" id="overlayL"> <div class="loaderL"> <img src="loading.svg" alt="処理中..." width="52px"> </div> </div> <script src="https://cdnjs.cloudflare.com/ajax/libs/pdf.js/2.11.338/pdf.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/html2canvas/1.3.2/html2canvas.min.js"></script> <script> 'use strict'; function addRow() { const table = document.getElementById("imageTable").getElementsByTagName('tbody')[0]; const rowCount = table.rows.length; const row = table.insertRow(rowCount); const pageNumber = rowCount + 1; const cell1 = row.insertCell(0); const cell2 = row.insertCell(1); const cell3 = row.insertCell(2); cell1.innerHTML = pageNumber; cell2.innerHTML = '<input type="file" accept="image/jpeg" onchange="updateDPI(this)" />'; cell3.innerHTML = '<button onclick="deleteRow(this)">列削除</button>'; } function deleteRow(button) { const row = button.parentNode.parentNode; row.parentNode.removeChild(row); } function updateDPI(input) { const file = input.files[0]; if (!file || !file.type.startsWith('image/jpeg')) { alert('JPEGファイルを選択してください'); return; } const image = new Image(); const reader = new FileReader(); reader.onload = function(e) { image.src = e.target.result; image.onload = function() { const dpi = (image.width / file.width) * 72; // 1px = 1/72 inchと仮定 input.parentNode.parentNode.querySelector('input[type="number"]').value = dpi; }; }; reader.readAsDataURL(file); } function autoFillDPI() { const table = document.getElementById("imageTable").getElementsByTagName('tbody')[0]; const rows = table.getElementsByTagName('tr'); let minDPI = Infinity; for (let i = 0; i < rows.length; i++) { const input = rows[i].getElementsByTagName('input')[0]; if (input && input.files.length > 0) { const file = input.files[0]; const image = new Image(); const reader = new FileReader(); reader.onload = function(e) { image.src = e.target.result; image.onload = function() { const dpi = (image.width / file.width) * 72; if (dpi < minDPI) { minDPI = dpi; } }; }; reader.readAsDataURL(file); } } if (minDPI === Infinity) { alert('画像ファイルが選択されていません'); return; } document.getElementById('dpi').value = minDPI; } async function convertToPDF() { const dpi = document.getElementById('dpi').value; if (!dpi) { alert('DPI値を入力してください'); return; } const table = document.getElementById("imageTable").getElementsByTagName('tbody')[0]; const rows = table.getElementsByTagName('tr'); // ローディングを表示 document.getElementById('overlayL').style.display = 'flex'; const canvasPromises = []; for (let i = 0; i < rows.length; i++) { const input = rows[i].getElementsByTagName('input')[0]; if (input && input.files.length > 0) { const file = input.files[0]; const canvasPromise = createCanvasFromImage(file); canvasPromises.push(canvasPromise); } } Promise.all(canvasPromises) .then(async canvases => { const pdf = new jsPDF({ orientation: 'p', unit: 'in', format: [8.5, 11] // ここ:Letterサイズならこうするが、A4,B5,A5,フリーサイズにするにはどうすればいいのか }); for (const canvas of canvases) { pdf.setDPI(dpi); pdf.addImage(canvas.toDataURL('image/jpeg'), 'JPEG', 0, 0, 8.5, 11); if (canvas !== canvases[canvases.length - 1]) { pdf.addPage(); } } const pdfDataUri = pdf.output('datauristring'); downloadPDF(pdfDataUri); }) .catch(error => { console.error('Error converting images to PDF:', error); }) .finally(() => { // 処理が完了したらローディングを非表示に document.getElementById('overlayL').style.display = 'none'; }); } function createCanvasFromImage(file) { return new Promise((resolve, reject) => { const reader = new FileReader(); reader.onload = function(e) { const img = new Image(); img.onload = function() { const canvas = document.createElement('canvas'); const ctx = canvas.getContext('2d'); canvas.width = img.width; canvas.height = img.height; ctx.drawImage(img, 0, 0); resolve(canvas); } img.src = e.target.result; }; reader.readAsDataURL(file); }); } function downloadPDF(dataUri) { var currentDate = new Date(); var year = currentDate.getFullYear(); var month = ('0' + (currentDate.getMonth() + 1)).slice(-2); var day = ('0' + currentDate.getDate()).slice(-2); var alphabet = generateRandomAlphabet(4); var hours = ('0' + currentDate.getHours()).slice(-2); // Add leading zero if necessary var minutes = ('0' + currentDate.getMinutes()).slice(-2); // Add leading zero if necessary var seconds = ('0' + currentDate.getSeconds()).slice(-2); // Add leading zero if necessary var milliseconds = ('00' + currentDate.getMilliseconds()).slice(-3); // Add leading zeros if necessary const link = document.createElement('a'); link.href = dataUri; link.download = 'JPEGtoPDF_' + year + month + day + hours + minutes + seconds + milliseconds + '.pdf'; link.click(); } </script> </body> </html>

コメントを投稿

0 コメント