web-dev-qa-db-fra.com

Calcul du rapport de taille d'image pour le redimensionnement

J'ai une largeur et une hauteur fixes définies pour redimensionner une image. Cependant, j'ai un problème avec cela, car l'image peut avoir n'importe quel rapport de taille (il peut s'agir de vertical ou de horizontal). Dans ce cas, une largeur et une hauteur fixes posent un problème. Je veux calculer largeur et hauteur de manière plus intelligente.

Par exemple, disons que j'ai défini largeur 1024px et hauteur 768px. Et je veux redimensionner une image qui est verticale (hauteur 1100px et largeur 200px). Donc, dans mon cas, il redimensionnera à taille fixe (1024x768), donc la largeur passera de 100px à 768px, et ce sera très moche. De même, si la hauteur de l'image est inférieure à 768px, la hauteur sera augmentée de force jusqu'à 768px.

Par conséquent, j'aimerais calculer la nouvelle taille de l'image en fonction du rapport de taille d'origine. Disons si l'image d'exemple ci-dessus doit être redimensionnée à la hauteur maximale de 768px, mais qu'en est-il de la largeur? il est déjà inférieur à ma "largeur maximale", qui est 200px. La largeur doit-elle rester inchangée? ou devrait-il être réduit davantage?

De même, si l'image a la hauteur 200px et la largeur 1100px. Donc, la largeur devrait être réduite à 1024px, mais qu'en est-il de la hauteur?

Le troisième problème est que, supposons que si la hauteur et la largeur sont supérieures à la hauteur maximale et à la largeur maximale, supposons que largeur: 1100px et hauteur: 4000px. Maintenant, puisque largeur et hauteur sont toutes deux supérieures à la largeur maximale et à la hauteur maximale, mais que l'image est verticale, l'image sera horizontale. Alors, comment puis-je vérifier si, dans ce cas, je devrais redimensionner l'image en fonction de la hauteur maximale ou de la largeur maximale?

J'apprécie toute aide avec ceci.

42
sunjie

Voici le code de mon sac personnel de code de redimensionnement d'image. Tout d'abord, les données dont vous avez besoin:

list($originalWidth, $originalHeight) = getimagesize($imageFile);
$ratio = $originalWidth / $originalHeight;

Ensuite, cet algorithme adapte l'image à la taille cible du mieux possible, en conservant le rapport hauteur/largeur d'origine, sans allonger l'image au-delà de l'original:

$targetWidth = $targetHeight = min($size, max($originalWidth, $originalHeight));

if ($ratio < 1) {
    $targetWidth = $targetHeight * $ratio;
} else {
    $targetHeight = $targetWidth / $ratio;
}

$srcWidth = $originalWidth;
$srcHeight = $originalHeight;
$srcX = $srcY = 0;

Ceci recadre l'image pour remplir complètement la taille de la cible, sans l'étirer:

$targetWidth = $targetHeight = min($originalWidth, $originalHeight, $size);

if ($ratio < 1) {
    $srcX = 0;
    $srcY = ($originalHeight / 2) - ($originalWidth / 2);
    $srcWidth = $srcHeight = $originalWidth;
} else {
    $srcY = 0;
    $srcX = ($originalWidth / 2) - ($originalHeight / 2);
    $srcWidth = $srcHeight = $originalHeight;
}

Et cela fait le redimensionnement réel:

$targetImage = imagecreatetruecolor($targetWidth, $targetHeight);
imagecopyresampled($targetImage, $originalImage, 0, 0, $srcX, $srcY, $targetWidth, $targetHeight, $srcWidth, $srcHeight);

Dans ce cas, le $size est juste un nombre pour la largeur et la hauteur (taille cible carrée). Je suis sûr que vous pouvez le modifier pour utiliser des cibles non carrées. Cela devrait également vous inspirer des autres algorithmes de redimensionnement que vous pouvez utiliser.

69
deceze
$ratio = $originalWidth / $originalHeight

si vous voulez changer la hauteur:

$targetWidth = $targetHeight * $ratio

si vous voulez changer la largeur:

$targetHeight = $targetWidth / $ratio
47
Mehran - Persian

Ce que vous voulez, c'est maintenir le rapport hauteur/largeur de votre image d'origine. C'est le rapport entre la largeur et la hauteur de l'image. Donc, vous calculez le facteur selon lequel vous devez redimensionner l'image verticalement et horizontalement, puis vous gardez le plus haut des deux. En pseudocode:

target_height = 768
target_width = 1024
# v_fact and h_fact are the factor by which the original vertical / horizontal
# image sizes should be multiplied to get the image to your target size.
v_fact = target_height / im_height 
h_fact = target_width / im_width
# you want to resize the image by the same factor in both vertical 
# and horizontal direction, so you need to pick the correct factor from
# v_fact / h_fact so that the largest (relative to target) of the new height/width
# equals the target height/width and the smallest is lower than the target.
# this is the lowest of the two factors
im_fact = min(v_fact, h_fact)
new_height = im_height * im_fact
new_width = im_width * im_fact
image.resize(new_width, new_height)
12
jilles de wit

cela fonctionne.

function calculateDimensions($width,$height,$maxwidth,$maxheight)
{

        if($width != $height)
        {
            if($width > $height)
            {
                $t_width = $maxwidth;
                $t_height = (($t_width * $height)/$width);
                //fix height
                if($t_height > $maxheight)
                {
                    $t_height = $maxheight;
                    $t_width = (($width * $t_height)/$height);
                }
            }
            else
            {
                $t_height = $maxheight;
                $t_width = (($width * $t_height)/$height);
                //fix width
                if($t_width > $maxwidth)
                {
                    $t_width = $maxwidth;
                    $t_height = (($t_width * $height)/$width);
                }
            }
        }
        else
            $t_width = $t_height = min($maxheight,$maxwidth);

        return array('height'=>(int)$t_height,'width'=>(int)$t_width);
    }
7
kestas

Vérifiez le code php ci-dessous:

$new_width  = 1024;
$new_height = 768;
$this_image = "images/my_image";

list($width, $height, $type, $attr) = getimagesize("$this_image");

if ($width > $height) {
  $image_height = floor(($height/$width)*$new_width);
  $image_width  = $new_width;
} else {
  $image_width  = floor(($width/$height)*$new_height);
  $image_height = $new_height;
}
echo "<img src='$this_image' height='$image_height' width='$image_width'>";
1
Wayne

Ce dont vous avez besoin, c'est de "maintenir" le rapport largeur/hauteur. À l’origine, vous avez une image de taille (lxh) 500x1000, ce rapport largeur/hauteur est de 0.5. En supposant que vous changiez 1000 en 768 en hauteur, la largeur de votre résultat serait 0.5 * 768 = 384

Un autre exemple, 1800 x 1200 et votre new height est 200, alors votre new width est 300 car 300/200 est 1.5 et 1800/1200 et 1.5.

Bonne chance.

1
Gary Tsui

Que dis-tu de ça:

double ratio = imageWidth/imageHeight;
int newHeight = Math.min(displayHeight, displayWidth / ratio); 
int newWidth =  Math.min(displayWidth, displayHeight * ratio); 
0
Yaza

Si la hauteur ou la largeur maximale est indiquée ou non, utilisez la logique @ (jilles de wit)

considérations: celles-ci devraient déjà être définies!

$mh = given height limit; //optional
$mw = given width limit; //optional

$height = $nh =[your original height];
$width = $nw =[your original width];

Le code

if($mh || $mw){
if(is_numeric($mh)){$h_fact = $mh / $nh;}
if(is_numeric($mw)){$v_fact = $mw / $nw;}

if(is_numeric($v_fact) && is_numeric($h_fact)  ){$im_fact = min($v_fact, $h_fact);}else{$im_fact=is_numeric($v_fact)?$v_fact:$h_fact;}
$nw = $nw * $im_fact;
$nh = $nh * $im_fact;
}

rééchantillonnage

$dst_img = imagecreatetruecolor($nw,$nh);
imagecopyresampled ($dst_img, $image, 0, 0, 0, 0, $nw, $nh, $width , $height);
0
Miguel

Vous devez le redimensionner en fonction de la propriété la plus éloignée de la valeur maximale. Ensuite, calcule le ratio.

if(($w - $w_max) > ($h - $h_max)) {
    $w_new = $w_max;
    $h_new = (int) ($h * ($w_max / $w));
}
else {
    $h_new = $h_max;
    $w_new = (int) ($w * ($h_max / $h));
}
0
Sascha Galley
class Image_Aspect_Ratio_Resize {
var $image_to_resize;
var $new_width;
var $new_height;
var $ratio;
var $new_image_name;
var $save_folder;

function resize() {
    if (!file_exists($this->image_to_resize)) {
        exit("File " . $this->image_to_resize . " does not exist.");
    }

    $info = GetImageSize($this->image_to_resize);

    if (empty($info)) {
        exit("The file " . $this->image_to_resize . " doesn't seem to be an image.");
    }

    $width = $info[0];
    $height = $info[1];
    $mime = $info['mime'];

    /* Keep Aspect Ratio? */

    if ($this->ratio) {
        $thumb = ($this->new_width < $width && $this->new_height < $height) ? true : false; // Thumbnail
        $bigger_image = ($this->new_width > $width || $this->new_height > $height) ? true : false; // Bigger Image

        if ($thumb) {
            if ($this->new_width >= $this->new_height) {
                $x = ($width / $this->new_width);

                $this->new_height = ($height / $x);
            } else if ($this->new_height >= $this->new_width) {
                $x = ($height / $this->new_height);

                $this->new_width = ($width / $x);
            }
        } else if ($bigger_image) {
            if ($this->new_width >= $width) {
                $x = ($this->new_width / $width);

                $this->new_height = ($height * $x);
            } else if ($this->new_height >= $height) {
                $x = ($this->new_height / $height);

                $this->new_width = ($width * $x);
            }
        }
    }


    $type = substr(strrchr($mime, '/'), 1);

    switch ($type) {
        case 'jpeg':
            $image_create_func = 'ImageCreateFromJPEG';
            $image_save_func = 'ImageJPEG';
            $new_image_ext = 'jpg';
            break;

        case 'png':
            $image_create_func = 'ImageCreateFromPNG';
            $image_save_func = 'ImagePNG';
            $new_image_ext = 'png';
            break;

        case 'bmp':
            $image_create_func = 'ImageCreateFromBMP';
            $image_save_func = 'ImageBMP';
            $new_image_ext = 'bmp';
            break;

        case 'gif':
            $image_create_func = 'ImageCreateFromGIF';
            $image_save_func = 'ImageGIF';
            $new_image_ext = 'gif';
            break;

        case 'vnd.wap.wbmp':
            $image_create_func = 'ImageCreateFromWBMP';
            $image_save_func = 'ImageWBMP';
            $new_image_ext = 'bmp';
            break;

        case 'xbm':
            $image_create_func = 'ImageCreateFromXBM';
            $image_save_func = 'ImageXBM';
            $new_image_ext = 'xbm';
            break;

        default:
            $image_create_func = 'ImageCreateFromJPEG';
            $image_save_func = 'ImageJPEG';
            $new_image_ext = 'jpg';
    }

    // New Image
    $image_c = ImageCreateTrueColor($this->new_width, $this->new_height);

    $new_image = $image_create_func($this->image_to_resize);

    ImageCopyResampled($image_c, $new_image, 0, 0, 0, 0, $this->new_width, $this->new_height, $width, $height);

    if ($this->save_folder) {
        if ($this->new_image_name) {
            $new_name = $this->new_image_name . '.' . $new_image_ext;
        } else {
            $new_name = $this->new_thumb_name(basename($this->image_to_resize)) . '_resized.' . $new_image_ext;
        }

        $save_path = $this->save_folder . $new_name;
    } else {
        /* Show the image without saving it to a folder */
        header("Content-Type: " . $mime);

        $image_save_func($image_c);

        $save_path = '';
    }

    $process = $image_save_func($image_c, $save_path);

    return array('result' => $process, 'new_file_path' => $save_path);
}}

/ * Appel de fonction * / 

$resize_image = new Image_Aspect_Ratio_Resize;
$new_width = (int) $_POST['new_width'];
$new_height = (int) $_POST['new_height'];
$resize_image->new_width = $new_width;
$resize_image->new_height = $new_height;
$resize_image->image_to_resize = $image; // Full Path to the file
$resize_image->ratio = true; // Keep aspect ratio
// Name of the new image (optional) - If it's not set a new will be added automatically
$resize_image->new_image_name = 'water_lilies_thumbnail';
/* Path where the new image should be saved. If it's not set the script will output the image without saving it */
$resize_image->save_folder = 'thumbs/';
$process = $resize_image->resize(); // Output image
0
Jah Yusuff

J'ai atteint cette question et je n'ai pas trouvé de réponse appropriée. Je me suis donc mis à la tâche.

j'ai commencé avec une logique de base, et après avoir consulté un de mes amis qui est un peu meilleur en maths, voici ce que nous avons trouvé.

function calculate_dimensions($width,$height,$max){
    if($width != $height){
        if($width > $height){
            $t_height = $max;
            $t_width = min(($width * $t_height)/$height);
        }
        if($height > $width){
            $t_width = $max;
            $t_height = min(($t_width * $height)/$width)
        }
    }else{
        if($width > $max){
            $t_width = $t_height = $max;
        }
    }
    $res = ['height'=>$t_height,'width'=>$t_width]
    return $res;
}

Cet extrait de code est réutilisable, alors assommez-vous. transmettez-lui la plus petite dimension maximale autorisée et calculera la dimension du plus grand côté. Vous obtiendrez ainsi une dimension correctement dimensionnée, dans laquelle vous pourrez ensuite centrer le rognage, ce qui donnera une image carrée correctement réduite et recadrée. c'est utile pour des choses comme les images de profil et les vignettes.

crédit à mon ami, Justin Gillett pour sa brillante suggestion de multiplication croisée. 

0
r3wt

Cet exemple réduira une image pour l’adapter à un rapport de format parfait de pixel (16: 9), créant une image ne dépassant pas une limite spécifiée (1200 x 675).

Définissez votre rapport d’image et toute limite supérieure:

const RATIO_W                       = 16;
const RATIO_H                       = 9;
const RATIO_MULIPLIER_UPPER_LIMIT   = 75;

Calculer la nouvelle largeur et hauteur de l'image

list($imageWidth, $imageHeight) = getimagesize($path_to_image);    

if( ($imageWidth / $imageHeight) === (self::RATIO_W / self::RATIO_H) ){
    return;

// Find closest ratio multiple to image size
if($imageWidth > $imageHeight){
    // landscape
    $ratioMultiple  = round($imageHeight / self::RATIO_H, 0, PHP_ROUND_HALF_DOWN);
}else{
    // portrait
    $ratioMultiple  = round($imageWidth / self::RATIO_W, 0, PHP_ROUND_HALF_DOWN);
}    

$newWidth   = $ratioMultiple * self::RATIO_W;
$newHeight = $ratioMultiple * self::RATIO_H;    

if($newWidth > self::RATIO_W * self::RATIO_MULIPLIER_UPPER_LIMIT|| $newHeight > self::RATIO_H * self::RATIO_MULIPLIER_UPPER_LIMIT){
    // File is larger than upper limit
    $ratioMultiple = self::RATIO_MULIPLIER_UPPER_LIMIT;
}    

$this->tweakMultiplier($ratioMultiple, $imageWidth, $imageHeight);    

$newWidth   = $ratioMultiple * self::RATIO_W;
$newHeight = $ratioMultiple * self::RATIO_H;    

Redimensionner l'image

$originalImage  = imagecreatefromjpeg( $tempImagePath );
$newImage       = imagecreatetruecolor($newWidth, $newHeight);
imagefilledrectangle($newImage, 0, 0, $newWidth, $newHeight, imagecolorallocate($newImage, 255, 255, 255));
imagecopyresampled($newImage, $originalImage, 0, 0, 0, 0, $newWidth, $newHeight, $imageWidth, $imageHeight);
imagejpeg($newImage, $tempImagePath, 100);

Facteurs de bouclage jusqu'à ce que les deux dimensions soient inférieures à la taille de l'image d'origine

protected function tweakMultiplier( &$ratioMultiple, $fitInsideWidth, $fitInsideHeight ){
    $newWidth   = $ratioMultiple * self::RATIO_W;
    $newHeight  = $ratioMultiple * self::RATIO_H;    

    if($newWidth > $fitInsideWidth || $newHeight > $fitInsideHeight){
        echo " Tweak ";
        $ratioMultiple--;
        $this->tweakMultiplier($ratioMultiple, $fitInsideWidth, $fitInsideHeight);
    }else{
        return;
    }    
}
0
JPickup