Created
January 17, 2026 13:22
-
-
Save Jaid/45b18b105ab0546a51caf0dc9f535fb8 to your computer and use it in GitHub Desktop.
Simple text compression
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <!DOCTYPE html> | |
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>Text Encoder</title> | |
| <style> | |
| body { | |
| margin: 0; | |
| padding: 0; | |
| font-family: monospace; | |
| } | |
| .header { | |
| display: flex; | |
| align-items: center; | |
| padding: 10px; | |
| border-bottom: 1px solid #ccc; | |
| background-color: #f8f8f8; | |
| } | |
| .header select, .header span, .header button { | |
| margin-right: 10px; | |
| } | |
| .container { | |
| display: flex; | |
| flex-direction: column; | |
| height: calc(100vh - 41px); /* Adjust for header height */ | |
| } | |
| .input-area, .output-area { | |
| flex: 1; | |
| padding: 10px; | |
| box-sizing: border-box; | |
| } | |
| .input-area { | |
| border-bottom: 1px solid #ccc; | |
| } | |
| textarea { | |
| width: 100%; | |
| height: 100%; | |
| border: none; | |
| resize: none; | |
| font-family: monospace; | |
| font-size: 14px; | |
| } | |
| pre { | |
| margin: 0; | |
| white-space: pre-wrap; | |
| word-wrap: break-word; | |
| font-size: 14px; | |
| } | |
| </style> | |
| </head> | |
| <body> | |
| <div class="header"> | |
| <select id="cipher"> | |
| <option value="none" selected>None</option> | |
| <option value="rot13">Rot13</option> | |
| </select> | |
| <select id="compression"> | |
| <option value="none">None</option> | |
| <option value="deflate" selected>Deflate</option> | |
| </select> | |
| <select id="encoding"> | |
| <option value="base64" selected>Base64</option> | |
| <option value="base64url">Base64Url</option> | |
| <option value="base62">Base62</option> | |
| <option value="base85">Base85</option> | |
| <option value="hex">Hex</option> | |
| </select> | |
| <span id="charcount">0 characters</span> | |
| <button id="copy">Copy</button> | |
| </div> | |
| <div class="container"> | |
| <div class="input-area"> | |
| <textarea id="input" placeholder="Enter text here..."></textarea> | |
| </div> | |
| <div class="output-area"> | |
| <pre id="output"></pre> | |
| </div> | |
| </div> | |
| <script> | |
| function rot13(str) { | |
| return str.replace(/[a-zA-Z]/g, function(char) { | |
| const code = char.charCodeAt(0); | |
| const base = code < 97 ? 65 : 97; | |
| return String.fromCharCode((code - base + 13) % 26 + base); | |
| }); | |
| } | |
| function toBase62(bytes) { | |
| let num = BigInt(0); | |
| for (const byte of bytes) { | |
| num = num * 256n + BigInt(byte); | |
| } | |
| const chars = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'; | |
| if (num === 0n) return '0'; | |
| let result = ''; | |
| while (num > 0n) { | |
| result = chars[Number(num % 62n)] + result; | |
| num /= 62n; | |
| } | |
| return result; | |
| } | |
| function toBase85(bytes) { | |
| const chars = "!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstu"; | |
| let result = ''; | |
| let i = 0; | |
| const len = bytes.length; | |
| while (i < len) { | |
| let tuple = 0; | |
| let count = 0; | |
| for (let j = 0; j < 4; j++) { | |
| if (i < len) { | |
| tuple = (tuple * 256) + bytes[i]; | |
| i++; | |
| count++; | |
| } else { | |
| tuple *= 256; | |
| } | |
| } | |
| let encoded = ''; | |
| for (let j = 4; j >= 0; j--) { | |
| if (j < count + 1 || count === 4) { | |
| encoded = chars[tuple % 85] + encoded; | |
| tuple = Math.floor(tuple / 85); | |
| } | |
| } | |
| result += encoded; | |
| } | |
| return result; | |
| } | |
| function toHex(bytes) { | |
| return Array.from(bytes).map(b => b.toString(16).padStart(2, '0')).join(''); | |
| } | |
| async function getProcessedBytes(text, compression) { | |
| const encoder = new TextEncoder(); | |
| const bytes = encoder.encode(text); | |
| const readable = new ReadableStream({ | |
| start(controller) { | |
| controller.enqueue(bytes); | |
| controller.close(); | |
| } | |
| }); | |
| let processedStream = readable; | |
| if (compression === 'deflate') { | |
| const compressor = new CompressionStream('deflate'); | |
| processedStream = readable.pipeThrough(compressor); | |
| } | |
| const reader = processedStream.getReader(); | |
| const chunks = []; | |
| while (true) { | |
| const { done, value } = await reader.read(); | |
| if (done) break; | |
| chunks.push(value); | |
| } | |
| let totalLength = 0; | |
| for (const chunk of chunks) { | |
| totalLength += chunk.length; | |
| } | |
| const processed = new Uint8Array(totalLength); | |
| let offset = 0; | |
| for (const chunk of chunks) { | |
| processed.set(chunk, offset); | |
| offset += chunk.length; | |
| } | |
| return processed; | |
| } | |
| async function updateOutput() { | |
| let text = document.getElementById('input').value; | |
| const cipher = document.getElementById('cipher').value; | |
| const compression = document.getElementById('compression').value; | |
| const encoding = document.getElementById('encoding').value; | |
| if (cipher === 'rot13') { | |
| text = rot13(text); | |
| } | |
| const bytes = await getProcessedBytes(text, compression); | |
| let encoded; | |
| if (encoding === 'base64') { | |
| encoded = btoa(String.fromCharCode(...bytes)); | |
| } else if (encoding === 'base64url') { | |
| encoded = btoa(String.fromCharCode(...bytes)) | |
| .replace(/\+/g, '-') | |
| .replace(/\//g, '_') | |
| .replace(/=+$/, ''); | |
| } else if (encoding === 'base62') { | |
| encoded = toBase62(bytes); | |
| } else if (encoding === 'base85') { | |
| encoded = toBase85(bytes); | |
| } else if (encoding === 'hex') { | |
| encoded = toHex(bytes); | |
| } | |
| document.getElementById('output').textContent = encoded; | |
| document.getElementById('charcount').textContent = `${encoded.length} characters`; | |
| } | |
| document.getElementById('input').addEventListener('input', updateOutput); | |
| document.getElementById('cipher').addEventListener('change', updateOutput); | |
| document.getElementById('compression').addEventListener('change', updateOutput); | |
| document.getElementById('encoding').addEventListener('change', updateOutput); | |
| document.getElementById('copy').addEventListener('click', () => { | |
| const output = document.getElementById('output').textContent; | |
| navigator.clipboard.writeText(output).then(() => { | |
| alert('Copied to clipboard!'); | |
| }).catch(err => { | |
| console.error('Failed to copy: ', err); | |
| }); | |
| }); | |
| </script> | |
| </body> | |
| </html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment