PNG to XBM Converter

Upload a PNG image to convert it into an XBM (X Window System Bitmap) format file. XBM is a monochrome (1-bit) text-based image format. Transparent pixels will be converted to white.

Image preview will appear here.

${originalFileName} (${imageWidth}x${imageHeight} pixels)

`; }; img.onerror = function() { imagePreview.innerHTML = '

Could not load image preview.

'; originalFileName = ""; }; img.src = e.target.result; }; reader.readAsDataURL(file); } /** * Converts the loaded PNG image data to an XBM (monochrome) format string. */ function convertPngToXbm() { const pngFileInput = document.getElementById('pngFileInput'); const resultArea = document.getElementById('resultArea'); const downloadPdfButton = document.getElementById('downloadPdfButton'); if (!pngFileInput || !resultArea || !downloadPdfButton) { console.error('Missing DOM elements for conversion.'); return; } const file = pngFileInput.files[0]; if (!file) { resultArea.style.display = 'block'; resultArea.innerHTML = '

Please select a PNG image file first.

'; downloadPdfButton.style.display = 'none'; return; } if (!file.type.startsWith('image/png')) { resultArea.style.display = 'block'; resultArea.innerHTML = '

Invalid file type. Please select a PNG image.

'; downloadPdfButton.style.display = 'none'; return; } 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); const imageData = ctx.getImageData(0, 0, img.width, img.height); const pixelData = imageData.data; // RGBA data from canvas // XBM dimensions const xbmWidth = img.width; const xbmHeight = img.height; // Calculate bytes per row (padded to 8 bits) const bytesPerRow = Math.ceil(xbmWidth / 8); const xbmBytes = []; for (let y = 0; y < xbmHeight; y++) { for (let byteIdx = 0; byteIdx < bytesPerRow; byteIdx++) { let currentByte = 0; for (let bitIdx = 0; bitIdx < 8; bitIdx++) { const x = byteIdx * 8 + bitIdx; if (x >= xbmWidth) { // If past image width, pad with 0s (white) // (currentByte << 1) | 0; - no change continue; } const pixelIndex = (y * xbmWidth + x) * 4; const r = pixelData[pixelIndex]; const g = pixelData[pixelIndex + 1]; const b = pixelData[pixelIndex + 2]; const a = pixelData[pixelIndex + 3]; let isBlackPixel; // If transparent, convert to white (0 bit) if (a < ALPHA_THRESHOLD) { isBlackPixel = false; } else { // Convert to grayscale and apply threshold const grayscale = (r + g + b) / 3; isBlackPixel = grayscale < MONOCHROME_THRESHOLD; } // XBM uses 1 for foreground (often black), 0 for background (white) // Pixels are stored LSB first, so we shift from right to left if (isBlackPixel) { currentByte |= (1 << bitIdx); // Set the bit } } xbmBytes.push(currentByte); } } // Generate XBM string const baseName = originalFileName.replace(/\.png$/i, '').replace(/[^a-zA-Z0-9_]/g, '_'); let xbmString = `#define ${baseName}_width ${xbmWidth}\n`; xbmString += `#define ${baseName}_height ${xbmHeight}\n`; xbmString += `static unsigned char ${baseName}_bits[] = {\n`; // Format bytes into lines of C array for (let i = 0; i < xbmBytes.length; i++) { if (i % 12 === 0) { // 12 bytes per line for readability xbmString += ' '; } xbmString += `0x${xbmBytes[i].toString(16).padStart(2, '0')}`; if (i < xbmBytes.length - 1) { xbmString += ','; } if ((i + 1) % 12 === 0 && i < xbmBytes.length - 1) { xbmString += '\n'; } } xbmString += '\n};'; convertedXbmContent = xbmString; // Store for PDF const outputFileName = originalFileName.replace(/\.png$/i, '.xbm'); const blob = new Blob([xbmString], { type: 'text/plain;charset=utf-8' }); const url = URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; a.download = outputFileName; document.body.appendChild(a); a.click(); document.body.removeChild(a); URL.revokeObjectURL(url); resultArea.style.display = 'block'; resultArea.innerHTML = `

Success! Your PNG has been converted to "${outputFileName}".

Note: This is a monochrome XBM file. Transparency converted to white.

`; downloadPdfButton.style.display = 'block'; // Store data for PDF report resultArea.dataset.inputFileName = originalFileName; resultArea.dataset.outputFileName = outputFileName; resultArea.dataset.imageWidth = img.width; resultArea.dataset.imageHeight = img.height; resultArea.dataset.xbmContentPreview = xbmString.substring(0, 500) + (xbmString.length > 500 ? '...' : ''); }; img.onerror = function() { resultArea.style.display = 'block'; resultArea.innerHTML = '

Error processing image. Make sure it\'s a valid PNG.

'; downloadPdfButton.style.display = 'none'; }; img.src = e.target.result; }; reader.onerror = function() { resultArea.style.display = 'block'; resultArea.innerHTML = '

Error reading file data.

'; downloadPdfButton.style.display = 'none'; }; reader.readAsDataURL(file); } /** * Clears all inputs, previews, and results. */ function clearAll() { document.getElementById('pngFileInput').value = ''; // Clear selected file document.getElementById('imagePreview').innerHTML = '

Image preview will appear here.

'; originalFileName = ""; imageWidth = 0; imageHeight = 0; convertedXbmContent = ""; clearResultArea(); } /** * Helper function to clear and hide the result area and PDF button. */ function clearResultArea() { const resultArea = document.getElementById('resultArea'); const downloadPdfButton = document.getElementById('downloadPdfButton'); if (resultArea) { resultArea.style.display = 'none'; resultArea.innerHTML = ''; // Clear stored data for PDF delete resultArea.dataset.inputFileName; delete resultArea.dataset.outputFileName; delete resultArea.dataset.imageWidth; delete resultArea.dataset.imageHeight; delete resultArea.dataset.xbmContentPreview; } if (downloadPdfButton) { downloadPdfButton.style.display = 'none'; } } /** * Generates a PDF summary of the conversion. */ function generatePdf() { // Check if jsPDF library is loaded if (typeof window.jspdf === 'undefined' || typeof window.jspdf.jsPDF === 'undefined') { console.error('jsPDF library not loaded. Cannot generate PDF.'); const resultArea = document.getElementById('resultArea'); if (resultArea) { resultArea.innerHTML = '

PDF generation failed. Library not loaded.

'; } return; } const { jsPDF } = window.jspdf; const doc = new jsPDF(); const resultArea = document.getElementById('resultArea'); // Retrieve stored data for PDF const inputFileName = resultArea.dataset.inputFileName || 'N/A'; const outputFileName = resultArea.dataset.outputFileName || 'N/A'; const width = resultArea.dataset.imageWidth || 'N/A'; const height = resultArea.dataset.imageHeight || 'N/A'; const xbmContentPreview = resultArea.dataset.xbmContentPreview || 'No XBM content generated.'; const generationDate = new Date().toLocaleString(); let yOffset = 20; // Title doc.setFontSize(24); doc.setTextColor(44, 62, 80); doc.text("PNG to XBM Conversion Summary", 105, yOffset, { align: 'center' }); yOffset += 20; // Summary details doc.setFontSize(14); doc.setTextColor(51, 51, 51); doc.text(`Conversion Date: ${generationDate}`, 20, yOffset); yOffset += 10; doc.text(`Input File: ${inputFileName}`, 20, yOffset); yOffset += 10; doc.text(`Output File: ${outputFileName}`, 20, yOffset); yOffset += 10; doc.text(`Image Dimensions: ${width} x ${height} pixels`, 20, yOffset); yOffset += 20; // Conversion Notes doc.setFontSize(12); doc.setTextColor(80, 80, 80); doc.text("Important Notes on XBM Conversion:", 20, yOffset); yOffset += 7; const notes = [ "• XBM is a monochrome (1-bit) format; all colors are converted to black or white.", "• Transparency from PNG is converted to white (background).", "• The conversion uses a grayscale threshold of 128 to determine black/white pixels.", "• XBM files are C-style source code files, ready to be included in C/C++ projects." ]; notes.forEach(note => { const splitNote = doc.splitTextToSize(note, 170); doc.text(splitNote, 25, yOffset); yOffset += (splitNote.length * 7) + 5; }); yOffset += 15; // XBM Content Preview if (yOffset > 250) { // Check for page break doc.addPage(); yOffset = 20; } doc.setFontSize(12); doc.setTextColor(51, 51, 51); doc.text("Generated XBM Content Preview (first 500 chars):", 20, yOffset); yOffset += 10; const xbmPreviewLines = doc.splitTextToSize(xbmContentPreview, 170); doc.setFont('courier'); // Monospace font for code preview doc.setFontSize(10); doc.text(xbmPreviewLines, 20, yOffset); doc.setFont('helvetica'); // Reset font doc.setFontSize(12); yOffset += (xbmPreviewLines.length * 6) + 15; // Adjusted line height for courier // Footer doc.setFontSize(9); doc.setTextColor(150, 150, 150); doc.text(`Report Generated by PNG to XBM Converter Tool`, 20, doc.internal.pageSize.height - 15); doc.save("PNG_to_XBM_Conversion_Summary.pdf"); }
Scroll to Top