PerfectVector
Di Irene Kim

SVG feComposite: confronta grafica con in, out e xor

Confronta input dei filtri SVG con in, out e xor, prova ordine e alfa parziale e conserva i tracciati quando un’apertura visiva non è geometria modificabile.

11 min di lettura
In questa pagina

SVG feComposite combina due input renderizzati. Con input completamente opachi, in mantiene il primo nella sovrapposizione, out lo mantiene fuori e xor combina entrambi al di fuori della sovrapposizione comune. Queste operazioni cambiano la pittura durante il rendering. Non riscrivono i tracciati sorgente in un’intersezione o differenza modificabile.

La distinzione conta quando una sovrapposizione sembra un’apertura ma la consegna richiede contorni reali. L’esempio seguente confronta due nostre forme asimmetriche originali, inverte gli input e verifica la trasparenza parziale. Conserva la grafica sorgente accanto al risultato filtrato.

Assegna un nome a entrambi gli input prima di scegliere l’operatore

Il riferimento MDN su feComposite descrive un’operazione per pixel nello spazio dell’immagine. in nomina il primo input, in2 il secondo. Assegna nomi espliciti ai risultati intermedi, così una modifica della catena di filtri non cambia silenziosamente gli operandi.

Per interni opachi, queste tre operazioni sono facili da confrontare:

OperazionePrimo input A, secondo input BCosa cambia invertendo gli input
inPittura di A nella sovrapposizioneLa sovrapposizione assume invece la pittura di B
outPittura di A fuori da BLa pittura di B fuori da A è una regione diversa
xorEntrambi gli input fuori dalla sovrapposizione opaca comuneRestano le stesse regioni non sovrapposte

Lo stesso attributo operator compare anche su altre primitive di filtro con valori diversi. Esplicita il contesto di composizione: il riferimento MDN su operator lo distingue dalle operazioni morfologiche.

Cambia la pittura visibile
Confronto concettuale di grafica colorata sovrapposta e una composizione con sovrapposizione non dipinta
Illustrazione: input sovrapposti possono lasciare una regione non dipinta. Sagome decorative e frecce sono concettuali; operatori esatti, campioni alfa e tracciati invariati sotto provengono da un test originale eseguito nel browser.

Allinea esplicitamente la seconda grafica

Il primo operando A è un blocco a gradini verde petrolio. B è un aquilone obliquo ocra. Entrambi usano lo stesso viewBox 0 0 240 160. B si estende oltre il riquadro locale di A, quindi usare i limiti di A come regione del filtro sarebbe una cattiva ipotesi iniziale.

Il filtro usa filterUnits="userSpaceOnUse" per la regione esplicita x=0, y=0, width=240, height=160. Il riferimento MDN su filterUnits spiega la scelta delle coordinate. Impostiamo anche primitiveUnits="userSpaceOnUse" e diamo al secondo input le stesse coordinate dell’intera cornice.

B è un URL di dati SVG autonomo passato tramite feImage, con nome del risultato operandB. Entra nel filtro come input immagine; il suo tracciato non viene inserito come nuovo figlio diretto della grafica filtrata. Il riferimento MDN su feImage descrive il comportamento dell’input immagine.

Il filtro seleziona esplicitamente sRGB. Il valore predefinito di queste primitive è linearRGB, come documentato nel riferimento feComposite. Né quel valore né il nome dell’operatore forniscono un’operazione di modifica dei tracciati.

Esegui il confronto originale completo

Salvalo come starter.html e servi la cartella tramite HTTP locale, per esempio con python3 -m http.server 8766 --bind 127.0.0.1. Apri http://127.0.0.1:8766/starter.html; usa un’altra porta libera se necessario.

La pagina crea due originali più sette casi filtrati per ciascuna di due dimensioni esplicite. Ogni ID del filtro include caso e larghezza, così più SVG inline nello stesso documento hanno riferimenti univoci. Ogni collegamento Save SVG conserva il filtro autonomo e il suo input B codificato.

<!doctype html>
<html lang="en">
<meta charset="utf-8">
<title>Original SVG composite artwork</title>
<style>
  body { margin: 24px; font: 16px system-ui; background: #f6f2e8; }
  main { display: grid; grid-template-columns: repeat(3, 260px); gap: 18px; }
  figure { margin: 0; }
  svg { display: block; background: white; border: 1px solid #bbb; }
  figcaption { margin: 6px 0; }
  pre { white-space: pre-wrap; font-size: 12px; }
</style>
<h1>Original operands and rendered composites</h1>
<main id="cases"></main>
<pre id="report"></pre>
<script>
  const A = 'M24 24 H132 V56 H192 V136 H24 Z';
  const B = 'M92 8 L216 84 L92 152 L60 84 Z';
  const svgNS = 'http://www.w3.org/2000/svg';
  const cases = [
    { id: 'a' }, { id: 'b' },
    { id: 'a-in-b', operator: 'in' },
    { id: 'a-out-b', operator: 'out' },
    { id: 'a-xor-b', operator: 'xor' },
    { id: 'b-in-a', operator: 'in', reverse: true },
    { id: 'b-out-a', operator: 'out', reverse: true },
    { id: 'b-xor-a', operator: 'xor', reverse: true },
    { id: 'a-out-half-b', operator: 'out', opacity: 0.5 },
  ];
  function documentSVG(test, width) {
    const height = width * 2 / 3;
    const id = test.id + '-' + width;
    const second = '<svg xmlns="' + svgNS + '" width="240" height="160" viewBox="0 0 240 160">'
      + '<path d="' + B + '" fill="#d4a53a" opacity="' + (test.opacity ?? 1) + '"/></svg>';
    const href = 'data:image/svg+xml;charset=utf-8,' + encodeURIComponent(second);
    const first = test.reverse ? 'operandB' : 'SourceGraphic';
    const other = test.reverse ? 'SourceGraphic' : 'operandB';
    const defs = test.operator ? '<defs><filter id="' + id + '" filterUnits="userSpaceOnUse" primitiveUnits="userSpaceOnUse" x="0" y="0" width="240" height="160" color-interpolation-filters="sRGB">'
      + '<feImage href="' + href + '" x="0" y="0" width="240" height="160" preserveAspectRatio="none" result="operandB"/>'
      + '<feComposite in="' + first + '" in2="' + other + '" operator="' + test.operator + '"/></filter></defs>' : '';
    return '<svg xmlns="' + svgNS + '" width="' + width + '" height="' + height + '" viewBox="0 0 240 160">'
      + defs + '<path d="' + (test.id === 'b' ? B : A) + '" fill="' + (test.id === 'b' ? '#d4a53a' : '#176b5b')
      + '"' + (test.operator ? ' filter="url(#' + id + ')"' : '') + '/></svg>';
  }
  async function run() {
    const results = [];
    for (const width of [120, 240]) {
      for (const test of cases) {
        const source = documentSVG(test, width);
        const svg = new DOMParser().parseFromString(source, 'image/svg+xml').documentElement;
        const figure = document.createElement('figure');
        const caption = document.createElement('figcaption');
        caption.textContent = test.id + ', ' + width + ' × ' + width * 2 / 3;
        figure.append(document.importNode(svg, true), caption);
        document.getElementById('cases').append(figure);
        const path = figure.querySelector('path');
        const bbox = path.getBBox();
        const image = new Image();
        image.src = 'data:image/svg+xml;charset=utf-8,' + encodeURIComponent(source);
        await image.decode();
        const canvas = document.createElement('canvas');
        canvas.width = width;
        canvas.height = width * 2 / 3;
        const ctx = canvas.getContext('2d');
        ctx.drawImage(image, 0, 0);
        const sample = (x, y) => [...ctx.getImageData(Math.floor(x * width / 240), Math.floor(y * width / 240), 1, 1).data];
        const hash = [...new Uint8Array(await crypto.subtle.digest('SHA-256', new TextEncoder().encode(path.getAttribute('d'))))]
          .map(v => v.toString(16).padStart(2, '0')).join('');
        const download = document.createElement('a');
        download.href = image.src;
        download.download = test.id + '-' + width + '.svg';
        download.textContent = 'Save SVG';
        figure.append(download);
        results.push({ id: test.id, width, height: canvas.height, d: path.getAttribute('d'), dSHA256: hash,
          bbox: { x: bbox.x, y: bbox.y, width: bbox.width, height: bbox.height },
          directPaths: svg.querySelectorAll('path').length, filterImages: svg.querySelectorAll('feImage').length,
          aOnly: sample(40, 40), bOnly: sample(200, 84), overlap: sample(120, 84), outside: sample(230, 150) });
      }
    }
    document.getElementById('report').textContent = JSON.stringify({ A, B, results }, null, 2);
  }
  run();
</script>
</html>

Il codice conserva lo stesso tracciato diretto A anche quando gli input dell’operatore sono invertiti. Per esempio, b-in-a cambia feComposite in in="operandB" e in2="SourceGraphic"; non sostituisce l’elemento sorgente filtrato con B. Questo rende visibile l’ordine degli operandi senza alterare la geometria A sottostante.

L’ispezione dei pixel legge qui un canvas dipinto da ogni SVG generato. Il file scaricabile resta l’SVG filtrato. Non è un nuovo tracciato booleano o una conversione PerfectVector.

Confronta pittura e geometria separatamente

Abbiamo eseguito esattamente questa pagina in un ambiente Chrome a 120 × 80 e 240 × 160, salvato tutti i 18 SVG e riaperto come immagini nello stesso browser. Le dimensioni visualizzate sono input espliciti, non un’affermazione su due dispositivi fisici.

Tre posizioni interne usano il sistema di coordinate originale: solo A (40,40), solo B (200,84) e sovrapposizione (120,84). Sono stati osservati i seguenti valori alfa a entrambe le dimensioni con operandi opachi:

Input del filtro e operatoreAlfa solo AAlfa solo BAlfa sovrapposizione
A in B00255
A out B25500
A xor B2552550
B in A00255
B out A02550
B xor A2552550

Le righe in condividono una sovrapposizione opaca ma differiscono per colore: con A primo era verde petrolio (23,107,91,255), con B primo ocra (212,165,58,255). Il campione esterno (230,150) restava sempre trasparente. Sono pixel interni selezionati, non un test completo della copertura dei bordi o della compatibilità.

Ogni file filtrato conservava l’esatta stringa d originale di A e lo stesso SHA-256. Il getBBox() geometrico locale restava x=24, y=24, width=168, height=112. Quel riquadro descrive il tracciato sorgente; non è il riquadro dei pixel visibili del filtro. Anche il tracciato B codificato restava invariato. Un risultato filtrato può quindi apparire diverso mentre entrambi i contorni creati restano intatti.

Gli originali salvati hanno un tracciato diretto e nessuna immagine di filtro. Ogni file filtrato ha un tracciato diretto A più un feImage che trasporta l’SVG separato di B con un solo tracciato. Non viene introdotto un normale elemento raster image. Un’operazione renderizzata nello spazio dell’immagine e operandi sorgente vettoriali possono coesistere; il solo inventario della sorgente non significa che il risultato sia diventato geometria combinata modificabile.

L’opacità parziale cambia il significato di un’apertura

L’ultimo caso rende B opaco a metà lasciando A opaco, poi applica A out B. La sovrapposizione non diventa vuota. A entrambe le dimensioni, il valore RGBA osservato era (22,106,90,127): verde petrolio parzialmente trasparente, con arrotondamenti dalla catena di rendering e lettura.

Per out, l’alfa di output è il primo alfa moltiplicato per uno meno il secondo. Per in, è il loro prodotto. La definizione di composizione Filter Effects definisce le operazioni con colori premoltiplicati e alfa. B opaco può rimuovere la pittura sovrapposta di A; B parzialmente trasparente ne lascia una parte.

Esamina il risultato sullo sfondo effettivo. Una regione chiara sul bianco può essere pittura traslucida anziché un foro completamente trasparente. Anche i pixel dei bordi antialias richiedono verifica visiva; il campione interno non promette alfa zero per ogni pixel del confine. Per un lavoro separato di rimappatura dell’opacità, consulta la guida alle soglie alfa SVG.

Consegna un effetto di filtro o crea contorni reali

Conserva questo filtro quando il renderer ricevente deve riprodurre la composizione visiva. Mantieni i file A e B originali e controlla l’SVG filtrato riaperto nella destinazione effettiva. La riapertura riuscita nel nostro browser non certifica altri renderer o macchine di produzione.

Se la consegna richiede contorni combinati selezionabili o un’apertura pronta per il taglio, esegui e controlla una vera modifica dei tracciati o un’operazione booleana nel procedimento previsto. La pittura visibile cambiata qui non crea quella geometria. La guida clipPath contro maschera chiarisce una distinzione correlata sulla visibilità; la guida alla separazione dei gruppi SVG aiuta quando la grafica visualizzata non è l’oggetto modificabile atteso.

Se la clipart esiste solo come pixel e ti servono forme sorgente modificabili, prepara un SVG di clipart con PerfectVector, esamina contorni e aperture e conserva il master. Applica e verifica separatamente il filtro o l’operazione sui tracciati desiderati. La vettorializzazione non trasforma la sovrapposizione visiva di questo filtro in un contorno di produzione verificato.

Domande frequenti

feComposite out elimina la geometria del tracciato sovrapposto? No. Cambia la pittura renderizzata usando l’alfa del secondo input. Nei nostri file filtrati, dati originali del tracciato A e limiti geometrici locali restavano invariati anche dove la pittura sovrapposta diventava trasparente.

Perché scambiare in e in2 cambia il risultato? Identificano primo e secondo input. In mantiene la pittura del primo nell’opacità del secondo; out mantiene il primo fuori. I nostri casi in invertiti condividono la sovrapposizione opaca ma mostrano colori diversi, mentre i casi out invertiti conservano regioni diverse.

xor crea sempre una sovrapposizione completamente vuota? La sovrapposizione interna completamente opaca era vuota nei nostri casi xor. Alfa parziale e bordi antialias richiedono controlli specifici; i diagrammi di insiemi di forme opache non descrivono ogni pixel traslucido.

Posso inviare direttamente l’apertura filtrata come tracciato di taglio modificabile? Un risultato visivo di filtro non è nuova geometria booleana creata. Conserva le forme originali, crea e controlla i contorni richiesti nel procedimento di tracciati previsto e verifica separatamente applicazione ricevente e requisiti di produzione.

Fonti

  1. MDN: feComposite — Ruoli degli input nello spazio dell’immagine, operatori e spazio colore predefinito del filtro.
  2. MDN: operator — Valori degli operatori di composizione e contesto morfologico separato.
  3. MDN: filterUnits — Sistema di coordinate della regione del filtro.
  4. MDN: feImage — Input immagine nella catena di filtri.
  5. W3C: Composizione Filter Effects — Definizioni della composizione di colore premoltiplicato e alfa.

Parti da una tua clipart raster? Crea un master SVG modificabile, controlla contorni e aperture, poi conservalo mentre verifichi nella destinazione la composizione visiva scelta o il risultato di tracciati creato separatamente.

Altro dal blog

PerfectVector

Riparti da un SVG più pulito
e facile da modificare

Nessuna carta di credito