Olaf from Frozen with Open Arms and Snowflakes Around Coloring Page

Olaf from Frozen with Open Arms and Snowflakes Around
Download
Frozen 704 × 1000 px

Published by: Coloring Pages

Author: Fill Feleciano

Source: Pinterest

Free to use for personal, educational, editorial, and commercial purposes. This artwork is in the public domain. Attribution is not required. Report DMCA · Download issues

Frames
' ].join('')); pw.document.close(); if (onClose) pw.addEventListener('afterprint', function(){ onClose(); }, {once:true}); } // ── Download ────────────────────────────────────────────────────────────────── var dlBtn = document.querySelector('.sc-btn-dl'); if (dlBtn) { dlBtn.addEventListener('click', function(e) { e.preventDefault(); var orig = dlBtn.textContent; dlBtn.textContent = '…'; function forceDownload(url, filename) { fetch(url) .then(function(r){ return r.blob(); }) .then(function(blob){ dlBtn.textContent = orig; var bUrl = URL.createObjectURL(blob); var a = document.createElement('a'); a.href = bUrl; a.download = filename; document.body.appendChild(a); a.click(); document.body.removeChild(a); setTimeout(function(){ URL.revokeObjectURL(bUrl); }, 30000); }) .catch(function(){ dlBtn.textContent = orig; window.open(url, '_blank'); }); } if (colorCanvas && !hasOverlays()) { colorCanvas.toBlob(function(blob) { dlBtn.textContent = orig; if (!blob) { forceDownload(dlBtn.href, dlBtn.getAttribute('download') || 'image.png'); return; } var bUrl = URL.createObjectURL(blob); var a = document.createElement('a'); a.href = bUrl; a.download = (dlBtn.getAttribute('download') || 'desenho').replace(/\.[^/.]+$/, "") + '-editado.png'; document.body.appendChild(a); a.click(); document.body.removeChild(a); setTimeout(function(){ URL.revokeObjectURL(bUrl); }, 30000); }, 'image/png'); } else if (hasOverlays()) { captureImgWrap(function(canvas) { dlBtn.textContent = orig; if (!canvas) { forceDownload(dlBtn.href, dlBtn.getAttribute('download') || 'image.png'); return; } canvas.toBlob(function(blob) { if (!blob) { forceDownload(dlBtn.href, dlBtn.getAttribute('download') || 'image.png'); return; } var bUrl = URL.createObjectURL(blob); var a = document.createElement('a'); a.href = bUrl; a.download = (dlBtn.getAttribute('download') || 'desenho').replace(/\.[^/.]+$/, "") + '-editado.png'; document.body.appendChild(a); a.click(); document.body.removeChild(a); setTimeout(function(){ URL.revokeObjectURL(bUrl); }, 30000); }, 'image/png'); }); } else { forceDownload(dlBtn.href, dlBtn.getAttribute('download') || 'image.png'); } }); } // Pré-carrega no hover do botão PDF var pdfBtn = document.querySelector('.sc-btn-pdf'); if (pdfBtn) { pdfBtn.addEventListener('mouseenter', function(){ loadPdfLib(function(){}); }, {once:true}); pdfBtn.addEventListener('touchstart', function(){ loadPdfLib(function(){}); }, {once:true, passive:true}); } // ── PDF ─────────────────────────────────────────────────────────────────────── document.addEventListener('click', function(e){ var btn = e.target.closest('.sc-btn-pdf'); if (!btn) return; var url = btn.dataset.url; var title = btn.dataset.title || 'desenho'; if (!url) return; btn.disabled = true; btn.textContent = '…'; var fname = title.replace(/[^a-z0-9]/gi,'-').toLowerCase() + '.pdf'; function pdfFromCanvas(canvas) { // Usa jsPDF directamente (exposto pelo html2pdf bundle) if (!window.jsPDF) { window.open(url,'_blank'); btn.disabled=false; btn.textContent='PDF'; return; } try { var pdf = new window.jsPDF({orientation:'portrait', unit:'mm', format:'a4'}); var pw = pdf.internal.pageSize.getWidth() - 20; var ph = (canvas.height / canvas.width) * pw; var py = Math.max(10, (pdf.internal.pageSize.getHeight() - ph) / 2); pdf.addImage(canvas.toDataURL('image/jpeg', 0.93), 'JPEG', 10, py, pw, ph); pdf.save(fname); } catch(ex) { window.open(url,'_blank'); } btn.disabled=false; btn.textContent='PDF'; } function pdfFromUrl(imgUrl) { // html2pdf normal a partir de URL loadPdfLib(function(err){ if (err || !window.html2pdf) { window.open(imgUrl,'_blank'); btn.disabled=false; btn.textContent='PDF'; return; } var div = document.createElement('div'); div.style.cssText = 'width:794px;padding:20px;background:#fff;text-align:center;position:fixed;left:-9999px;top:0;'; var img = new Image(); img.style.cssText = 'max-width:754px;width:100%;height:auto;'; img.onload = function(){ div.appendChild(img); document.body.appendChild(div); html2pdf().set({ margin:[10,10,10,10], filename: fname, image:{type:'jpeg',quality:0.95}, html2canvas:{scale:2,useCORS:true,allowTaint:false}, jsPDF:{unit:'mm',format:'a4',orientation:'portrait'}, }).from(div).save() .then(function(){ document.body.removeChild(div); btn.disabled=false; btn.textContent='PDF'; }) .catch(function(){ document.body.removeChild(div); window.open(imgUrl,'_blank'); btn.disabled=false; btn.textContent='PDF'; }); }; img.onerror = function(){ window.open(imgUrl,'_blank'); btn.disabled=false; btn.textContent='PDF'; }; img.src = imgUrl; }); } // Se colorCanvas existe (imagem editada), usa directamente — mais fiável que html2canvas if (colorCanvas) { pdfFromCanvas(colorCanvas); } else if (hasOverlays()) { captureImgWrap(function(canvas) { if (canvas) { pdfFromCanvas(canvas); } else { pdfFromUrl(url); } }); } else { pdfFromUrl(url); } }); // ═══════════════════════════════════════════════════════════ // WIDGET PERSONALIZAR // ═══════════════════════════════════════════════════════════ var imgWrap = document.getElementById('sc-img-wrap'); var custPanel = document.getElementById('sc-cust-panel'); var custToggle= document.getElementById('sc-cust-toggle'); // ── Mobile toggle ───────────────────────────────────────── if (custToggle && custPanel) { custPanel.hidden = false; custToggle.setAttribute('aria-expanded', 'true'); if (window.innerWidth <= 720) { custPanel.hidden = true; custToggle.setAttribute('aria-expanded', 'false'); } custToggle.addEventListener('click', function() { var open = custPanel.hidden; custPanel.hidden = !open; custToggle.setAttribute('aria-expanded', open ? 'true' : 'false'); }); window.addEventListener('resize', function() { if (window.innerWidth > 720) { custPanel.hidden = false; custToggle.setAttribute('aria-expanded', 'true'); } }); } // ── "About this coloring page" — collapsed by default on all screen // sizes, opens only on click (same interaction pattern as Customize, // but always starts closed regardless of viewport width). ────────── var aiToggle = document.getElementById('sc-ai-desc-toggle'); var aiPanel = document.getElementById('sc-ai-desc-panel'); if (aiToggle && aiPanel) { aiToggle.addEventListener('click', function() { var open = aiPanel.hidden; aiPanel.hidden = !open; aiToggle.setAttribute('aria-expanded', open ? 'true' : 'false'); }); } // ── Creates overlay wrap with inline styles (theme-proof) ─── var overlayWrap = null; var frameOverlay = null; if (imgWrap) { // Forces position:relative via JS — doesn't depend on the theme's CSS imgWrap.style.position = 'relative'; imgWrap.style.overflow = 'hidden'; overlayWrap = document.createElement('div'); overlayWrap.id = 'sc-overlay-wrap'; // writing-mode !important: blocks vertical inheritance from the theme overlayWrap.style.cssText = 'position:absolute;top:0;left:0;right:0;bottom:0;pointer-events:none;z-index:10;overflow:hidden;writing-mode:horizontal-tb !important;direction:ltr !important;'; frameOverlay = document.createElement('div'); frameOverlay.id = 'sc-frame-overlay'; frameOverlay.setAttribute('aria-hidden', 'true'); frameOverlay.style.cssText = 'position:absolute;top:0;left:0;width:100%;height:100%;pointer-events:none;display:none;'; overlayWrap.appendChild(frameOverlay); imgWrap.appendChild(overlayWrap); } // ── Frames — built entirely as SVG, no image files ────────── // Each frame is a decorative border drawn with vector paths/shapes, // stretched to fill the image box (viewBox 0 0 200 200, // preserveAspectRatio="none" — same stretch behaviour a PNG frame would have). // Black only, thin strokes — these are meant to be printed in black & white // alongside the coloring page itself, not decorative colored shapes. var FRAME_COLOR = '#000000'; function buildFrameSVG(id) { var c = FRAME_COLOR; var body = ''; switch (id) { case 1: // Simple — thin single-line border body = ''; break; case 2: // Double line — classic picture-frame style body = '' + ''; break; case 3: // Corner flourish — thin curled accents, open sides (certificate style) var flourish = function(x, y, rot) { return '' + '' + '' + ''; }; body = flourish(4, 4, 0) + flourish(196, 4, 90) + flourish(196, 196, 180) + flourish(4, 196, 270); break; case 4: // Dashed — thin dashed rectangle body = ''; break; case 5: // Scalloped — soft wavy edge, classic coloring-book border var bumps = []; var n = 12, r = 200 / n / 2; for (var i = 0; i < n; i++) { var cx = i * (200/n) + (200/n)/2; bumps.push(''); bumps.push(''); bumps.push(''); bumps.push(''); } body = bumps.join(''); break; case 6: // Dotted corners — small dot clusters at each corner, clean middle var dots = function(x, y) { var out = ''; var offs = [[0,0],[10,0],[0,10],[20,0],[0,20]]; for (var j = 0; j < offs.length; j++) { out += ''; } return out; }; body = '' + dots(10,10) + dots(180,10) + dots(180,180) + dots(10,180); break; default: body = ''; } return '' + body + ''; } // Fill in the small preview swatches in the Frames picker document.querySelectorAll('.sc-frame-preview').forEach(function(el) { var id = parseInt(el.dataset.framePreview, 10); el.innerHTML = buildFrameSVG(id); el.style.cssText = 'display:block;width:100%;height:100%;'; }); // ── Frame toggle ────────────────────────────────────────── var activeMolduraBtn = null; document.querySelectorAll('.sc-moldura-btn').forEach(function(btn) { btn.addEventListener('click', function() { var id = parseInt(btn.dataset.frame, 10); if (activeMolduraBtn === btn && frameOverlay.style.display !== 'none') { frameOverlay.style.display = 'none'; frameOverlay.innerHTML = ''; btn.classList.remove('active'); activeMolduraBtn = null; } else { if (activeMolduraBtn) activeMolduraBtn.classList.remove('active'); frameOverlay.innerHTML = buildFrameSVG(id); frameOverlay.style.display = 'block'; btn.classList.add('active'); activeMolduraBtn = btn; } }); }); // ── Adicionar Texto ─────────────────────────────────────── var addTextBtn = document.getElementById('sc-add-text'); if (addTextBtn) { addTextBtn.addEventListener('click', function() { if (!overlayWrap || !imgWrap) return; createTextItem(); }); } function createTextItem() { var wW = imgWrap.offsetWidth || 408; var wH = imgWrap.offsetHeight || 528; var item = document.createElement('div'); item.className = 'sc-text-item'; // necessário para hasOverlays() item.contentEditable = 'false'; item.textContent = 'Text here'; item.style.cssText = [ 'position:absolute', 'left:' + Math.round(wW * 0.20) + 'px', 'top:' + Math.round(wH * 0.30) + 'px', 'min-width:70px', 'padding:5px 10px', 'background:rgba(255,255,255,0.82)', 'border:1.5px dashed #1a73e8', 'border-radius:4px', 'cursor:move', 'pointer-events:all', 'font-size:20px', 'font-weight:700', 'color:#111', 'text-align:left', 'white-space:pre-wrap', 'word-break:break-word', 'user-select:none', '-webkit-user-select:none', 'box-shadow:0 2px 8px rgba(0,0,0,.18)', 'z-index:20', 'line-height:1.4', 'writing-mode:horizontal-tb !important', 'direction:ltr !important', 'font-family:Arial,sans-serif', 'max-width:' + Math.round(wW * 0.85) + 'px', ].join(';'); // Fechar var closeBtn = document.createElement('div'); closeBtn.style.cssText = 'position:absolute;top:-9px;right:-9px;width:18px;height:18px;background:#e53935;border-radius:50%;color:#fff;font-size:11px;line-height:18px;text-align:center;cursor:pointer;pointer-events:all;font-weight:700;z-index:21;'; closeBtn.innerHTML = '\u00d7'; closeBtn.title = 'Remove'; closeBtn.addEventListener('mousedown', function(e) { e.stopPropagation(); }); closeBtn.addEventListener('click', function(e) { e.stopPropagation(); item.remove(); }); // Resize handle var rh = document.createElement('div'); rh.style.cssText = 'position:absolute;bottom:-7px;right:-7px;width:15px;height:15px;background:#1a73e8;border-radius:50%;cursor:se-resize;pointer-events:all;z-index:21;border:2px solid #fff;'; rh.title = 'Resize'; item.appendChild(closeBtn); item.appendChild(rh); overlayWrap.appendChild(item); // Duplo clique → editar item.addEventListener('dblclick', function(e) { if (e.target === rh || e.target === closeBtn) return; item.contentEditable = 'true'; item.style.cursor = 'text'; item.style.userSelect = 'text'; item.style.webkitUserSelect = 'text'; item.focus(); if (item.textContent === 'Text here') { try { var r = document.createRange(); r.selectNodeContents(item); var s = window.getSelection(); s.removeAllRanges(); s.addRange(r); } catch(ex) {} } }); item.addEventListener('blur', function() { // Delay para não disparar quando o utilizador clica na alça de resize ou fechar setTimeout(function() { if (item.contentEditable !== 'true') return; // já foi tratado item.contentEditable = 'false'; item.style.cursor = 'move'; item.style.userSelect = 'none'; item.style.webkitUserSelect = 'none'; if (!item.textContent.trim()) item.textContent = 'Text here'; }, 150); }); // ── Drag ────────────────────────────────────────────── var dragging = false, dX, dY, dL, dT; item.addEventListener('mousedown', function(e) { if (e.target === rh || e.target === closeBtn) return; if (item.contentEditable === 'true') return; dragging = true; dX = e.clientX; dY = e.clientY; dL = parseInt(item.style.left)||0; dT = parseInt(item.style.top)||0; e.preventDefault(); }); document.addEventListener('mousemove', function(e) { if (!dragging) return; item.style.left = (dL + e.clientX - dX) + 'px'; item.style.top = (dT + e.clientY - dY) + 'px'; }); document.addEventListener('mouseup', function() { dragging = false; }); item.addEventListener('touchstart', function(e) { if (e.target === rh || e.target === closeBtn) return; if (item.contentEditable === 'true') return; var t = e.touches[0]; dragging = true; dX = t.clientX; dY = t.clientY; dL = parseInt(item.style.left)||0; dT = parseInt(item.style.top)||0; }, {passive:true}); document.addEventListener('touchmove', function(e) { if (!dragging) return; var t = e.touches[0]; item.style.left = (dL + t.clientX - dX) + 'px'; item.style.top = (dT + t.clientY - dY) + 'px'; }, {passive:true}); document.addEventListener('touchend', function() { dragging = false; }); // ── Resize (font-size) ──────────────────────────────── var resizing = false, rX0, rFs0; rh.addEventListener('mousedown', function(e) { e.stopPropagation(); e.preventDefault(); resizing = true; rX0 = e.clientX; rFs0 = parseFloat(window.getComputedStyle(item).fontSize)||20; }); document.addEventListener('mousemove', function(e) { if (!resizing) return; item.style.fontSize = Math.max(10, Math.min(120, rFs0 + (e.clientX - rX0) * 0.4)) + 'px'; }); document.addEventListener('mouseup', function() { resizing = false; }); rh.addEventListener('touchstart', function(e) { e.stopPropagation(); var t = e.touches[0]; resizing = true; rX0 = t.clientX; rFs0 = parseFloat(window.getComputedStyle(item).fontSize)||20; }, {passive:true}); document.addEventListener('touchmove', function(e) { if (!resizing) return; var t = e.touches[0]; item.style.fontSize = Math.max(10, Math.min(120, rFs0 + (t.clientX - rX0) * 0.4)) + 'px'; }, {passive:true}); document.addEventListener('touchend', function() { resizing = false; }); } // ═══════════════════════════════════════════════════════════ // COLORIR — canvas + flood fill + caneta // ═══════════════════════════════════════════════════════════ var colorCanvas = null; var colorCtx = null; var currentColor = '#e74c3c'; var currentTool = 'bucket'; // 'bucket' | 'pen' var penSz = 5; var penDrawing = false; var penLastX = 0, penLastY = 0; var colorirBtn = document.getElementById('sc-colorir'); var colorirPanel = document.getElementById('sc-colorir-panel'); var toolBucket = document.getElementById('sc-tool-bucket'); var toolPen = document.getElementById('sc-tool-pen'); function hexToRgb(hex) { return { r: parseInt(hex.slice(1,3),16), g: parseInt(hex.slice(3,5),16), b: parseInt(hex.slice(5,7),16), }; } // Cria canvas sobre a imagem principal (carrega com crossOrigin) function activateColorCanvas(cb) { if (colorCanvas) { if (cb) cb(); return; } var mainImg = imgWrap ? imgWrap.querySelector('.sc-main-img') : null; if (!mainImg || !overlayWrap) return; var dW = imgWrap.offsetWidth; var dH = imgWrap.offsetHeight; colorCanvas = document.createElement('canvas'); colorCanvas.width = dW; colorCanvas.height = dH; colorCanvas.style.cssText = [ 'position:absolute','top:0','left:0', 'width:100%','height:100%', 'z-index:12','pointer-events:all', 'writing-mode:horizontal-tb !important', ].join(';'); colorCtx = colorCanvas.getContext('2d', {willReadFrequently: true}); function draw(src) { var tmp = new Image(); tmp.onload = function() { colorCtx.clearRect(0, 0, dW, dH); colorCtx.drawImage(tmp, 0, 0, dW, dH); overlayWrap.insertBefore(colorCanvas, overlayWrap.firstChild); updateColorCursor(); if (cb) cb(); }; tmp.src = src; } // Tenta com crossOrigin (necessário para getImageData sem taint) var probe = new Image(); probe.crossOrigin = 'anonymous'; probe.onload = function() { draw(probe.src); }; probe.onerror = function() { // crossOrigin falhou (hotlink?); carrega sem — bucket não funciona mas caneta sim draw(mainImg.src); }; probe.src = mainImg.src + (mainImg.src.indexOf('?') < 0 ? '?' : '&') + '_cc=1'; } function updateColorCursor() { if (!colorCanvas) return; colorCanvas.style.cursor = currentTool === 'pen' ? 'crosshair' : 'cell'; } // ── Flood fill (BFS) ────────────────────────────────────── function floodFill(sx, sy) { var w = colorCanvas.width, h = colorCanvas.height; var imgData; try { imgData = colorCtx.getImageData(0, 0, w, h); } catch(e) { return; } // canvas tainted (sem CORS) var d = imgData.data; var si = (sy * w + sx) * 4; var tr = d[si], tg = d[si+1], tb = d[si+2]; var bri = tr * 0.299 + tg * 0.587 + tb * 0.114; if (bri < 80) return; // clicou numa linha escura → não preenche var fc = hexToRgb(currentColor); if (Math.abs(tr-fc.r)<4 && Math.abs(tg-fc.g)<4 && Math.abs(tb-fc.b)<4) return; var tol = 38; var vis = new Uint8Array(w * h); var stk = [sx + sy * w]; vis[stk[0]] = 1; while (stk.length) { var pos = stk.pop(); var x = pos % w; var y = (pos - x) / w; var i = pos * 4; // Barreira escura if (d[i]*0.299 + d[i+1]*0.587 + d[i+2]*0.114 < 75) continue; // Diferença em relação à cor alvo if (Math.abs(d[i]-tr)>tol || Math.abs(d[i+1]-tg)>tol || Math.abs(d[i+2]-tb)>tol) continue; // Blend suave: mantém escuridão relativa dos pixels cinzentos var t = Math.min(1, Math.max(0, (d[i]*0.299+d[i+1]*0.587+d[i+2]*0.114 - 75) / 170)); d[i] = Math.round(fc.r * t + d[i] * (1-t)); d[i+1] = Math.round(fc.g * t + d[i+1] * (1-t)); d[i+2] = Math.round(fc.b * t + d[i+2] * (1-t)); d[i+3] = 255; if (x>0 && !vis[pos-1]) { vis[pos-1]=1; stk.push(pos-1); } if (x0 && !vis[pos-w]) { vis[pos-w]=1; stk.push(pos-w); } if (y