2012-04-23 8 views
15

Sto creando un "generatore di immagini" in cui gli utenti possono caricare un'immagine e aggiungere testo e/o disegnare su di esso. L'immagine prodotta è una dimensione fissa (698x450).Qual è la matematica dietro la dimensione di sfondo del CSS: copertina

Sul lato client, quando l'utente carica la propria immagine viene impostato come sfondo di un div che è 698x450 con background-size: cover. Questo fa riempire bene l'area.

L'immagine combinata finale viene generata da PHP utilizzando le funzioni GD. La mia domanda è, come posso ottenere l'immagine in scala in PHP nello stesso modo in cui lo fa nei CSS. Voglio che il risultato dello script PHP abbia lo stesso aspetto di come l'immagine fosse impostata in CSS come era in precedenza. Qualcuno sa in che modo i browser utilizzano la dimensione dello sfondo: la copertina calcola come ridimensionare l'immagine in modo appropriato? Voglio tradurre questo in PHP.

Grazie

risposta

40

Ecco una logica dietro i calcoli di copertura.

Sono disponibili quattro valori di base:

imgWidth // your original img width 
imgHeight 

containerWidth // your container width (here 698px) 
containerHeight 

due rapporti derivati ​​da questi valori:

imgRatio = (imgHeight/imgWidth)  // original img ratio 
containerRatio = (containerHeight/containerWidth)  // container ratio 

Si vuole trovare due nuovi valori:

finalWidth // the scaled img width 
finalHeight 

Quindi:

if (containerRatio > imgRatio) 
{ 
    finalHeight = containerHeight 
    finalWidth = (containerHeight/imgRatio) 
} 
else 
{ 
    finalWidth = containerWidth 
    finalHeight = (containerWidth/imgRatio) 
} 

... e si ha l'equivalente di una dimensione di sfondo: copertina.

+10

Non so perché, ma ho dovuto modificare l'ultima riga come 'finalHeight = (containerWidth * imgRatio)' per funzionare correttamente per il mio codice – Ergec

3

Quando si utilizza background-size: cover, è scalato alla dimensione più piccola che copre l'intero sfondo.

Quindi, dove è più sottile di quanto è alto, ridimensionarlo finché la sua larghezza non è uguale all'area. Dove è più alto di quanto non sia sottile, ridimensionalo fino a raggiungere l'altezza uguale a quella dell'area.

Quando è più grande dell'area da coprire, ridimensionarla finché non si adatta (se c'è meno trabocco in altezza, scala fino alla stessa altezza, se c'è meno trabocco di larghezza, scala fino alla stessa larghezza).

3

Grazie a mdi per avermi indicato nella giusta direzione, ma non mi sembrava giusto. Questa è la soluzione che ha funzionato per me:

$imgRatio = $imageHeight/$imageWidth; 
    $canvasRatio = $canvasHeight/$canvasWidth; 

    if ($canvasRatio > $imgRatio) { 
     $finalHeight = $canvasHeight; 
     $scale = $finalHeight/$imageHeight; 
     $finalWidth = round($imageWidth * $scale , 0); 
    } else { 
     $finalWidth = $canvasWidth; 
     $scale = $finalWidth/$imageWidth; 
     $finalHeight = round($imageHeight * $scale , 0); 
    } 
2

So che questa è una domanda molto vecchio, ma la risposta che ho scritto è in realtà più pulita utilizzando max e min sui rapporti tra le immagini al posto di ogni immagine con stessa:

var originalRatios = { 
    width: containerWidth/imageNaturalWidth, 
    height: containerHeight/imageNaturalHeight 
}; 

// formula for cover: 
var coverRatio = Math.max(originalRatios.width, originalRatios.height); 

// result: 
var newImageWidth = imageNaturalWidth * coverRatio; 
var newImageHeight = imageNaturalHeight * coverRatio; 

mi piace questo approccio, perché è molto sistematica - forse è la parola sbagliata -.Quello che voglio dire è che si può sbarazzarsi dei if dichiarazioni e farlo funzionare in un tipo più "formula matematica" di modo (ingresso = uscita, se questo ha un senso):

var ratios = { 
    cover: function(wRatio, hRatio) { 
    return Math.max(wRatio, hRatio); 
    }, 

    contain: function(wRatio, hRatio) { 
    return Math.min(wRatio, hRatio); 
    }, 

    // original size 
    "auto": function() { 
    return 1; 
    }, 

    // stretch 
    "100% 100%": function(wRatio, hRatio) { 
    return { width:wRatio, height:hRatio }; 
    } 
}; 

function getImageSize(options) { 
    if(!ratios[options.size]) { 
    throw new Error(size + " not found in ratios"); 
    } 

    var r = ratios[options.size](
    options.container.width/options.image.width, 
    options.container.height/options.image.height 
); 

    return { 
    width: options.image.width * (r.width || r), 
    height: options.image.height * (r.height || r) 
    }; 
} 

ho creato un jsbinhere se vuoi dare un'occhiata a cosa intendo con sistematico (ha anche un metodo scale che pensavo non fosse necessario in questa risposta ma molto utile per qualcosa di diverso dal solito).

Problemi correlati