2011-05-11 2 views
0

Moi et un collège essayons de construire une méthode qui peut trouver la plus grande taille pour une sélection affichée par défaut dans une image. La sélection a un ratio.PHP: Trouver la dimension maximum upscalée tout en respectant un ratio

Jusqu'à présent, nous avons essayé ceci:

public function findBestSizeForRatio($inputW, $inputH, $ratioW, $ratioH) 
{ 
    if($inputW/$ratioW > $ratioH/$inputH){ 
     $w = floor($inputW/$ratioW) * $ratioW; 
     $h = $w * $ratioH/$ratioW; 
    } 
    else{ 
     $h = floor($inputH/$ratioH) * $ratioH; 
     $w = $h * $ratioW/$ratioH; 
    } 

    return array($w, $h); 
} 

Mais échouer nos tests unitaires.

Nous avons également essayé ceci:

public function findBestSizeForRatio($inputW, $inputH, $ratioW, $ratioH) 
{ 
    return $this->findBestSizeInBox($ratioW*10000, $ratioH*10000, $inputW, $inputH); 
} 
public function findBestSizeInBox($inputW, $inputH, $boxW, $boxH) 
{ 
    if($inputW/$boxW > $inputH/$boxH){ 
     return array($boxW, round($inputH * $boxW/$inputW)); 
    } 
    else{ 
     return array(round($inputW * $boxH/$inputH), $boxH); 
    } 
} 

Il semble fonctionner, mais il est pas parfait pixel. Comme notre ratio est fait d'un petit nombre, nous avons besoin d'une méthode qui respecte VRAIMENT le rapport, même si l'image n'est pas remplie à 100%. Et il est aussi vraiment stupide de coder en constante constante comme * 10000 parce que nous sommes incapables de trouver une bonne formule mathématique. ;)

Nous avons également construit ces tests PHPUnit, qui semblaient comme représentant pour nous (donc on aurait pu oublié certains cas)

/** 
* @covers Img_GD::findBestSizeInBox 
*/ 
public function testfindBestSizeForRatioReturnValidValueForEasyInput() 
{ 

    $img = new Img_GD(); 

    //1 
    $iW = 400; $iH = 300; //Input image size 
    $rW = 4; $rH = 3; //ratio 
    $eW = 400; $eH = 300; //Expected 
    $this->assertEquals(array($eW, $eH), $img->findBestSizeForRatio($iW, $iH, $rW, $rH), "Img: {$iW} x {$iH} Ratio: {$rW} x {$rH}"); 

    //2 
    $iW = 400; $iH = 3000; //Input image size 
    $rW = 4; $rH = 3; //ratio 
    $eW = 400; $eH = 300; //Expected 
    $this->assertEquals(array($eW, $eH), $img->findBestSizeForRatio($iW, $iH, $rW, $rH), "Img: {$iW} x {$iH} Ratio: {$rW} x {$rH}"); 

    //3 
    $iW = 4000; $iH = 300; //Input image size 
    $rW = 4; $rH = 3; //ratio. 
    $eW = 400; $eH = 300; //Expected 
    $this->assertEquals(array($eW, $eH), $img->findBestSizeForRatio($iW, $iH, $rW, $rH), "Img: {$iW} x {$iH} Ratio: {$rW} x {$rH}"); 

    //4 
    $iW = 400; $iH = 3000; //Input image size 
    $rW = 3; $rH = 4; //ratio 
    $eW = 399; $eH = 532; //Expected 
    $this->assertEquals(array($eW, $eH), $img->findBestSizeForRatio($iW, $iH, $rW, $rH), "Img: {$iW} x {$iH} Ratio: {$rW} x {$rH}"); 

    //5 
    $iW = 4000; $iH = 300; //Input image size 
    $rW = 3; $rH = 4; //ratio. 
    $eW = 225; $eH = 300; //Expected 
    $this->assertEquals(array($eW, $eH), $img->findBestSizeForRatio($iW, $iH, $rW, $rH), "Img: {$iW} x {$iH} Ratio: {$rW} x {$rH}"); 

    //6 
    $iW = 4000; $iH = 300; //Input image size 
    $rW = 3; $rH = 4; //ratio. 
    $eW = 225; $eH = 300; //Expected 
    $this->assertEquals(array($eW, $eH), $img->findBestSizeForRatio($iW, $iH, $rW, $rH), "Img: {$iW} x {$iH} Ratio: {$rW} x {$rH}"); 

} 

/** 
* @covers Img_GD::findBestSizeInBox 
*/ 
public function testfindBestSizeForRatioReturnValidValueForNonExactInput() 
{ 
    $img = new Img_GD(); 

    //7 
    $iW = 403; $iH = 302; //Input image size 
    $rW = 4; $rH = 3; //ratio 
    $eW = 400; $eH = 300; //Expected 
    $this->assertEquals(array($eW, $eH), $img->findBestSizeForRatio($iW, $iH, $rW, $rH), "Img: {$iW} x {$iH} Ratio: {$rW} x {$rH}"); 

    //8 
    $iW = 403; $iH = 3000; //Input image size 
    $rW = 4; $rH = 3; //ratio 
    $eW = 400; $eH = 300; //Expected 
    $this->assertEquals(array($eW, $eH), $img->findBestSizeForRatio($iW, $iH, $rW, $rH), "Img: {$iW} x {$iH} Ratio: {$rW} x {$rH}"); 

    //9 
    $iW = 4000; $iH = 302; //Input image size 
    $rW = 4; $rH = 3; //ratio. 
    $eW = 400; $eH = 300; //Expected 
    $this->assertEquals(array($eW, $eH), $img->findBestSizeForRatio($iW, $iH, $rW, $rH), "Img: {$iW} x {$iH} Ratio: {$rW} x {$rH}"); 

    //10 
    $iW = 403; $iH = 3000; //Input image size 
    $rW = 3; $rH = 4; //ratio 
    $eW = 402; $eH = 536; //Expected 
    $this->assertEquals(array($eW, $eH), $img->findBestSizeForRatio($iW, $iH, $rW, $rH), "Img: {$iW} x {$iH} Ratio: {$rW} x {$rH}"); 

    //11 
    $iW = 4000; $iH = 302; //Input image size 
    $rW = 3; $rH = 4; //ratio. 
    $eW = 225; $eH = 300; //Expected 
    $this->assertEquals(array($eW, $eH), $img->findBestSizeForRatio($iW, $iH, $rW, $rH), "Img: {$iW} x {$iH} Ratio: {$rW} x {$rH}"); 

    //12 
    $iW = 4000; $iH = 302; //Input image size 
    $rW = 3; $rH = 4; //ratio. 
    $eW = 225; $eH = 300; //Expected 
    $this->assertEquals(array($eW, $eH), $img->findBestSizeForRatio($iW, $iH, $rW, $rH), "Img: {$iW} x {$iH} Ratio: {$rW} x {$rH}"); 

} 

Toute solution qui passe tous les tests?

+0

Si la précision de vos calculs vous concerne, vous pouvez consulter http://php.net/manual/fr/book.bc.php ou http://php.net/manual/fr/ book.gmp.php – Mikk

+0

@Mikk ce n'est pas que j'ai besoin de précision comme la précision en virgule flottante. C'est que je ne veux pas arrondir. Si Regardez le test # 4. Je ne veux pas 400 x 533,333, je veux 399 x 532, car il est impossible de maintenir le ratio avec une largeur idéale de 400. Je veux seulement un entier dans mes résultats, toujours, et non arrondi. – FMaz008

Répondre

2

Essayez celui-changement subtil:

public function findBestSizeForRatio($inputW, $inputH, $ratioW, $ratioH) 
{ 
    if($inputW/$ratioW < $inputH/$ratioH){ 
     $w = floor($inputW/$ratioW) * $ratioW; 
     $h = $w * $ratioH/$ratioW; 
    } 
    else{ 
     $h = floor($inputH/$ratioH) * $ratioH; 
     $w = $h * $ratioW/$ratioH; 
    } 

    return array($w, $h); 
} 

Je vous vois déjà fixé votre essais unitaires btilly suggested; bien.

2

Laissez-moi être sûr que j'ai raison. Vous voulez prendre une image, et prendre le plus gros morceau que vous pouvez qui est un rectangle avec exactement le rapport h/w spécifié.

Dans ce cas, rappelez-vous la règle selon laquelle les tests unitaires sont également du code. Lorsque vous échouez à votre test unitaire, il y a même des chances que l'erreur soit dans le test unitaire. Dans cet esprit, vos tests unitaires semblent erronés. Par exemple, prenez # 4. 533/400 n'est pas dans un rapport 4/3 exact. La meilleure réponse possible avec ce ratio exact est 532/399.

Si vous êtes prêt à détendre l'exactitude du rapport, alors vous devriez faire quelque chose comme:

public function findBestSizeForRatio($inputW, $inputH, $ratioW, $ratioH) 
{ 
    if($inputW/$ratioW > $ratioH/$inputH){ 
     $w = $inputW; 
     $h = round($w * $ratioH/$ratioW); 
    } 
    else{ 
     $h = $inputH; 
     $h = round($h * $ratioW/$ratioH); 
    } 

    return array($w, $h); 
} 
+0

Vous avez bien compris le problème. Mais non, je ne veux pas me détendre. Comme vous l'avez remarqué, j'ai déjà cette méthode (et ça marche bien). Et vous avez raison, le test n ° 4 était faux, comme vous l'avez souligné, le résultat attendu devrait être 532/399. Je vais éditer le post. – FMaz008

+0

@ FMaz008: Ah. Dans ce cas, quelque chose dans le sens de '$ w = $ inputW - ($ inputW% $ ratioW)' et ensuite '$ h = $ w * $ ratioH/$ ratioW'. Cela suppose que '$ ratioW' et' $ ratioH' sont relativement premiers. Si vous ne pouvez pas supposer cela, il est facile de le garantir en les divisant par le gcd. Recherchez "gcd" sur http://php.net/manual/fr/ref.math.php pour trouver un exemple d'implémentation. – btilly

+0

@btilly N'est pas $ w = $ inputW - ($ inputW% $ ratioW) et $ w = étage ($ inputW/$ ratioW) * $ ratioW; revenir à peu près la même chose? Je ne vois pas beaucoup de différences ... Et oui, je suppose que le ratio sera réduit (40/30 sera toujours 4/3) – FMaz008

Questions connexes