pdf2img.html 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177
  1. <div class="field">
  2. <span class="field-label">Input PDF</span>
  3. <div class="row">
  4. <button class="btn btn-primary" id="p2iPickBtn">Select PDF...</button>
  5. <span class="selected-file" id="p2iFile">No file selected</span>
  6. </div>
  7. </div>
  8. <div class="field">
  9. <span class="field-label">Output Format</span>
  10. <div class="radio-group">
  11. <label class="radio-item"><input type="radio" name="p2iFmt" value="jpg" checked> JPEG</label>
  12. <label class="radio-item"><input type="radio" name="p2iFmt" value="png"> PNG</label>
  13. </div>
  14. </div>
  15. <div class="field" id="p2iQfield">
  16. <span class="field-label">JPEG Quality: <span id="p2iQval">90</span>%</span>
  17. <div class="range-row">
  18. <span style="font-size:11px;color:var(--sub)">50</span>
  19. <input type="range" id="p2iQrange" min="50" max="100" value="90">
  20. <span style="font-size:11px;color:var(--sub)">100</span>
  21. </div>
  22. </div>
  23. <button class="btn-action" id="p2iBtn" disabled>Convert</button>
  24. <div id="p2iProg" style="display:none" class="progress-wrap">
  25. <div class="progress-label" id="p2iProgLbl">Preparing...</div>
  26. <div class="progress-track"><div class="progress-fill" id="p2iFill"></div></div>
  27. </div>
  28. <div id="p2iResult"></div>
  29. <script>
  30. (function() {
  31. var registry = window.ProductivityToolModules = window.ProductivityToolModules || {};
  32. var state = { filepath: null, root: null };
  33. var pdfJsReady = false;
  34. function getRoot() {
  35. return state.root && document.body.contains(state.root) ? state.root : null;
  36. }
  37. function loadPdfJs(onReady, onError) {
  38. if (pdfJsReady || typeof pdfjsLib !== 'undefined') {
  39. if (!pdfJsReady) {
  40. pdfjsLib.GlobalWorkerOptions.workerSrc = '../PDF Viewer/js/pdf.worker.js';
  41. pdfJsReady = true;
  42. }
  43. onReady();
  44. return;
  45. }
  46. var s = document.createElement('script');
  47. s.src = '../PDF Viewer/js/pdf.js';
  48. s.onload = function() {
  49. pdfjsLib.GlobalWorkerOptions.workerSrc = '../PDF Viewer/js/pdf.worker.js';
  50. pdfJsReady = true;
  51. onReady();
  52. };
  53. s.onerror = function() { onError(new Error('Failed to load PDF library')); };
  54. document.head.appendChild(s);
  55. }
  56. function runConversion(filepath, fmt, quality, onProgress, onDone, onError) {
  57. loadPdfJs(function() {
  58. pdfjsLib.getDocument(mediaUrl(filepath)).promise.then(function(pdf) {
  59. var numPages = pdf.numPages;
  60. var basename = basenameNoExt(filepath);
  61. var outDir = dirOf(filepath);
  62. var mime = fmt === 'png' ? 'image/png' : 'image/jpeg';
  63. var ext = fmt === 'png' ? '.png' : '.jpg';
  64. var i = 1;
  65. function nextPage() {
  66. if (i > numPages) {
  67. onDone(numPages, outDir);
  68. return;
  69. }
  70. onProgress(i, numPages);
  71. pdf.getPage(i).then(function(page) {
  72. var vp = page.getViewport({ scale: 2.0 });
  73. var canvas = document.createElement('canvas');
  74. canvas.width = vp.width;
  75. canvas.height = vp.height;
  76. var ctx = canvas.getContext('2d');
  77. if (fmt !== 'png') {
  78. ctx.fillStyle = '#FFF';
  79. ctx.fillRect(0, 0, vp.width, vp.height);
  80. }
  81. page.render({ canvasContext: ctx, viewport: vp }).promise.then(function() {
  82. canvas.toBlob(function(blob) {
  83. uploadBlob(blob, basename + '_page' + i + ext, outDir).then(function() {
  84. i += 1;
  85. nextPage();
  86. }, onError);
  87. }, mime, quality / 100);
  88. }, onError);
  89. }, onError);
  90. }
  91. nextPage();
  92. }, onError);
  93. }, onError);
  94. }
  95. registry.pdf2img = {
  96. init: function(root) {
  97. state = { filepath: null, root: root };
  98. var qRange = root.querySelector('#p2iQrange');
  99. var qValue = root.querySelector('#p2iQval');
  100. var qField = root.querySelector('#p2iQfield');
  101. var pickBtn = root.querySelector('#p2iPickBtn');
  102. var convertBtn = root.querySelector('#p2iBtn');
  103. qRange.addEventListener('input', function() {
  104. qValue.textContent = this.value;
  105. });
  106. Array.prototype.forEach.call(root.querySelectorAll('input[name=p2iFmt]'), function(input) {
  107. input.addEventListener('change', function() {
  108. qField.style.display = this.value === 'jpg' ? '' : 'none';
  109. });
  110. });
  111. pickBtn.addEventListener('click', function() {
  112. ao_module_openFileSelector('_p2iPickCb', 'user:/', 'file', false);
  113. });
  114. convertBtn.addEventListener('click', function() {
  115. if (!state.filepath) { return; }
  116. var btn = root.querySelector('#p2iBtn');
  117. var prog = root.querySelector('#p2iProg');
  118. var lbl = root.querySelector('#p2iProgLbl');
  119. var fill = root.querySelector('#p2iFill');
  120. var result = root.querySelector('#p2iResult');
  121. var fmt = root.querySelector('input[name=p2iFmt]:checked').value;
  122. var qual = parseInt(root.querySelector('#p2iQrange').value, 10);
  123. btn.disabled = true;
  124. prog.style.display = 'block';
  125. result.innerHTML = '';
  126. runConversion(state.filepath, fmt, qual, function(cur, total) {
  127. lbl.textContent = 'Page ' + cur + ' of ' + total + '...';
  128. fill.style.width = ((cur / total) * 100) + '%';
  129. }, function(numPages, outDir) {
  130. lbl.textContent = 'Done!';
  131. fill.style.width = '100%';
  132. result.innerHTML =
  133. '<div class="result-box result-ok"><strong>' + numPages +
  134. ' image' + (numPages !== 1 ? 's' : '') + ' saved</strong> to<br>' +
  135. escHtml(outDir) + '</div>';
  136. btn.disabled = false;
  137. }, function(err) {
  138. result.innerHTML =
  139. '<div class="result-box result-err"><strong>Error:</strong> ' +
  140. escHtml(err && err.message ? err.message : String(err)) + '</div>';
  141. btn.disabled = false;
  142. });
  143. });
  144. }
  145. };
  146. window._p2iPickCb = function(files) {
  147. var root = getRoot();
  148. if (!root || !files || !files.length) { return; }
  149. state.filepath = files[0].filepath;
  150. var label = root.querySelector('#p2iFile');
  151. label.textContent = files[0].filename;
  152. label.className = 'selected-file has-value';
  153. root.querySelector('#p2iBtn').disabled = false;
  154. };
  155. })();
  156. </script>