Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /**
- * ASCII Studio v1.5 - Generator + Settings Integrated + Proper Minimize + Universal Clipboard Paste
- * Features: Drag & Drop, Contrast, Custom Gradients + Preview, Debounced Inputs, .txt Download, Inversion, Clipboard Paste (button + Ctrl+V)
- */
- (function() {
- const id = 'asciiStudio';
- if (document.getElementById(id)) return;
- // --- State Management ---
- let settings = {
- width: 120,
- contrast: 40,
- gradient: "█▉▊▋▌▍▎▏ ",
- inverted: false,
- currentImg: null,
- gradArr: null,
- contrastFactor: null
- };
- const updateGradient = () => {
- settings.gradArr = settings.inverted
- ? settings.gradient.split('').reverse()
- : settings.gradient.split('');
- };
- const updateContrastFactor = () => {
- const c = settings.contrast;
- settings.contrastFactor = (259 * (c + 255)) / (255 * (259 - c));
- };
- updateGradient();
- updateContrastFactor();
- // --- Core HUD Structure ---
- const hud = document.createElement('div');
- hud.id = id;
- hud.style.cssText = `position:fixed; top:20px; left:20px; width:520px; height:650px; background:#111; color:#fff; font-family:monospace; z-index:9999; border:1px solid #fff; display:flex; flex-direction:column; overflow:hidden; resize:both; min-width:350px; min-height:40px; box-shadow:0 0 15px rgba(0,0,0,0.8);`;
- const header = document.createElement('div');
- header.style.cssText = `display:flex; justify-content:space-between; padding:8px 10px; cursor:grab; background:#222; border-bottom:1px solid #fff; user-select:none; flex-shrink:0;`;
- header.innerHTML = `<span>Image to Ascii v1.5</span><div><button id="${id}-min">—</button><button id="${id}-close">✕</button></div>`;
- const [minBtn, closeBtn] = header.querySelectorAll('button');
- [minBtn, closeBtn].forEach(b => b.style.cssText = `background:#333; color:#fff; border:none; cursor:pointer; padding:2px 8px; margin-left:5px; border-radius:2px;`);
- hud.appendChild(header);
- const container = document.createElement('div');
- container.style.cssText = `flex:1; overflow:auto; padding:15px; display:flex; flex-direction:column;`;
- // --- Generator + Settings Pane ---
- const genPane = document.createElement('div');
- genPane.style.display = 'flex';
- genPane.style.flexDirection = 'column';
- genPane.style.height = '100%';
- genPane.style.gap = '10px';
- // Drop Zone
- const dropZone = document.createElement('div');
- dropZone.id = 'dropZone';
- dropZone.style.cssText = `border:2px dashed #444; padding:20px; text-align:center; cursor:pointer; background:#1a1a1a;`;
- dropZone.textContent = "Drag Image, Click to Load, or Ctrl+V to Paste";
- genPane.appendChild(dropZone);
- // Controls container
- const controls = document.createElement('div');
- controls.style.display = 'flex';
- controls.style.flexDirection = 'column';
- controls.style.gap = '8px';
- genPane.appendChild(controls);
- // --- Utility: Debounced ---
- const debounce = (fn, delay=100) => {
- let timer;
- return (...args) => { clearTimeout(timer); timer = setTimeout(() => fn(...args), delay); };
- };
- // --- Add Controls ---
- const addControl = (label, html) => {
- const row = document.createElement('div');
- row.innerHTML = `<label style="font-size:12px;color:#aaa">${label}</label><br>${html}`;
- controls.appendChild(row);
- return row.lastChild;
- };
- // Width
- const wIn = addControl("Resolution Width", `<input type="range" min="40" max="300" value="${settings.width}" style="width:100%">`);
- wIn.oninput = debounce(() => { settings.width = parseInt(wIn.value); generateASCII(); });
- // Contrast
- const cIn = addControl("Contrast Boost", `<input type="range" min="0" max="150" value="${settings.contrast}" style="width:100%">`);
- cIn.oninput = debounce(() => { settings.contrast = parseInt(cIn.value); updateContrastFactor(); generateASCII(); });
- // Gradient
- const gIn = addControl("ASCII Gradient String", `<input type="text" value="${settings.gradient}" style="width:100%; background:#222; color:#fff; border:1px solid #444; padding:5px;">`);
- gIn.onchange = () => { settings.gradient = gIn.value || " "; updateGradient(); generateASCII(); gradientPreview.textContent = settings.gradArr.join(''); };
- // Gradient Preview
- const gradientPreview = document.createElement('pre');
- gradientPreview.style.cssText = 'background:#111;color:#0f0;padding:5px;border:1px solid #333;font-size:10px;white-space:pre;';
- gradientPreview.textContent = settings.gradArr.join('');
- controls.appendChild(gradientPreview);
- // Invert Button
- const invBtn = document.createElement('button');
- invBtn.textContent = "Invert Gradient: OFF";
- invBtn.style.cssText = "width:100%; padding:10px; background:#333; color:#fff; border:1px solid #555; cursor:pointer;";
- invBtn.onclick = () => {
- settings.inverted = !settings.inverted;
- invBtn.textContent = `Invert Gradient: ${settings.inverted ? 'ON' : 'OFF'}`;
- invBtn.style.background = settings.inverted ? '#555' : '#333';
- updateGradient();
- gradientPreview.textContent = settings.gradArr.join('');
- generateASCII();
- };
- controls.appendChild(invBtn);
- // Download / Copy / Paste Buttons
- const btns = document.createElement('div');
- btns.style.cssText = 'display:flex; gap:10px;';
- const dlBtn = document.createElement('button');
- dlBtn.textContent = 'Download';
- dlBtn.style.cssText = 'flex:1; padding:8px; background:#333; color:#fff; border:1px solid #555; cursor:pointer;';
- const copyBtn = document.createElement('button');
- copyBtn.textContent = 'Copy';
- copyBtn.style.cssText = 'flex:1; padding:8px; background:#333; color:#fff; border:1px solid #555; cursor:pointer;';
- const pasteBtn = document.createElement('button');
- pasteBtn.textContent = 'Paste Image';
- pasteBtn.style.cssText = 'flex:1; padding:8px; background:#333; color:#fff; border:1px solid #555; cursor:pointer;';
- btns.appendChild(dlBtn);
- btns.appendChild(copyBtn);
- btns.appendChild(pasteBtn);
- genPane.appendChild(btns);
- // ASCII Output
- const asciiOutput = document.createElement('pre');
- asciiOutput.id = 'asciiOutput';
- asciiOutput.style.cssText = 'font-size:7px; line-height:6px; background:#000; color:#fff; overflow:auto; white-space:pre; border:1px solid #333; flex:1; min-height:250px; padding:5px;';
- genPane.appendChild(asciiOutput);
- container.appendChild(genPane);
- hud.appendChild(container);
- document.body.appendChild(hud);
- // --- ASCII Generation ---
- const generateASCII = () => {
- if (!settings.currentImg) return;
- const img = settings.currentImg;
- const canvas = document.createElement("canvas");
- const ctx = canvas.getContext("2d");
- const scale = img.height / img.width;
- const h = Math.min(Math.floor(settings.width * scale * 0.55), 600);
- canvas.width = settings.width; canvas.height = h;
- ctx.drawImage(img, 0, 0, settings.width, h);
- const { data } = ctx.getImageData(0, 0, settings.width, h);
- let out = "";
- const grad = settings.gradArr;
- for (let y = 0; y < h; y++) {
- for (let x = 0; x < settings.width; x++) {
- const i = (y * settings.width + x) * 4;
- const r = settings.contrastFactor * (data[i] - 128) + 128;
- const g = settings.contrastFactor * (data[i+1] - 128) + 128;
- const b = settings.contrastFactor * (data[i+2] - 128) + 128;
- const brightness = Math.max(0, Math.min(255, (0.2126*r + 0.7152*g + 0.0722*b)));
- const charIdx = Math.floor((brightness / 255) * (grad.length - 1));
- out += grad[charIdx] || " ";
- }
- out += "\n";
- }
- asciiOutput.textContent = out;
- };
- // --- Events ---
- dropZone.onclick = () => {
- const input = document.createElement('input');
- input.type = 'file';
- input.onchange = e => process(e.target.files[0]);
- input.click();
- };
- const process = (file) => {
- if (file && file.type.startsWith('image/')) {
- const img = new Image();
- img.src = URL.createObjectURL(file);
- img.onload = () => { settings.currentImg = img; generateASCII(); };
- }
- };
- dlBtn.onclick = () => {
- const blob = new Blob([asciiOutput.textContent], {type:'text/plain'});
- const a = document.createElement('a');
- a.href = URL.createObjectURL(blob);
- a.download = 'ascii_art.txt';
- a.click();
- };
- copyBtn.onclick = () => {
- navigator.clipboard.writeText(asciiOutput.textContent)
- .then(() => {
- const old = copyBtn.textContent;
- copyBtn.textContent = "Copied!";
- setTimeout(() => copyBtn.textContent = old, 2000);
- })
- .catch(() => alert("Clipboard permission denied."));
- };
- // Paste Button (modern browsers)
- pasteBtn.onclick = async () => {
- try {
- if (!navigator.clipboard || !navigator.clipboard.read) return;
- const items = await navigator.clipboard.read();
- for (const item of items) {
- for (const type of item.types) {
- if (type.startsWith("image/")) {
- const blob = await item.getType(type);
- process(blob);
- const old = pasteBtn.textContent;
- pasteBtn.textContent = "Pasted!";
- setTimeout(() => pasteBtn.textContent = old, 2000);
- return;
- }
- }
- }
- alert("No image found in clipboard.");
- } catch {
- console.warn("Clipboard API failed, try Ctrl+V");
- }
- };
- // Universal Ctrl+V paste (works in Firefox and all browsers)
- window.addEventListener("paste", (e) => {
- const items = e.clipboardData?.items;
- if (!items) return;
- for (const item of items) {
- if (item.type.startsWith("image/")) {
- const blob = item.getAsFile();
- if (blob) {
- process(blob);
- const old = pasteBtn.textContent;
- pasteBtn.textContent = "Pasted!";
- setTimeout(() => pasteBtn.textContent = old, 2000);
- }
- break;
- }
- }
- });
- // Dragging
- let drag=false, ox, oy;
- header.onmousedown = e => { drag=true; ox=e.clientX; oy=e.clientY; header.style.cursor='grabbing'; };
- window.addEventListener("mousemove", e => {
- if(!drag) return;
- hud.style.top = (hud.offsetTop + e.clientY - oy)+'px';
- hud.style.left = (hud.offsetLeft + e.clientX - ox)+'px';
- ox=e.clientX; oy=e.clientY;
- });
- window.addEventListener("mouseup", () => { drag=false; header.style.cursor='grab'; });
- closeBtn.onclick = () => hud.remove();
- // --- Proper Minimize ---
- let minimized=false;
- let oldH = hud.offsetHeight;
- minBtn.onclick = () => {
- minimized = !minimized;
- if(minimized){
- oldH = hud.offsetHeight;
- container.style.display='none';
- hud.style.height='auto';
- } else {
- container.style.display='flex';
- hud.style.height = oldH + 'px';
- }
- };
- })();
Advertisement