Download je Canva designs met transparante achtergrond zonder Pro versie
Size
8.6 KB
Version
1.1.4
Created
Oct 19, 2025
Updated
4 days ago
1// ==UserScript==
2// @name Canva Transparante Achtergrond Downloader
3// @description Download je Canva designs met transparante achtergrond zonder Pro versie
4// @version 1.1.4
5// @match https://*.canva.com/*
6// @icon https://static.canva.com/static/images/favicons/favicon_web_print.ico
7// @require https://cdnjs.cloudflare.com/ajax/libs/html2canvas/1.4.1/html2canvas.min.js
8// ==/UserScript==
9(function() {
10 'use strict';
11
12 console.log('Canva Transparante Achtergrond Downloader gestart');
13
14 // Debounce functie om te voorkomen dat de knop meerdere keren wordt toegevoegd
15 function debounce(func, wait) {
16 let timeout;
17 return function executedFunction(...args) {
18 const later = () => {
19 clearTimeout(timeout);
20 func(...args);
21 };
22 clearTimeout(timeout);
23 timeout = setTimeout(later, wait);
24 };
25 }
26
27 // Functie om de download knop toe te voegen
28 function addDownloadButton() {
29 // Check of de knop al bestaat
30 if (document.getElementById('transparent-download-btn')) {
31 console.log('Download knop bestaat al');
32 return;
33 }
34
35 // Zoek de toolbar container waar de "Delen" knop staat
36 const shareButtonContainer = document.querySelector('div._2WzgFw._8drCYA');
37
38 if (!shareButtonContainer) {
39 console.log('Toolbar container nog niet gevonden, probeer later opnieuw');
40 return;
41 }
42
43 console.log('Toolbar container gevonden, voeg download knop toe');
44
45 // Maak een nieuwe container voor onze knop
46 const buttonWrapper = document.createElement('div');
47 buttonWrapper.className = '_7nAWcw';
48 buttonWrapper.id = 'transparent-download-btn';
49
50 // Maak de download knop met dezelfde styling als andere knoppen
51 const downloadButton = document.createElement('button');
52 downloadButton.className = '_5KtATA LQzFZw VgvqkQ _8ERLTg MCgm0w Z3nT2A LQzFZw VgvqkQ _4_iekA j34Zww aqbYPg _3FvZZg uyUyGw VOvjeA';
53 downloadButton.type = 'button';
54 downloadButton.setAttribute('role', 'menuitem');
55 downloadButton.style.cssText = 'background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white; font-weight: 600; padding: 8px 16px; border-radius: 8px; margin-left: 8px;';
56
57 const buttonContent = document.createElement('span');
58 buttonContent.className = 'vxQy1w';
59 buttonContent.innerHTML = '⬇️ PNG Transparant';
60
61 downloadButton.appendChild(buttonContent);
62 buttonWrapper.appendChild(downloadButton);
63
64 // Voeg de knop toe aan de toolbar
65 shareButtonContainer.appendChild(buttonWrapper);
66
67 console.log('Download knop toegevoegd aan toolbar');
68
69 // Voeg click event toe
70 downloadButton.addEventListener('click', async function() {
71 console.log('Download knop geklikt');
72 downloadButton.disabled = true;
73 buttonContent.innerHTML = '⏳ Bezig...';
74
75 try {
76 await downloadTransparentPNG();
77 buttonContent.innerHTML = '✅ Gelukt!';
78 setTimeout(() => {
79 buttonContent.innerHTML = '⬇️ PNG Transparant';
80 downloadButton.disabled = false;
81 }, 2000);
82 } catch (error) {
83 console.error('Download fout:', error);
84 buttonContent.innerHTML = '❌ Fout';
85 alert('Er ging iets mis: ' + error.message);
86 setTimeout(() => {
87 buttonContent.innerHTML = '⬇️ PNG Transparant';
88 downloadButton.disabled = false;
89 }, 2000);
90 }
91 });
92 }
93
94 // Functie om witte pixels transparant te maken
95 function makeWhiteTransparent(canvas, threshold = 240) {
96 const ctx = canvas.getContext('2d');
97 const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
98 const data = imageData.data;
99
100 // Loop door alle pixels
101 for (let i = 0; i < data.length; i += 4) {
102 const red = data[i];
103 const green = data[i + 1];
104 const blue = data[i + 2];
105
106 // Als de pixel (bijna) wit is, maak het transparant
107 if (red > threshold && green > threshold && blue > threshold) {
108 data[i + 3] = 0; // Zet alpha naar 0 (transparant)
109 }
110 }
111
112 ctx.putImageData(imageData, 0, 0);
113 return canvas;
114 }
115
116 // Functie om het design te downloaden met transparante achtergrond
117 async function downloadTransparentPNG() {
118 console.log('Start download proces...');
119
120 // Zoek het design viewport element
121 const designViewport = document.querySelector('div[data-page-id="0"]');
122
123 if (!designViewport) {
124 throw new Error('Kon het design niet vinden. Zorg dat je design volledig geladen is.');
125 }
126
127 console.log('Design viewport gevonden');
128
129 console.log('Maak screenshot van design...');
130
131 // Maak screenshot met transparante achtergrond en skip oklch kleuren
132 const canvas = await html2canvas(designViewport, {
133 backgroundColor: null,
134 scale: 2,
135 logging: false,
136 useCORS: true,
137 allowTaint: true,
138 ignoreElements: function(element) {
139 // Skip elementen die problemen kunnen veroorzaken
140 const style = window.getComputedStyle(element);
141 const bgColor = style.backgroundColor;
142 const color = style.color;
143
144 // Check of het oklch gebruikt (geeft parsing errors)
145 if (bgColor && bgColor.includes('oklch')) {
146 return true;
147 }
148 if (color && color.includes('oklch')) {
149 return true;
150 }
151
152 return false;
153 },
154 onclone: function(clonedDoc) {
155 // Fix oklch kleuren in de gekloonde document
156 const allElements = clonedDoc.querySelectorAll('*');
157 allElements.forEach(element => {
158 const style = window.getComputedStyle(element);
159
160 // Vervang oklch kleuren met fallback kleuren
161 if (style.backgroundColor && style.backgroundColor.includes('oklch')) {
162 element.style.backgroundColor = 'transparent';
163 }
164 if (style.color && style.color.includes('oklch')) {
165 element.style.color = '#000000';
166 }
167 if (style.borderColor && style.borderColor.includes('oklch')) {
168 element.style.borderColor = 'transparent';
169 }
170
171 // Verwijder witte achtergronden
172 const bgColor = style.backgroundColor;
173 if (bgColor === 'rgb(255, 255, 255)' || bgColor === '#ffffff' || bgColor === 'white') {
174 element.style.backgroundColor = 'transparent';
175 }
176 });
177 }
178 });
179
180 console.log(`Canvas gemaakt: ${canvas.width}x${canvas.height}`);
181
182 // Maak witte pixels transparant
183 console.log('Verwijder witte achtergrond...');
184 makeWhiteTransparent(canvas, 240);
185
186 // Converteer naar PNG blob
187 const blob = await new Promise(resolve => {
188 canvas.toBlob(resolve, 'image/png', 1.0);
189 });
190
191 // Download de afbeelding
192 const url = URL.createObjectURL(blob);
193 const link = document.createElement('a');
194
195 // Probeer de design naam te krijgen uit de pagina titel
196 const designName = document.title.split(' - ')[0] || 'canva-design';
197 link.download = `${designName}-transparent.png`;
198 link.href = url;
199 link.click();
200
201 // Cleanup
202 setTimeout(() => URL.revokeObjectURL(url), 100);
203
204 console.log('Download succesvol!');
205 }
206
207 // Observeer DOM veranderingen om de knop toe te voegen wanneer de toolbar geladen is
208 const debouncedAddButton = debounce(addDownloadButton, 500);
209
210 const observer = new MutationObserver(debouncedAddButton);
211
212 observer.observe(document.body, {
213 childList: true,
214 subtree: true
215 });
216
217 // Probeer de knop direct toe te voegen
218 if (document.readyState === 'loading') {
219 document.addEventListener('DOMContentLoaded', addDownloadButton);
220 } else {
221 setTimeout(addDownloadButton, 2000);
222 }
223
224 console.log('Extensie geïnitialiseerd');
225})();