2012-04-23 5 views
15

Estoy creando un "generador de imágenes" donde los usuarios pueden cargar una imagen y agregar texto y/o dibujar en ella. La imagen generada tiene un tamaño fijo (698x450).¿Cuál es la matemática detrás del tamaño de fondo de CSS: cover

En el lado del cliente, cuando el usuario carga su imagen, se establece como fondo de un div que es 698x450 con fondo de tamaño: portada. Esto hace que llene el área muy bien.

La última imagen combinada es generada por PHP usando funciones GD. Mi pregunta es, ¿cómo puedo obtener la imagen para escalar en PHP de la misma manera que lo hace en CSS. Quiero que el resultado del script PHP se vea igual que si la imagen estuviera configurada en CSS como estaba arriba. ¿Alguien sabe cómo los navegadores que usan tamaño de fondo: cubren calculan cómo escalar la imagen de forma apropiada? Quiero traducir esto en PHP.

Gracias

Respuesta

40

Aquí hay una lógica detrás de los cálculos de la cubierta.

Tienes cuatro valores básicos:

imgWidth // your original img width 
imgHeight 

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

dos relaciones derivadas de estos valores:

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

Usted quiere encontrar dos nuevos valores:

finalWidth // the scaled img width 
finalHeight 

Así:

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

... y tiene el equivalente de una cubierta de tamaño de fondo.

+10

No estoy seguro por qué pero tuve que cambiar la última línea como 'finalHeight = (containerWidth * imgRatio)' para que funcione correctamente para mi código – Ergec

3

Al utilizar background-size: cover, se escala al tamaño más pequeño que cubre todo el fondo.

Por lo tanto, cuando es más delgada que alta, escala hasta que su ancho sea el mismo que el área. Donde es más alto que delgado, escala hasta que su altura sea la misma que el área.

Cuando es más grande que el área a cubrir, descálgalo hasta que encaje (si hay menos sobreflujo en altura, escala hasta la misma altura, si hay menos sobreflujo en ancho, escala hasta el mismo ancho).

3

Gracias a mdi por señalarme en la dirección correcta, pero eso no parecía del todo bien. Esta es la solución que funcionó para mí:

$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

Sé que esto es una pregunta muy antigua, pero la respuesta que escribí es en realidad más limpio mediante el uso de max y min de las relaciones entre las imágenes en lugar de cada imagen con sí:

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; 

me gusta este enfoque porque es muy sistemática - tal vez es la palabra equivocada -.Lo que quiero decir es que puede deshacerse de los if declaraciones y hacer que funcione en un tipo más "fórmula matemática" de forma (entrada = salida, si eso tiene sentido):

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) 
    }; 
} 

he creado un jsbinhere si quieres ver lo que quiero decir con sistemática (también tiene un método scale que pensé que no era necesario en esta respuesta, pero muy útil para algo distinto de lo habitual).

Cuestiones relacionadas