From 2d6ab231e0257538c3ae1a9f1f59ef589e03b975 Mon Sep 17 00:00:00 2001 From: Ankit Kumar <139707943+ankit071105@users.noreply.github.com> Date: Sun, 4 Aug 2024 10:18:17 +0530 Subject: [PATCH] =?UTF-8?q?ImageXpert:=20Transform=20Your=20Images=20Just?= =?UTF-8?q?=20One=20Click=20=E2=80=93=20Effortless!?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit # Describe the solution you'd like I’d like a feature that allows users to upload an image and convert it into multiple formats (e.g., JPEG, PNG, TIFF) and PDFs. The solution should provide a straightforward interface for users to select their desired output formats and perform the conversion with minimal steps. # Additional context The feature should support high-quality conversions and handle various image formats effectively. It should also include a preview option before finalizing the conversion to ensure accuracy. What problem is this feature trying to solve? This feature aims to simplify the process of converting images into various formats and PDFs, providing users with a versatile and efficient tool to meet their conversion needs. How do we know when the feature is complete? The feature will be considered complete when: Users can upload an image and select from a list of output formats. The conversion process is seamless and produces high-quality results. Users receive an option to preview the converted file before finalizing. The feature operates smoothly with various image formats and produces accurate PDFs. # Fix Issue :- #2593 --- ImageXpert/index.html | 51 +++++++++++ ImageXpert/script.js | 197 ++++++++++++++++++++++++++++++++++++++++++ ImageXpert/style.css | 42 +++++++++ 3 files changed, 290 insertions(+) create mode 100644 ImageXpert/index.html create mode 100644 ImageXpert/script.js create mode 100644 ImageXpert/style.css diff --git a/ImageXpert/index.html b/ImageXpert/index.html new file mode 100644 index 00000000..0a41ebfe --- /dev/null +++ b/ImageXpert/index.html @@ -0,0 +1,51 @@ + + + + + + ImageXpert + + + + +


+
+

ImageXpert: Transforming Your Images, One Click at a Time.

+
+ + UNIVERSAL to PNG Wizard +
+ +
+ + +
+ + +
+ + + + + + + + + diff --git a/ImageXpert/script.js b/ImageXpert/script.js new file mode 100644 index 00000000..b361355f --- /dev/null +++ b/ImageXpert/script.js @@ -0,0 +1,197 @@ + +let selectedConversion = 'jpegToPNG'; + +function changeConversion(conversion) { + selectedConversion = conversion; + document.getElementById('selectedConversion').innerText = selectedConversion.replace(/([A-Z])/g, ' $1').trim(); + document.getElementById('fileUpload').value = ''; + document.getElementById('downloadLink').style.display = 'none'; +} + +async function convertFile() { + const fileInput = document.getElementById('fileUpload'); + const file = fileInput.files[0]; + if (!file) { + alert('Please upload a file first!'); + return; + } + + const fileExtension = file.name.split('.').pop().toLowerCase(); + if (fileExtension === 'pdf' && !selectedConversion.startsWith('pdfTo')) { + alert('You selected an image conversion. Please upload an image.'); + return; + } else if (fileExtension !== 'pdf' && selectedConversion.startsWith('pdfTo')) { + alert('You selected a PDF conversion. Please upload a PDF.'); + return; + } + + const reader = new FileReader(); + reader.onload = async function (event) { + const dataUrl = event.target.result; + + if (fileExtension === 'pdf') { + await handlePDFConversion(dataUrl); + } else { + const img = new Image(); + img.src = dataUrl; + img.onload = async function () { + await handleImageConversion(img); + }; + } + }; + + reader.readAsDataURL(file); +} + +async function handleImageConversion(img) { + let convertedBlob, outputFormat; + + switch (selectedConversion) { + case 'jpegToPNG': + convertedBlob = await convertToCanvasBlob(img, 'image/png'); + outputFormat = 'png'; + break; + + case 'pngToJPEG': + convertedBlob = await convertToCanvasBlob(img, 'image/jpeg'); + outputFormat = 'jpg'; + break; + + case 'pngToAVIF': + convertedBlob = await convertToCanvasBlob(img, 'image/avif'); + outputFormat = 'avif'; + break; + + case 'avifToPNG': + convertedBlob = await convertToCanvasBlob(img, 'image/png'); + outputFormat = 'png'; + break; + + case 'pngToWebP': + convertedBlob = await convertToCanvasBlob(img, 'image/webp'); + outputFormat = 'webp'; + break; + + case 'webpToPNG': + convertedBlob = await convertToCanvasBlob(img, 'image/png'); + outputFormat = 'png'; + break; + + case 'jpegToBMP': + convertedBlob = await convertToCanvasBlob(img, 'image/bmp'); + outputFormat = 'bmp'; + break; + + case 'bmpToJPEG': + convertedBlob = await convertToCanvasBlob(img, 'image/jpeg'); + outputFormat = 'jpg'; + break; + + case 'imageToPDF': + convertedBlob = await convertImageToPDF(img); + outputFormat = 'pdf'; + break; + + default: + alert('Conversion type not supported!'); + return; + } + + const downloadLink = document.getElementById('downloadButton'); + downloadLink.href = URL.createObjectURL(convertedBlob); + downloadLink.download = `converted.${outputFormat}`; + document.getElementById('downloadLink').style.display = 'block'; +} + +async function handlePDFConversion(dataUrl) { + if (selectedConversion === 'pdfToImage') { + await convertPDFToImage(dataUrl); + } else { + const pdfjsLib = window['pdfjs-dist/build/pdf']; + pdfjsLib.GlobalWorkerOptions.workerSrc = 'https://cdnjs.cloudflare.com/ajax/libs/pdf.js/2.18.0/pdf.worker.min.js'; + + const pdf = await pdfjsLib.getDocument(dataUrl).promise; + const page = await pdf.getPage(1); + const viewport = page.getViewport({ scale: 2.0 }); + + const canvas = document.createElement('canvas'); + const context = canvas.getContext('2d'); + canvas.width = viewport.width; + canvas.height = viewport.height; + + const renderContext = { + canvasContext: context, + viewport: viewport, + }; + + await page.render(renderContext).promise(); + + let outputFormat = 'png'; + + if (selectedConversion === 'pdfToPNG') { + canvas.toBlob(blob => { + const downloadLink = document.getElementById('downloadButton'); + downloadLink.href = URL.createObjectURL(blob); + downloadLink.download = `converted.${outputFormat}`; + document.getElementById('downloadLink').style.display = 'block'; + }, 'image/png'); + } else { + alert('Conversion type not supported for PDF!'); + } + } +} + +async function convertPDFToImage(dataUrl) { + const pdfjsLib = window['pdfjs-dist/build/pdf']; + pdfjsLib.GlobalWorkerOptions.workerSrc = 'https://cdnjs.cloudflare.com/ajax/libs/pdf.js/2.18.0/pdf.worker.min.js'; + + const pdf = await pdfjsLib.getDocument(dataUrl).promise; + const page = await pdf.getPage(1); + const viewport = page.getViewport({ scale: 2.0 }); + + const canvas = document.createElement('canvas'); + const context = canvas.getContext('2d'); + canvas.width = viewport.width; + canvas.height = viewport.height; + + const renderContext = { + canvasContext: context, + viewport: viewport, + }; + + await page.render(renderContext).promise(); + + canvas.toBlob(blob => { + const downloadLink = document.getElementById('downloadButton'); + downloadLink.href = URL.createObjectURL(blob); + downloadLink.download = 'converted.png'; + document.getElementById('downloadLink').style.display = 'block'; + }, 'image/png'); +} + +function convertToCanvasBlob(img, type) { + return new Promise((resolve) => { + const canvas = document.createElement('canvas'); + const context = canvas.getContext('2d'); + canvas.width = img.width; + canvas.height = img.height; + context.drawImage(img, 0, 0, img.width, img.height); + + canvas.toBlob(blob => { + resolve(blob); + }, type); + }); +} + +async function convertImageToPDF(img) { + const { jsPDF } = window.jspdf; + + const pdf = new jsPDF({ + orientation: img.width > img.height ? 'l' : 'p', + unit: 'px', + format: [img.width, img.height] + }); + + pdf.addImage(img.src, 'PNG', 0, 0, img.width, img.height); + return pdf.output('blob'); +} diff --git a/ImageXpert/style.css b/ImageXpert/style.css new file mode 100644 index 00000000..990fbaec --- /dev/null +++ b/ImageXpert/style.css @@ -0,0 +1,42 @@ + +body { + font-family: Arial, sans-serif; + background-color: #d8f6f6; + margin: 0; + padding: 50px; +} +.navbar { + background-color: #3d3d3d; + overflow: hidden; +} +.navbar a { + float: left; + display: block; + color: white; + text-align: center; + padding: 14px 20px; + text-decoration: none; +} +.navbar a:hover { + background-color: #ddd; + color: black; +} +.container { + max-width: 800px; + margin: auto; + padding: 20px; + text-align: center; +} +.conversion-options { + margin: 20px 0; +} +.conversion-options select, input[type="file"] { + margin: 10px 0; +} +footer { + background-color: #333; + color: white; + text-align: center; + padding: 10px 0; + margin-top: 20px; +}